From 9545a10361203a6e1c24c3512b6f28a7e136802a Mon Sep 17 00:00:00 2001 From: GUVWAF <78759985+GUVWAF@users.noreply.github.com> Date: Sat, 16 Nov 2024 01:20:20 +0100 Subject: [PATCH 001/101] RP2040: Update core; add mDNS support (#5355) * Update arduino-pico core * RP2040: Add mDNS support * SimpleMDNS `begin` now returns a bool * Add `-g` option to `debug_build_flags` to link files for gdb * RAK11310 needs old platform as well * Change defines to specific architecture * Core version 4.2.1 is out --- arch/rp2xx0/rp2040.ini | 6 +++--- arch/rp2xx0/rp2350.ini | 4 ++-- src/mesh/wifi/WiFiAPClient.cpp | 24 ++++++++++++++---------- variants/rak11310/platformio.ini | 3 ++- variants/rp2040-lora/platformio.ini | 2 +- variants/rpipico/platformio.ini | 2 +- variants/rpipico2/platformio.ini | 2 +- variants/rpipicow/platformio.ini | 2 +- 8 files changed, 25 insertions(+), 20 deletions(-) diff --git a/arch/rp2xx0/rp2040.ini b/arch/rp2xx0/rp2040.ini index 17b5df618..57e5d7bc2 100644 --- a/arch/rp2xx0/rp2040.ini +++ b/arch/rp2xx0/rp2040.ini @@ -1,8 +1,8 @@ ; Common settings for rp2040 Processor based targets [rp2040_base] -platform = https://github.com/maxgerhardt/platform-raspberrypi.git#v1.2.0-gcc12 +platform = https://github.com/maxgerhardt/platform-raspberrypi.git#a606be683748c73e9a0d46baf70163478d298f0f ; For arduino-pico 4.2.0 extends = arduino_base -platform_packages = framework-arduinopico@https://github.com/earlephilhower/arduino-pico.git#4.0.3 +platform_packages = framework-arduinopico@https://github.com/earlephilhower/arduino-pico.git#4.2.1 board_build.core = earlephilhower board_build.filesystem_size = 0.5m @@ -23,4 +23,4 @@ lib_deps = ${arduino_base.lib_deps} ${environmental_base.lib_deps} ${radiolib_base.lib_deps} - rweather/Crypto \ No newline at end of file + rweather/Crypto diff --git a/arch/rp2xx0/rp2350.ini b/arch/rp2xx0/rp2350.ini index 33bb36ad1..58c5e5554 100644 --- a/arch/rp2xx0/rp2350.ini +++ b/arch/rp2xx0/rp2350.ini @@ -1,8 +1,8 @@ ; Common settings for rp2040 Processor based targets [rp2350_base] -platform = https://github.com/maxgerhardt/platform-raspberrypi.git#9e55f6db5c56b9867c69fe473f388beea4546672 +platform = https://github.com/maxgerhardt/platform-raspberrypi.git#a606be683748c73e9a0d46baf70163478d298f0f ; For arduino-pico 4.2.0 extends = arduino_base -platform_packages = framework-arduinopico@https://github.com/earlephilhower/arduino-pico.git#a6ab6e1f95bc1428d667d55ea7173c0744acc03c ; 4.0.2+ +platform_packages = framework-arduinopico@https://github.com/earlephilhower/arduino-pico.git#4.2.1 board_build.core = earlephilhower board_build.filesystem_size = 0.5m diff --git a/src/mesh/wifi/WiFiAPClient.cpp b/src/mesh/wifi/WiFiAPClient.cpp index faf5ce3de..911a47093 100644 --- a/src/mesh/wifi/WiFiAPClient.cpp +++ b/src/mesh/wifi/WiFiAPClient.cpp @@ -20,6 +20,8 @@ #include #include static void WiFiEvent(WiFiEvent_t event); +#elif defined(ARCH_RP2040) +#include #endif #ifndef DISABLE_NTP @@ -59,19 +61,21 @@ static void onNetworkConnected() // Start web server LOG_INFO("Start WiFi network services"); -#ifdef ARCH_ESP32 // start mdns if (!MDNS.begin("Meshtastic")) { LOG_ERROR("Error setting up MDNS responder!"); } else { - LOG_INFO("mDNS responder started"); LOG_INFO("mDNS Host: Meshtastic.local"); +#ifdef ARCH_ESP32 MDNS.addService("http", "tcp", 80); MDNS.addService("https", "tcp", 443); - } -#else // ESP32 handles this in WiFiEvent - LOG_INFO("Obtained IP address: %s", WiFi.localIP().toString().c_str()); +#elif defined(ARCH_RP2040) + // ARCH_RP2040 does not support HTTPS, create a "meshtastic" service + MDNS.addService("meshtastic", "tcp", 4403); + // ESP32 handles this in WiFiEvent + LOG_INFO("Obtained IP address: %s", WiFi.localIP().toString().c_str()); #endif + } #ifndef DISABLE_NTP LOG_INFO("Start NTP time client"); @@ -129,7 +133,7 @@ static int32_t reconnectWiFi() // Make sure we clear old connection credentials #ifdef ARCH_ESP32 WiFi.disconnect(false, true); -#else +#elif defined(ARCH_RP2040) WiFi.disconnect(false); #endif LOG_INFO("Reconnecting to WiFi access point %s", wifiName); @@ -193,7 +197,7 @@ void deinitWifi() if (isWifiAvailable()) { #ifdef ARCH_ESP32 WiFi.disconnect(true, false); -#else +#elif defined(ARCH_RP2040) WiFi.disconnect(true); #endif WiFi.mode(WIFI_OFF); @@ -229,15 +233,15 @@ bool initWifi() if (config.network.address_mode == meshtastic_Config_NetworkConfig_AddressMode_STATIC && config.network.ipv4_config.ip != 0) { -#ifndef ARCH_RP2040 +#ifdef ARCH_ESP32 WiFi.config(config.network.ipv4_config.ip, config.network.ipv4_config.gateway, config.network.ipv4_config.subnet, config.network.ipv4_config.dns); -#else +#elif defined(ARCH_RP2040) WiFi.config(config.network.ipv4_config.ip, config.network.ipv4_config.dns, config.network.ipv4_config.gateway, config.network.ipv4_config.subnet); #endif } -#ifndef ARCH_RP2040 +#ifdef ARCH_ESP32 WiFi.onEvent(WiFiEvent); WiFi.setAutoReconnect(true); WiFi.setSleep(false); diff --git a/variants/rak11310/platformio.ini b/variants/rak11310/platformio.ini index c7b3504fe..923cedaa3 100644 --- a/variants/rak11310/platformio.ini +++ b/variants/rak11310/platformio.ini @@ -3,6 +3,7 @@ extends = rp2040_base board = wiscore_rak11300 upload_protocol = picotool # keep an old SDK to use less memory. +platform = https://github.com/maxgerhardt/platform-raspberrypi.git#v1.2.0-gcc12 platform_packages = framework-arduinopico@https://github.com/earlephilhower/arduino-pico.git#3.7.2 # add our variants files to the include and src paths @@ -13,5 +14,5 @@ build_flags = ${rp2040_base.build_flags} -L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/cortex-m0plus" lib_deps = ${rp2040_base.lib_deps} -debug_build_flags = ${rp2040_base.build_flags} +debug_build_flags = ${rp2040_base.build_flags}, -g debug_tool = cmsis-dap ; for e.g. Picotool \ No newline at end of file diff --git a/variants/rp2040-lora/platformio.ini b/variants/rp2040-lora/platformio.ini index 8499f6f3c..4c578fb2b 100644 --- a/variants/rp2040-lora/platformio.ini +++ b/variants/rp2040-lora/platformio.ini @@ -12,5 +12,5 @@ build_flags = ${rp2040_base.build_flags} -L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/cortex-m0plus" lib_deps = ${rp2040_base.lib_deps} -debug_build_flags = ${rp2040_base.build_flags} +debug_build_flags = ${rp2040_base.build_flags}, -g debug_tool = cmsis-dap ; for e.g. Picotool \ No newline at end of file diff --git a/variants/rpipico/platformio.ini b/variants/rpipico/platformio.ini index e4b9e479f..9c62ebcb5 100644 --- a/variants/rpipico/platformio.ini +++ b/variants/rpipico/platformio.ini @@ -12,5 +12,5 @@ build_flags = ${rp2040_base.build_flags} -L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/cortex-m0plus" lib_deps = ${rp2040_base.lib_deps} -debug_build_flags = ${rp2040_base.build_flags} +debug_build_flags = ${rp2040_base.build_flags}, -g debug_tool = cmsis-dap ; for e.g. Picotool \ No newline at end of file diff --git a/variants/rpipico2/platformio.ini b/variants/rpipico2/platformio.ini index a63414418..24714efd5 100644 --- a/variants/rpipico2/platformio.ini +++ b/variants/rpipico2/platformio.ini @@ -12,5 +12,5 @@ build_flags = ${rp2350_base.build_flags} -L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/cortex-m0plus" lib_deps = ${rp2350_base.lib_deps} -debug_build_flags = ${rp2350_base.build_flags} +debug_build_flags = ${rp2350_base.build_flags}, -g debug_tool = cmsis-dap ; for e.g. Picotool \ No newline at end of file diff --git a/variants/rpipicow/platformio.ini b/variants/rpipicow/platformio.ini index 2600b4b38..7a43ece3b 100644 --- a/variants/rpipicow/platformio.ini +++ b/variants/rpipicow/platformio.ini @@ -14,5 +14,5 @@ build_src_filter = ${rp2040_base.build_src_filter} + lib_deps = ${rp2040_base.lib_deps} ${networking_base.lib_deps} -debug_build_flags = ${rp2040_base.build_flags} +debug_build_flags = ${rp2040_base.build_flags}, -g debug_tool = cmsis-dap ; for e.g. Picotool \ No newline at end of file From 90a3050c1fbe711df4096885a03c87d98317d819 Mon Sep 17 00:00:00 2001 From: Tom Fifield Date: Sat, 16 Nov 2024 12:01:41 +0800 Subject: [PATCH 002/101] Add sudo to apt-get commands for Raspbian Build (#5364) Without sudo, inadequate permissions to runs the commands meant the build was failing. --- .github/workflows/build_raspbian.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build_raspbian.yml b/.github/workflows/build_raspbian.yml index 1fd8fad30..66c65a347 100644 --- a/.github/workflows/build_raspbian.yml +++ b/.github/workflows/build_raspbian.yml @@ -13,8 +13,8 @@ jobs: - name: Install libbluetooth shell: bash run: | - apt-get update -y --fix-missing - apt-get install -y libbluetooth-dev libgpiod-dev libyaml-cpp-dev openssl libssl-dev libulfius-dev liborcania-dev + sudo apt-get update -y --fix-missing + sudp apt-get install -y libbluetooth-dev libgpiod-dev libyaml-cpp-dev openssl libssl-dev libulfius-dev liborcania-dev - name: Checkout code uses: actions/checkout@v4 From 1b99543a1558ddfeeb7e7e2c88ef905ce79b5d12 Mon Sep 17 00:00:00 2001 From: Tom Fifield Date: Sat, 16 Nov 2024 12:48:15 +0800 Subject: [PATCH 003/101] Typo fix in build_raspbian.yml (#5365) s/sudp/sudo :(:(:( --- .github/workflows/build_raspbian.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build_raspbian.yml b/.github/workflows/build_raspbian.yml index 66c65a347..e857ae635 100644 --- a/.github/workflows/build_raspbian.yml +++ b/.github/workflows/build_raspbian.yml @@ -14,7 +14,7 @@ jobs: shell: bash run: | sudo apt-get update -y --fix-missing - sudp apt-get install -y libbluetooth-dev libgpiod-dev libyaml-cpp-dev openssl libssl-dev libulfius-dev liborcania-dev + sudo apt-get install -y libbluetooth-dev libgpiod-dev libyaml-cpp-dev openssl libssl-dev libulfius-dev liborcania-dev - name: Checkout code uses: actions/checkout@v4 From add70b522910bd94a4e9efbdcad7750707e98b0c Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Sat, 16 Nov 2024 05:58:07 -0600 Subject: [PATCH 004/101] Rework some things --- .github/actions/build-variant/action.yml | 1 + arch/nrf52/nrf52.ini | 1 + src/mesh/mesh-pb-constants.h | 6 +----- version.properties | 2 +- 4 files changed, 4 insertions(+), 6 deletions(-) diff --git a/.github/actions/build-variant/action.yml b/.github/actions/build-variant/action.yml index 80d2a56bb..e0c5fba06 100644 --- a/.github/actions/build-variant/action.yml +++ b/.github/actions/build-variant/action.yml @@ -51,6 +51,7 @@ runs: file: build.tar target: build.tar token: ${{ inputs.github_token }} + version: v2.5.3 - name: Unpack web ui if: inputs.include-web-ui == 'true' diff --git a/arch/nrf52/nrf52.ini b/arch/nrf52/nrf52.ini index 99e8693dc..d75f86306 100644 --- a/arch/nrf52/nrf52.ini +++ b/arch/nrf52/nrf52.ini @@ -16,6 +16,7 @@ build_flags = -DLFS_NO_ASSERT ; Disable LFS assertions , see https://github.com/meshtastic/firmware/pull/3818 -DMESHTASTIC_EXCLUDE_AUDIO=1 -DMESHTASTIC_EXCLUDE_PAXCOUNTER=1 + -DMAX_NUM_NODES=80 build_src_filter = ${arduino_base.build_src_filter} - - - - - - - - - - diff --git a/src/mesh/mesh-pb-constants.h b/src/mesh/mesh-pb-constants.h index a055804d9..df7ae89e6 100644 --- a/src/mesh/mesh-pb-constants.h +++ b/src/mesh/mesh-pb-constants.h @@ -1,7 +1,7 @@ #pragma once #include -#include "architecture.h" + #include "mesh/generated/meshtastic/admin.pb.h" #include "mesh/generated/meshtastic/deviceonly.pb.h" #include "mesh/generated/meshtastic/localonly.pb.h" @@ -21,12 +21,8 @@ /// max number of nodes allowed in the mesh #ifndef MAX_NUM_NODES -#ifdef ARCH_NRF52 -#define MAX_NUM_NODES 80 -#else #define MAX_NUM_NODES 100 #endif -#endif #define MAX_NUM_NODES_FS 100 diff --git a/version.properties b/version.properties index bed14bad5..091ebde9e 100644 --- a/version.properties +++ b/version.properties @@ -1,4 +1,4 @@ [VERSION] major = 2 minor = 5 -build = 14 +build = 13 From fdc473e5faf5d97a58629491559718a504c2364f Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Sat, 16 Nov 2024 06:01:07 -0600 Subject: [PATCH 005/101] Trunk --- src/mesh/mesh-pb-constants.h | 1 - 1 file changed, 1 deletion(-) diff --git a/src/mesh/mesh-pb-constants.h b/src/mesh/mesh-pb-constants.h index df7ae89e6..039b36d8d 100644 --- a/src/mesh/mesh-pb-constants.h +++ b/src/mesh/mesh-pb-constants.h @@ -1,7 +1,6 @@ #pragma once #include - #include "mesh/generated/meshtastic/admin.pb.h" #include "mesh/generated/meshtastic/deviceonly.pb.h" #include "mesh/generated/meshtastic/localonly.pb.h" From be6348388edcb170231bbb75c04b343a5d0db8a6 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Sat, 16 Nov 2024 06:12:45 -0600 Subject: [PATCH 006/101] Separate littlefs bundle --- bin/build-esp32.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/bin/build-esp32.sh b/bin/build-esp32.sh index adb6ab12a..b5f7c126e 100755 --- a/bin/build-esp32.sh +++ b/bin/build-esp32.sh @@ -35,6 +35,10 @@ cp $SRCBIN $OUTDIR/$basename-update.bin echo "Building Filesystem for ESP32 targets" pio run --environment $1 -t buildfs +cp .pio/build/$1/littlefs.bin $OUTDIR/littlefswebui-$VERSION.bin +# Remove webserver files from the filesystem and rebuild +rm -rf data/static +pio run --environment $1 -t buildfs cp .pio/build/$1/littlefs.bin $OUTDIR/littlefs-$VERSION.bin cp bin/device-install.* $OUTDIR cp bin/device-update.* $OUTDIR From ca3d8da128b6473a5578f1416c909a92f9750a3c Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Sat, 16 Nov 2024 06:22:08 -0600 Subject: [PATCH 007/101] version tags --- .github/actions/build-variant/action.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/actions/build-variant/action.yml b/.github/actions/build-variant/action.yml index e0c5fba06..b3303d393 100644 --- a/.github/actions/build-variant/action.yml +++ b/.github/actions/build-variant/action.yml @@ -51,7 +51,7 @@ runs: file: build.tar target: build.tar token: ${{ inputs.github_token }} - version: v2.5.3 + version: tags/v2.5.3 - name: Unpack web ui if: inputs.include-web-ui == 'true' From 74d0c58576bd43c24d0bfb68aec86f3da36979a3 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Sat, 16 Nov 2024 06:24:10 -0600 Subject: [PATCH 008/101] Diag --- bin/build-esp32.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/bin/build-esp32.sh b/bin/build-esp32.sh index b5f7c126e..f8d808ced 100755 --- a/bin/build-esp32.sh +++ b/bin/build-esp32.sh @@ -37,6 +37,7 @@ echo "Building Filesystem for ESP32 targets" pio run --environment $1 -t buildfs cp .pio/build/$1/littlefs.bin $OUTDIR/littlefswebui-$VERSION.bin # Remove webserver files from the filesystem and rebuild +ls -l data/static # Diagnostic list of files rm -rf data/static pio run --environment $1 -t buildfs cp .pio/build/$1/littlefs.bin $OUTDIR/littlefs-$VERSION.bin From 37b29f689951db02cbace46e4896b91f2efec6ad Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Sat, 16 Nov 2024 19:36:55 -0600 Subject: [PATCH 009/101] Add littlefswebui --- .github/workflows/main_matrix.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/main_matrix.yml b/.github/workflows/main_matrix.yml index efdbd2637..37164b758 100644 --- a/.github/workflows/main_matrix.yml +++ b/.github/workflows/main_matrix.yml @@ -203,6 +203,7 @@ jobs: ./device-*.sh ./device-*.bat ./littlefs-*.bin + ./littlefswebui-*.bin ./bleota*bin ./Meshtastic_nRF52_factory_erase*.uf2 retention-days: 30 From a174ec7cf95be8a4a5400c0df3a205d5a89181fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Gjels=C3=B8?= <36234524+gjelsoe@users.noreply.github.com> Date: Sun, 17 Nov 2024 14:36:06 +0100 Subject: [PATCH 010/101] Bug fixed in ExternalNotificationModule (#5375) While `nagging` setExternalState wasn't written to Buzzer & Vibra so output was never toggled. Possible fix for #5348 --- src/modules/ExternalNotificationModule.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/modules/ExternalNotificationModule.cpp b/src/modules/ExternalNotificationModule.cpp index d88f275b9..3ec6ff690 100644 --- a/src/modules/ExternalNotificationModule.cpp +++ b/src/modules/ExternalNotificationModule.cpp @@ -119,12 +119,13 @@ int32_t ExternalNotificationModule::runOnce() if (externalTurnedOn[1] + (moduleConfig.external_notification.output_ms ? moduleConfig.external_notification.output_ms : EXT_NOTIFICATION_MODULE_OUTPUT_MS) < millis()) { - setExternalState(0, !getExternal(1)); + setExternalState(1, !getExternal(1)); } if (externalTurnedOn[2] + (moduleConfig.external_notification.output_ms ? moduleConfig.external_notification.output_ms : EXT_NOTIFICATION_MODULE_OUTPUT_MS) < millis()) { - setExternalState(0, !getExternal(2)); + LOG_DEBUG("EXTERNAL 2 %d compared to %d", externalTurnedOn[2]+moduleConfig.external_notification.output_ms, millis()); + setExternalState(2, !getExternal(2)); } #if defined(HAS_NCP5623) || defined(RGBLED_RED) || defined(HAS_NEOPIXEL) || defined(UNPHONE) red = (colorState & 4) ? brightnessValues[brightnessIndex] : 0; // Red enabled on colorState = 4,5,6,7 From 1a06f88dfb44ecc5bb45fe18d3ce8603c276a0fe Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Sun, 17 Nov 2024 07:57:59 -0600 Subject: [PATCH 011/101] Cleanup static files from bad Web UI bundle on 2.5.13 release (#5376) * Cleanup static files from bad Web UI bundle on 2.5.13 release * Check existence first * Esp32 is the only one we care about --- src/mesh/NodeDB.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index 7f051ae16..102ac1f61 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -823,6 +823,11 @@ void NodeDB::loadFromDisk() 0; // Mark the current device state as completely unusable, so that if we fail reading the entire file from // disk we will still factoryReset to restore things. +#ifdef ARCH_ESP32 + if (FSCom.exists("/static/static")) + rmDir("/static/static"); // Remove bad static web files bundle from initial 2.5.13 release +#endif + // static DeviceState scratch; We no longer read into a tempbuf because this structure is 15KB of valuable RAM auto state = loadProto(prefFileName, sizeof(meshtastic_DeviceState) + MAX_NUM_NODES_FS * sizeof(meshtastic_NodeInfo), sizeof(meshtastic_DeviceState), &meshtastic_DeviceState_msg, &devicestate); From 0d1f9e915f676201f1ac21eaa57dd61e20e34bd7 Mon Sep 17 00:00:00 2001 From: GUVWAF <78759985+GUVWAF@users.noreply.github.com> Date: Sun, 17 Nov 2024 17:51:01 +0100 Subject: [PATCH 012/101] Move some actions to after `startTransmit()` (#5383) To minimize the time between channel scan and actual transmit --- src/mesh/RadioInterface.cpp | 2 -- src/mesh/RadioLibInterface.cpp | 9 +++++++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/mesh/RadioInterface.cpp b/src/mesh/RadioInterface.cpp index f0d137e2c..53b66ff0a 100644 --- a/src/mesh/RadioInterface.cpp +++ b/src/mesh/RadioInterface.cpp @@ -601,8 +601,6 @@ size_t RadioInterface::beginSending(meshtastic_MeshPacket *p) // LOG_DEBUG("Send queued packet on mesh (txGood=%d,rxGood=%d,rxBad=%d)", rf95.txGood(), rf95.rxGood(), rf95.rxBad()); assert(p->which_payload_variant == meshtastic_MeshPacket_encrypted_tag); // It should have already been encoded by now - lastTxStart = millis(); - radioBuffer.header.from = p->from; radioBuffer.header.to = p->to; radioBuffer.header.id = p->id; diff --git a/src/mesh/RadioLibInterface.cpp b/src/mesh/RadioLibInterface.cpp index 23ef3d6f1..5f82a41ce 100644 --- a/src/mesh/RadioLibInterface.cpp +++ b/src/mesh/RadioLibInterface.cpp @@ -278,7 +278,8 @@ void RadioLibInterface::onNotify(uint32_t notification) startReceive(); // try receiving this packet, afterwards we'll be trying to transmit again setTransmitDelay(); } else { - // Send any outgoing packets we have ready + // Send any outgoing packets we have ready as fast as possible to keep the time between channel scan and + // actual transmission as short as possible meshtastic_MeshPacket *txp = txQueue.dequeue(); assert(txp); bool sent = startSend(txp); @@ -470,7 +471,8 @@ void RadioLibInterface::setStandby() /** start an immediate transmit */ bool RadioLibInterface::startSend(meshtastic_MeshPacket *txp) { - printPacket("Start low level send", txp); + /* NOTE: Minimize the actions before startTransmit() to keep the time between + channel scan and actual transmit as low as possible to avoid collisions. */ if (disabled || !config.lora.tx_enabled) { LOG_WARN("Drop Tx packet because LoRa Tx disabled"); packetPool.release(txp); @@ -489,6 +491,9 @@ bool RadioLibInterface::startSend(meshtastic_MeshPacket *txp) completeSending(); powerMon->clearState(meshtastic_PowerMon_State_Lora_TXOn); // Transmitter off now startReceive(); // Restart receive mode (because startTransmit failed to put us in xmit mode) + } else { + lastTxStart = millis(); + printPacket("Started Tx", txp); } // Must be done AFTER, starting transmit, because startTransmit clears (possibly stale) interrupt pending register From a8357ebd5296bbed9c952b21cb7255d7911fa54c Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 17 Nov 2024 10:51:11 -0600 Subject: [PATCH 013/101] [create-pull-request] automated change (#5380) Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com> --- version.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.properties b/version.properties index 091ebde9e..bed14bad5 100644 --- a/version.properties +++ b/version.properties @@ -1,4 +1,4 @@ [VERSION] major = 2 minor = 5 -build = 13 +build = 14 From 89469fcb88240617146dc11bc3cad01dcbf3f3a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Gjels=C3=B8?= <36234524+gjelsoe@users.noreply.github.com> Date: Sun, 17 Nov 2024 19:36:41 +0100 Subject: [PATCH 014/101] Allows all 3 PKI keys to be added to userPrefs.h (#4969) and a tool. (#5368) * more userPrefs.h Added PKI Admin keys to userPrefs.h * Update userPrefs.h Allows all 3 PKI keys to be added to userPrefs.h (#4969) * Update NodeDB.cpp Trunk * Update userPrefs.h Changed wording * Create base64_to_hex.py A little tool for converting base64 PKI Keys to decoded byte that userPrefs.h can understand. * more userPrefs.h Added PKI Admin keys to userPrefs.h * Update userPrefs.h Allows all 3 PKI keys to be added to userPrefs.h (#4969) * Update NodeDB.cpp Trunk * Update userPrefs.h Changed wording * Create base64_to_hex.py A little tool for converting base64 PKI Keys to decoded byte that userPrefs.h can understand. --- bin/base64_to_hex.py | 33 +++++++++++++++++++++++++++++++++ src/mesh/NodeDB.cpp | 27 ++++++++++++++++++++++++--- userPrefs.h | 14 +++++++++++--- 3 files changed, 68 insertions(+), 6 deletions(-) create mode 100644 bin/base64_to_hex.py diff --git a/bin/base64_to_hex.py b/bin/base64_to_hex.py new file mode 100644 index 000000000..07c559b9e --- /dev/null +++ b/bin/base64_to_hex.py @@ -0,0 +1,33 @@ +import sys +import base64 + +def base64_to_hex_string(b64_string): + try: + # Decode the Base64 string to raw bytes + decoded_bytes = base64.b64decode(b64_string) + except Exception as e: + raise ValueError(f"Invalid Base64 input: {e}") + + # Check if the decoded result is exactly 32 bytes + if len(decoded_bytes) != 32: + raise ValueError("Decoded Base64 input must be exactly 32 bytes.") + + # Convert each byte to its hex representation + hex_values = [f"0x{byte:02x}" for byte in decoded_bytes] + + # Join the formatted hex values with commas + formatted_output = "{ " + ", ".join(hex_values) + " };" + return formatted_output + +if __name__ == "__main__": + # Check if a Base64 string was provided in command line arguments + if len(sys.argv) != 2: + print("Usage: python script.py ") + sys.exit(1) + + b64_string = sys.argv[1] + try: + formatted_hex = base64_to_hex_string(b64_string) + print(formatted_hex) + except ValueError as e: + print(e) diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index 102ac1f61..55b8c0b4d 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -407,9 +407,30 @@ void NodeDB::installDefaultConfig(bool preserveKey = false) config.lora.ignore_mqtt = false; #endif #ifdef USERPREFS_USE_ADMIN_KEY - memcpy(config.security.admin_key[0].bytes, USERPREFS_ADMIN_KEY, 32); - config.security.admin_key[0].size = 32; - config.security.admin_key_count = 1; + // Initialize admin_key_count to zero + byte numAdminKeys = 0; + + // Check if USERPREFS_ADMIN_KEY_0 is non-empty + if (sizeof(USERPREFS_ADMIN_KEY_0) > 0) { + memcpy(config.security.admin_key[numAdminKeys].bytes, USERPREFS_ADMIN_KEY_0, 32); + config.security.admin_key[numAdminKeys].size = 32; + numAdminKeys++; + } + + // Check if USERPREFS_ADMIN_KEY_1 is non-empty + if (sizeof(USERPREFS_ADMIN_KEY_1) > 0) { + memcpy(config.security.admin_key[numAdminKeys].bytes, USERPREFS_ADMIN_KEY_1, 32); + config.security.admin_key[numAdminKeys].size = 32; + numAdminKeys++; + } + + // Check if USERPREFS_ADMIN_KEY_2 is non-empty + if (sizeof(USERPREFS_ADMIN_KEY_2) > 0) { + memcpy(config.security.admin_key[config.security.admin_key_count].bytes, USERPREFS_ADMIN_KEY_2, 32); + config.security.admin_key[config.security.admin_key_count].size = 32; + numAdminKeys++; + } + config.security.admin_key_count = numAdminKeys; #endif if (shouldPreserveKey) { config.security.private_key.size = 32; diff --git a/userPrefs.h b/userPrefs.h index c105e6b52..622a491c3 100644 --- a/userPrefs.h +++ b/userPrefs.h @@ -68,11 +68,19 @@ static unsigned char icon_bits[] = { 0x98, 0x3F, 0xF0, 0x23, 0x00, 0xFC, 0x0F, 0xE0, 0x7F, 0x00, 0xFC, 0x03, 0x80, 0xFF, 0x01, 0xFC, 0x00, 0x00, 0x3E, 0x00, 0x70, 0x00, 0x00, 0x1C, 0x00, 0x70, 0x00, 0x00, 0x1C, 0x00, 0x70, 0x00, 0x00, 0x1C, 0x00, 0x70, 0x00, 0x00, 0x1C, 0x00}; */ + +/* + * PKI Admin keys. + * If a Admin key is set with '{};' + * then it will be ignored, a PKI key must have a size of 32. + */ /* #define USERPREFS_USE_ADMIN_KEY 1 -static unsigned char USERPREFS_ADMIN_KEY[] = {0xcd, 0xc0, 0xb4, 0x3c, 0x53, 0x24, 0xdf, 0x13, 0xca, 0x5a, 0xa6, - 0x0c, 0x0d, 0xec, 0x85, 0x5a, 0x4c, 0xf6, 0x1a, 0x96, 0x04, 0x1a, - 0x3e, 0xfc, 0xbb, 0x8e, 0x33, 0x71, 0xe5, 0xfc, 0xff, 0x3c}; +static unsigned char USERPREFS_ADMIN_KEY_0[] = {0xcd, 0xc0, 0xb4, 0x3c, 0x53, 0x24, 0xdf, 0x13, 0xca, 0x5a, 0xa6, + 0x0c, 0x0d, 0xec, 0x85, 0x5a, 0x4c, 0xf6, 0x1a, 0x96, 0x04, 0x1a, + 0x3e, 0xfc, 0xbb, 0x8e, 0x33, 0x71, 0xe5, 0xfc, 0xff, 0x3c}; +static unsigned char USERPREFS_ADMIN_KEY_1[] = {}; +static unsigned char USERPREFS_ADMIN_KEY_2[] = {}; */ /* From de76caca328f1706d0147262ebbc74d45424515e Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 17 Nov 2024 19:29:43 -0600 Subject: [PATCH 015/101] [create-pull-request] automated change (#5388) Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com> --- protobufs | 2 +- src/mesh/generated/meshtastic/device_ui.pb.h | 15 +++++++++++---- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/protobufs b/protobufs index af2fea10f..52688fdcc 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit af2fea10fe2eba5857fb8e27975bbcea9c10af8e +Subproject commit 52688fdccb8a40c23101cada3736b3b22c2b229e diff --git a/src/mesh/generated/meshtastic/device_ui.pb.h b/src/mesh/generated/meshtastic/device_ui.pb.h index 5c1e067ab..107aa8846 100644 --- a/src/mesh/generated/meshtastic/device_ui.pb.h +++ b/src/mesh/generated/meshtastic/device_ui.pb.h @@ -49,6 +49,8 @@ typedef enum _meshtastic_Language { meshtastic_Language_DUTCH = 12, /* Greek */ meshtastic_Language_GREEK = 13, + /* Norwegian */ + meshtastic_Language_NORWEGIAN = 14, /* Simplified Chinese (experimental) */ meshtastic_Language_SIMPLIFIED_CHINESE = 30, /* Traditional Chinese (experimental) */ @@ -84,6 +86,7 @@ typedef struct _meshtastic_NodeHighlight { char node_name[16]; } meshtastic_NodeHighlight; +typedef PB_BYTES_ARRAY_T(16) meshtastic_DeviceUIConfig_calibration_data_t; typedef struct _meshtastic_DeviceUIConfig { /* A version integer used to invalidate saved files when we make incompatible changes. */ uint32_t version; @@ -109,6 +112,8 @@ typedef struct _meshtastic_DeviceUIConfig { /* Node list highlightening */ bool has_node_highlight; meshtastic_NodeHighlight node_highlight; + /* 8 integers for screen calibration data */ + meshtastic_DeviceUIConfig_calibration_data_t calibration_data; } meshtastic_DeviceUIConfig; @@ -132,10 +137,10 @@ extern "C" { /* Initializer values for message structs */ -#define meshtastic_DeviceUIConfig_init_default {0, 0, 0, 0, 0, 0, _meshtastic_Theme_MIN, 0, 0, 0, _meshtastic_Language_MIN, false, meshtastic_NodeFilter_init_default, false, meshtastic_NodeHighlight_init_default} +#define meshtastic_DeviceUIConfig_init_default {0, 0, 0, 0, 0, 0, _meshtastic_Theme_MIN, 0, 0, 0, _meshtastic_Language_MIN, false, meshtastic_NodeFilter_init_default, false, meshtastic_NodeHighlight_init_default, {0, {0}}} #define meshtastic_NodeFilter_init_default {0, 0, 0, 0, 0, ""} #define meshtastic_NodeHighlight_init_default {0, 0, 0, 0, ""} -#define meshtastic_DeviceUIConfig_init_zero {0, 0, 0, 0, 0, 0, _meshtastic_Theme_MIN, 0, 0, 0, _meshtastic_Language_MIN, false, meshtastic_NodeFilter_init_zero, false, meshtastic_NodeHighlight_init_zero} +#define meshtastic_DeviceUIConfig_init_zero {0, 0, 0, 0, 0, 0, _meshtastic_Theme_MIN, 0, 0, 0, _meshtastic_Language_MIN, false, meshtastic_NodeFilter_init_zero, false, meshtastic_NodeHighlight_init_zero, {0, {0}}} #define meshtastic_NodeFilter_init_zero {0, 0, 0, 0, 0, ""} #define meshtastic_NodeHighlight_init_zero {0, 0, 0, 0, ""} @@ -164,6 +169,7 @@ extern "C" { #define meshtastic_DeviceUIConfig_language_tag 11 #define meshtastic_DeviceUIConfig_node_filter_tag 12 #define meshtastic_DeviceUIConfig_node_highlight_tag 13 +#define meshtastic_DeviceUIConfig_calibration_data_tag 14 /* Struct field encoding specification for nanopb */ #define meshtastic_DeviceUIConfig_FIELDLIST(X, a) \ @@ -179,7 +185,8 @@ X(a, STATIC, SINGULAR, BOOL, banner_enabled, 9) \ X(a, STATIC, SINGULAR, UINT32, ring_tone_id, 10) \ X(a, STATIC, SINGULAR, UENUM, language, 11) \ X(a, STATIC, OPTIONAL, MESSAGE, node_filter, 12) \ -X(a, STATIC, OPTIONAL, MESSAGE, node_highlight, 13) +X(a, STATIC, OPTIONAL, MESSAGE, node_highlight, 13) \ +X(a, STATIC, SINGULAR, BYTES, calibration_data, 14) #define meshtastic_DeviceUIConfig_CALLBACK NULL #define meshtastic_DeviceUIConfig_DEFAULT NULL #define meshtastic_DeviceUIConfig_node_filter_MSGTYPE meshtastic_NodeFilter @@ -215,7 +222,7 @@ extern const pb_msgdesc_t meshtastic_NodeHighlight_msg; /* Maximum encoded size of messages (where known) */ #define MESHTASTIC_MESHTASTIC_DEVICE_UI_PB_H_MAX_SIZE meshtastic_DeviceUIConfig_size -#define meshtastic_DeviceUIConfig_size 99 +#define meshtastic_DeviceUIConfig_size 117 #define meshtastic_NodeFilter_size 36 #define meshtastic_NodeHighlight_size 25 From 70336f7f4f5b9d0aab2ec62f11257471c0c87459 Mon Sep 17 00:00:00 2001 From: jcyrio <50239349+jcyrio@users.noreply.github.com> Date: Mon, 18 Nov 2024 22:25:11 -0700 Subject: [PATCH 016/101] add smiley emoji (#5391) * add smiley emoji * clang-formatted --- src/graphics/Screen.cpp | 12 +++++++++++- src/graphics/images.h | 10 ++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index bd0133740..fb7edcbfd 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -966,6 +966,16 @@ static void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state display->drawXbm(x + (SCREEN_WIDTH - thumbs_width) / 2, y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - thumbs_height) / 2 + 2 + 5, thumbs_width, thumbs_height, thumbdown); + } else if (strcmp(reinterpret_cast(mp.decoded.payload.bytes), "\U0001F60A") == 0 || + strcmp(reinterpret_cast(mp.decoded.payload.bytes), "\U0001F600") == 0 || + strcmp(reinterpret_cast(mp.decoded.payload.bytes), "\U0001F642") == 0 || + strcmp(reinterpret_cast(mp.decoded.payload.bytes), "\U0001F609") == 0 || + strcmp(reinterpret_cast(mp.decoded.payload.bytes), "\U0001F601") == + 0) { // matches 5 different common smileys, so that the phone user doesn't have to remember which one is + // compatible + display->drawXbm(x + (SCREEN_WIDTH - smiley_width) / 2, + y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - smiley_height) / 2 + 2 + 5, smiley_width, smiley_height, + smiley); } else if (strcmp(reinterpret_cast(mp.decoded.payload.bytes), "❓") == 0) { display->drawXbm(x + (SCREEN_WIDTH - question_width) / 2, y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - question_height) / 2 + 2 + 5, question_width, question_height, @@ -2747,4 +2757,4 @@ int Screen::handleAdminMessage(const meshtastic_AdminMessage *arg) } // namespace graphics #else graphics::Screen::Screen(ScanI2C::DeviceAddress, meshtastic_Config_DisplayConfig_OledType, OLEDDISPLAY_GEOMETRY) {} -#endif // HAS_SCREEN \ No newline at end of file +#endif // HAS_SCREEN diff --git a/src/graphics/images.h b/src/graphics/images.h index 2b0854a33..fb6b176fc 100644 --- a/src/graphics/images.h +++ b/src/graphics/images.h @@ -56,6 +56,16 @@ static unsigned char thumbdown[] PROGMEM = { 0x80, 0x09, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, }; +#define smiley_height 30 +#define smiley_width 30 +static unsigned char smiley[] PROGMEM = { + 0x00, 0xfe, 0x0f, 0x00, 0x80, 0x01, 0x30, 0x00, 0x40, 0x00, 0xc0, 0x00, 0x20, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x02, + 0x08, 0x00, 0x00, 0x04, 0x04, 0x00, 0x00, 0x08, 0x04, 0x00, 0x00, 0x10, 0x02, 0x0e, 0x0e, 0x10, 0x02, 0x09, 0x12, 0x10, + 0x01, 0x09, 0x12, 0x20, 0x01, 0x0f, 0x1e, 0x20, 0x01, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x20, + 0x01, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x20, 0x81, 0x00, 0x20, 0x20, + 0x82, 0x00, 0x20, 0x10, 0x02, 0x01, 0x10, 0x10, 0x04, 0x02, 0x08, 0x08, 0x04, 0xfc, 0x07, 0x08, 0x08, 0x00, 0x00, 0x04, + 0x10, 0x00, 0x00, 0x02, 0x20, 0x00, 0x00, 0x01, 0x40, 0x00, 0xc0, 0x00, 0x80, 0x01, 0x30, 0x00, 0x00, 0xfe, 0x0f, 0x00}; + #define question_height 25 #define question_width 25 static unsigned char question[] PROGMEM = { From df1f66a6b94b11537accc5527431c05a5af5428e Mon Sep 17 00:00:00 2001 From: "Daniel.Cao" <144674500+DanielCao0@users.noreply.github.com> Date: Tue, 19 Nov 2024 19:42:29 +0800 Subject: [PATCH 017/101] Anable trace route function on wismeshtap platform (#5389) --- variants/rak_wismeshtap/platformio.ini | 1 - 1 file changed, 1 deletion(-) diff --git a/variants/rak_wismeshtap/platformio.ini b/variants/rak_wismeshtap/platformio.ini index 461696d29..277fdbe24 100644 --- a/variants/rak_wismeshtap/platformio.ini +++ b/variants/rak_wismeshtap/platformio.ini @@ -9,7 +9,6 @@ build_flags = ${nrf52840_base.build_flags} -Ivariants/rak_wismeshtap -D RAK_4631 -DEINK_WIDTH=250 -DEINK_HEIGHT=122 -DMESHTASTIC_EXCLUDE_WIFI=1 - -DMESHTASTIC_EXCLUDE_WAYPOINT=1 -DMESHTASTIC_EXCLUDE_DETECTIONSENSOR=1 -DMESHTASTIC_EXCLUDE_STOREFORWARD=1 -DMESHTASTIC_EXCLUDE_POWER_TELEMETRY=1 From b947b123fc80926689332e1ac3fd9d41ef675d5f Mon Sep 17 00:00:00 2001 From: jcyrio <50239349+jcyrio@users.noreply.github.com> Date: Tue, 19 Nov 2024 05:52:20 -0700 Subject: [PATCH 018/101] fix 'symbal' typo (#5395) --- src/graphics/Screen.cpp | 32 ++++++++++++++--------------- src/graphics/Screen.h | 10 ++++----- src/modules/CannedMessageModule.cpp | 16 +++++++-------- 3 files changed, 29 insertions(+), 29 deletions(-) diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index fb7edcbfd..9a41bf298 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -101,9 +101,9 @@ std::vector moduleFrames; static char ourId[5]; // vector where symbols (string) are displayed in bottom corner of display. -std::vector functionSymbals; -// string displayed in bottom right corner of display. Created from elements in functionSymbals vector -std::string functionSymbalString = ""; +std::vector functionSymbol; +// string displayed in bottom right corner of display. Created from elements in functionSymbol vector +std::string functionSymbolString = ""; #if HAS_GPS // GeoCoord object for the screen @@ -243,10 +243,10 @@ static void drawWelcomeScreen(OLEDDisplay *display, OLEDDisplayUiState *state, i static void drawFunctionOverlay(OLEDDisplay *display, OLEDDisplayUiState *state) { // LOG_DEBUG("Draw function overlay"); - if (functionSymbals.begin() != functionSymbals.end()) { + if (functionSymbol.begin() != functionSymbol.end()) { char buf[64]; display->setFont(FONT_SMALL); - snprintf(buf, sizeof(buf), "%s", functionSymbalString.c_str()); + snprintf(buf, sizeof(buf), "%s", functionSymbolString.c_str()); display->drawString(SCREEN_WIDTH - display->getStringWidth(buf), SCREEN_HEIGHT - FONT_HEIGHT_SMALL, buf); } } @@ -2252,24 +2252,24 @@ void Screen::decreaseBrightness() /* TO DO: add little popup in center of screen saying what brightness level it is set to*/ } -void Screen::setFunctionSymbal(std::string sym) +void Screen::setFunctionSymbol(std::string sym) { - if (std::find(functionSymbals.begin(), functionSymbals.end(), sym) == functionSymbals.end()) { - functionSymbals.push_back(sym); - functionSymbalString = ""; - for (auto symbol : functionSymbals) { - functionSymbalString = symbol + " " + functionSymbalString; + if (std::find(functionSymbol.begin(), functionSymbol.end(), sym) == functionSymbol.end()) { + functionSymbol.push_back(sym); + functionSymbolString = ""; + for (auto symbol : functionSymbol) { + functionSymbolString = symbol + " " + functionSymbolString; } setFastFramerate(); } } -void Screen::removeFunctionSymbal(std::string sym) +void Screen::removeFunctionSymbol(std::string sym) { - functionSymbals.erase(std::remove(functionSymbals.begin(), functionSymbals.end(), sym), functionSymbals.end()); - functionSymbalString = ""; - for (auto symbol : functionSymbals) { - functionSymbalString = symbol + " " + functionSymbalString; + functionSymbol.erase(std::remove(functionSymbol.begin(), functionSymbol.end(), sym), functionSymbol.end()); + functionSymbolString = ""; + for (auto symbol : functionSymbol) { + functionSymbolString = symbol + " " + functionSymbolString; } setFastFramerate(); } diff --git a/src/graphics/Screen.h b/src/graphics/Screen.h index 3066c0c17..ee8de69f0 100644 --- a/src/graphics/Screen.h +++ b/src/graphics/Screen.h @@ -24,8 +24,8 @@ class Screen void startFirmwareUpdateScreen() {} void increaseBrightness() {} void decreaseBrightness() {} - void setFunctionSymbal(std::string) {} - void removeFunctionSymbal(std::string) {} + void setFunctionSymbol(std::string) {} + void removeFunctionSymbol(std::string) {} void startAlert(const char *) {} void endAlert() {} }; @@ -282,8 +282,8 @@ class Screen : public concurrency::OSThread void increaseBrightness(); void decreaseBrightness(); - void setFunctionSymbal(std::string sym); - void removeFunctionSymbal(std::string sym); + void setFunctionSymbol(std::string sym); + void removeFunctionSymbol(std::string sym); /// Stops showing the boot screen. void stopBootScreen() { enqueueCmd(ScreenCmd{.cmd = Cmd::STOP_BOOT_SCREEN}); } @@ -605,4 +605,4 @@ class Screen : public concurrency::OSThread } // namespace graphics -#endif \ No newline at end of file +#endif diff --git a/src/modules/CannedMessageModule.cpp b/src/modules/CannedMessageModule.cpp index 37409b43b..6d1bfdc5c 100644 --- a/src/modules/CannedMessageModule.cpp +++ b/src/modules/CannedMessageModule.cpp @@ -234,13 +234,13 @@ int CannedMessageModule::handleInputEvent(const InputEvent *event) screen->decreaseBrightness(); LOG_DEBUG("Decrease Screen Brightness"); break; - case INPUT_BROKER_MSG_FN_SYMBOL_ON: // draw modifier (function) symbal + case INPUT_BROKER_MSG_FN_SYMBOL_ON: // draw modifier (function) symbol if (screen) - screen->setFunctionSymbal("Fn"); + screen->setFunctionSymbol("Fn"); break; - case INPUT_BROKER_MSG_FN_SYMBOL_OFF: // remove modifier (function) symbal + case INPUT_BROKER_MSG_FN_SYMBOL_OFF: // remove modifier (function) symbol if (screen) - screen->removeFunctionSymbal("Fn"); + screen->removeFunctionSymbol("Fn"); break; // mute (switch off/toggle) external notifications on fn+m case INPUT_BROKER_MSG_MUTE_TOGGLE: @@ -249,13 +249,13 @@ int CannedMessageModule::handleInputEvent(const InputEvent *event) externalNotificationModule->setMute(false); showTemporaryMessage("Notifications \nEnabled"); if (screen) - screen->removeFunctionSymbal("M"); // remove the mute symbol from the bottom right corner + screen->removeFunctionSymbol("M"); // remove the mute symbol from the bottom right corner } else { externalNotificationModule->stopNow(); // this will turn off all GPIO and sounds and idle the loop externalNotificationModule->setMute(true); showTemporaryMessage("Notifications \nDisabled"); if (screen) - screen->setFunctionSymbal("M"); // add the mute symbol to the bottom right corner + screen->setFunctionSymbol("M"); // add the mute symbol to the bottom right corner } } break; @@ -308,7 +308,7 @@ int CannedMessageModule::handleInputEvent(const InputEvent *event) break; } if (screen && (event->kbchar != INPUT_BROKER_MSG_FN_SYMBOL_ON)) { - screen->removeFunctionSymbal("Fn"); // remove modifier (function) symbal + screen->removeFunctionSymbol("Fn"); // remove modifier (function) symbol } } @@ -672,7 +672,7 @@ int32_t CannedMessageModule::runOnce() break; } if (screen) - screen->removeFunctionSymbal("Fn"); + screen->removeFunctionSymbol("Fn"); } this->lastTouchMillis = millis(); From c641bfd53c5948479d07883c7e2a30aa113e58fe Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 19 Nov 2024 12:53:54 -0600 Subject: [PATCH 019/101] [create-pull-request] automated change (#5399) Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com> --- protobufs | 2 +- src/mesh/generated/meshtastic/deviceonly.pb.h | 12 +++++++---- src/mesh/generated/meshtastic/mesh.pb.h | 21 +++++++++++++++---- 3 files changed, 26 insertions(+), 9 deletions(-) diff --git a/protobufs b/protobufs index 52688fdcc..af7521c3a 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit 52688fdccb8a40c23101cada3736b3b22c2b229e +Subproject commit af7521c3a77d56eb7a64efae5637a311ac33f76d diff --git a/src/mesh/generated/meshtastic/deviceonly.pb.h b/src/mesh/generated/meshtastic/deviceonly.pb.h index d9e291175..e52a914e0 100644 --- a/src/mesh/generated/meshtastic/deviceonly.pb.h +++ b/src/mesh/generated/meshtastic/deviceonly.pb.h @@ -90,6 +90,8 @@ typedef struct _meshtastic_NodeInfoLite { /* True if node is in our ignored list Persists between NodeDB internal clean ups */ bool is_ignored; + /* 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; } meshtastic_NodeInfoLite; /* This message is never sent over the wire, but it is used for serializing DB @@ -153,12 +155,12 @@ extern "C" { /* Initializer values for message structs */ #define meshtastic_PositionLite_init_default {0, 0, 0, 0, _meshtastic_Position_LocSource_MIN} #define meshtastic_UserLite_init_default {{0}, "", "", _meshtastic_HardwareModel_MIN, 0, _meshtastic_Config_DeviceConfig_Role_MIN, {0, {0}}} -#define meshtastic_NodeInfoLite_init_default {0, false, meshtastic_UserLite_init_default, false, meshtastic_PositionLite_init_default, 0, 0, false, meshtastic_DeviceMetrics_init_default, 0, 0, false, 0, 0, 0} +#define meshtastic_NodeInfoLite_init_default {0, false, meshtastic_UserLite_init_default, false, meshtastic_PositionLite_init_default, 0, 0, false, meshtastic_DeviceMetrics_init_default, 0, 0, false, 0, 0, 0, 0} #define meshtastic_DeviceState_init_default {false, meshtastic_MyNodeInfo_init_default, false, meshtastic_User_init_default, 0, {meshtastic_MeshPacket_init_default}, false, meshtastic_MeshPacket_init_default, 0, 0, 0, false, meshtastic_MeshPacket_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}, {0}} #define meshtastic_ChannelFile_init_default {0, {meshtastic_Channel_init_default, meshtastic_Channel_init_default, meshtastic_Channel_init_default, meshtastic_Channel_init_default, meshtastic_Channel_init_default, meshtastic_Channel_init_default, meshtastic_Channel_init_default, meshtastic_Channel_init_default}, 0} #define meshtastic_PositionLite_init_zero {0, 0, 0, 0, _meshtastic_Position_LocSource_MIN} #define meshtastic_UserLite_init_zero {{0}, "", "", _meshtastic_HardwareModel_MIN, 0, _meshtastic_Config_DeviceConfig_Role_MIN, {0, {0}}} -#define meshtastic_NodeInfoLite_init_zero {0, false, meshtastic_UserLite_init_zero, false, meshtastic_PositionLite_init_zero, 0, 0, false, meshtastic_DeviceMetrics_init_zero, 0, 0, false, 0, 0, 0} +#define meshtastic_NodeInfoLite_init_zero {0, false, meshtastic_UserLite_init_zero, false, meshtastic_PositionLite_init_zero, 0, 0, false, meshtastic_DeviceMetrics_init_zero, 0, 0, false, 0, 0, 0, 0} #define meshtastic_DeviceState_init_zero {false, meshtastic_MyNodeInfo_init_zero, false, meshtastic_User_init_zero, 0, {meshtastic_MeshPacket_init_zero}, false, meshtastic_MeshPacket_init_zero, 0, 0, 0, false, meshtastic_MeshPacket_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}, {0}} #define meshtastic_ChannelFile_init_zero {0, {meshtastic_Channel_init_zero, meshtastic_Channel_init_zero, meshtastic_Channel_init_zero, meshtastic_Channel_init_zero, meshtastic_Channel_init_zero, meshtastic_Channel_init_zero, meshtastic_Channel_init_zero, meshtastic_Channel_init_zero}, 0} @@ -186,6 +188,7 @@ extern "C" { #define meshtastic_NodeInfoLite_hops_away_tag 9 #define meshtastic_NodeInfoLite_is_favorite_tag 10 #define meshtastic_NodeInfoLite_is_ignored_tag 11 +#define meshtastic_NodeInfoLite_next_hop_tag 12 #define meshtastic_DeviceState_my_node_tag 2 #define meshtastic_DeviceState_owner_tag 3 #define meshtastic_DeviceState_receive_queue_tag 5 @@ -231,7 +234,8 @@ X(a, STATIC, SINGULAR, UINT32, channel, 7) \ 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_ignored, 11) \ +X(a, STATIC, SINGULAR, UINT32, next_hop, 12) #define meshtastic_NodeInfoLite_CALLBACK NULL #define meshtastic_NodeInfoLite_DEFAULT NULL #define meshtastic_NodeInfoLite_user_MSGTYPE meshtastic_UserLite @@ -284,7 +288,7 @@ extern const pb_msgdesc_t meshtastic_ChannelFile_msg; /* meshtastic_DeviceState_size depends on runtime parameters */ #define MESHTASTIC_MESHTASTIC_DEVICEONLY_PB_H_MAX_SIZE meshtastic_ChannelFile_size #define meshtastic_ChannelFile_size 718 -#define meshtastic_NodeInfoLite_size 185 +#define meshtastic_NodeInfoLite_size 188 #define meshtastic_PositionLite_size 28 #define meshtastic_UserLite_size 96 diff --git a/src/mesh/generated/meshtastic/mesh.pb.h b/src/mesh/generated/meshtastic/mesh.pb.h index 0d37efd54..3e195e7f5 100644 --- a/src/mesh/generated/meshtastic/mesh.pb.h +++ b/src/mesh/generated/meshtastic/mesh.pb.h @@ -212,6 +212,9 @@ typedef enum _meshtastic_HardwareModel { meshtastic_HardwareModel_MS24SF1 = 82, /* Lilygo TLora-C6 with the new ESP32-C6 MCU */ meshtastic_HardwareModel_TLORA_C6 = 83, + /* WisMesh Tap + RAK-4631 w/ TFT in injection modled case */ + meshtastic_HardwareModel_WISMESH_TAP = 84, /* ------------------------------------------------------------------------------------------------------------------------------------------ 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. ------------------------------------------------------------------------------------------------------------------------------------------ */ @@ -751,6 +754,12 @@ typedef struct _meshtastic_MeshPacket { meshtastic_MeshPacket_public_key_t public_key; /* Indicates whether the packet was en/decrypted using PKI */ bool pki_encrypted; + /* Last byte of the node number of the node that should be used as the next hop in routing. + Set by the firmware internally, clients are not supposed to set this. */ + uint8_t next_hop; + /* Last byte of the node number of the node that will relay/relayed this packet. + Set by the firmware internally, clients are not supposed to set this. */ + uint8_t relay_node; } meshtastic_MeshPacket; /* The bluetooth to device link: @@ -1159,7 +1168,7 @@ extern "C" { #define meshtastic_Data_init_default {_meshtastic_PortNum_MIN, {0, {0}}, 0, 0, 0, 0, 0, 0, false, 0} #define meshtastic_Waypoint_init_default {0, false, 0, false, 0, 0, 0, "", "", 0} #define meshtastic_MqttClientProxyMessage_init_default {"", 0, {{0, {0}}}, 0} -#define meshtastic_MeshPacket_init_default {0, 0, 0, 0, {meshtastic_Data_init_default}, 0, 0, 0, 0, 0, _meshtastic_MeshPacket_Priority_MIN, 0, _meshtastic_MeshPacket_Delayed_MIN, 0, 0, {0, {0}}, 0} +#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} #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} #define meshtastic_MyNodeInfo_init_default {0, 0, 0, {0, {0}}, ""} #define meshtastic_LogRecord_init_default {"", 0, "", _meshtastic_LogRecord_Level_MIN} @@ -1184,7 +1193,7 @@ extern "C" { #define meshtastic_Data_init_zero {_meshtastic_PortNum_MIN, {0, {0}}, 0, 0, 0, 0, 0, 0, false, 0} #define meshtastic_Waypoint_init_zero {0, false, 0, false, 0, 0, 0, "", "", 0} #define meshtastic_MqttClientProxyMessage_init_zero {"", 0, {{0, {0}}}, 0} -#define meshtastic_MeshPacket_init_zero {0, 0, 0, 0, {meshtastic_Data_init_zero}, 0, 0, 0, 0, 0, _meshtastic_MeshPacket_Priority_MIN, 0, _meshtastic_MeshPacket_Delayed_MIN, 0, 0, {0, {0}}, 0} +#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} #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} #define meshtastic_MyNodeInfo_init_zero {0, 0, 0, {0, {0}}, ""} #define meshtastic_LogRecord_init_zero {"", 0, "", _meshtastic_LogRecord_Level_MIN} @@ -1280,6 +1289,8 @@ extern "C" { #define meshtastic_MeshPacket_hop_start_tag 15 #define meshtastic_MeshPacket_public_key_tag 16 #define meshtastic_MeshPacket_pki_encrypted_tag 17 +#define meshtastic_MeshPacket_next_hop_tag 18 +#define meshtastic_MeshPacket_relay_node_tag 19 #define meshtastic_NodeInfo_num_tag 1 #define meshtastic_NodeInfo_user_tag 2 #define meshtastic_NodeInfo_position_tag 3 @@ -1474,7 +1485,9 @@ X(a, STATIC, SINGULAR, UENUM, delayed, 13) \ X(a, STATIC, SINGULAR, BOOL, via_mqtt, 14) \ X(a, STATIC, SINGULAR, UINT32, hop_start, 15) \ X(a, STATIC, SINGULAR, BYTES, public_key, 16) \ -X(a, STATIC, SINGULAR, BOOL, pki_encrypted, 17) +X(a, STATIC, SINGULAR, BOOL, pki_encrypted, 17) \ +X(a, STATIC, SINGULAR, UINT32, next_hop, 18) \ +X(a, STATIC, SINGULAR, UINT32, relay_node, 19) #define meshtastic_MeshPacket_CALLBACK NULL #define meshtastic_MeshPacket_DEFAULT NULL #define meshtastic_MeshPacket_payload_variant_decoded_MSGTYPE meshtastic_Data @@ -1724,7 +1737,7 @@ extern const pb_msgdesc_t meshtastic_ChunkedPayloadResponse_msg; #define meshtastic_FromRadio_size 510 #define meshtastic_Heartbeat_size 0 #define meshtastic_LogRecord_size 426 -#define meshtastic_MeshPacket_size 367 +#define meshtastic_MeshPacket_size 375 #define meshtastic_MqttClientProxyMessage_size 501 #define meshtastic_MyNodeInfo_size 77 #define meshtastic_NeighborInfo_size 258 From d65dc497f221e41d67b4f6977d154a00f8a9f34e Mon Sep 17 00:00:00 2001 From: Catalin Patulea Date: Tue, 19 Nov 2024 15:33:44 -0500 Subject: [PATCH 020/101] /api/v1/fromradio: add OPTIONS handler for CORS. (#5386) This avoids hitting the 404 Not Found handler, which breaks connection keep-alive, so this change fixes a big performance regression for Web Client in Chrome: https://github.com/meshtastic/firmware/issues/5385 Tested on Heltec V3. Co-authored-by: Ben Meadors --- src/mesh/http/ContentHandler.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/mesh/http/ContentHandler.cpp b/src/mesh/http/ContentHandler.cpp index efa816438..64f7164c9 100644 --- a/src/mesh/http/ContentHandler.cpp +++ b/src/mesh/http/ContentHandler.cpp @@ -74,6 +74,7 @@ void registerHandlers(HTTPServer *insecureServer, HTTPSServer *secureServer) ResourceNode *nodeAPIv1ToRadioOptions = new ResourceNode("/api/v1/toradio", "OPTIONS", &handleAPIv1ToRadio); ResourceNode *nodeAPIv1ToRadio = new ResourceNode("/api/v1/toradio", "PUT", &handleAPIv1ToRadio); + ResourceNode *nodeAPIv1FromRadioOptions = new ResourceNode("/api/v1/fromradio", "OPTIONS", &handleAPIv1FromRadio); ResourceNode *nodeAPIv1FromRadio = new ResourceNode("/api/v1/fromradio", "GET", &handleAPIv1FromRadio); // ResourceNode *nodeHotspotApple = new ResourceNode("/hotspot-detect.html", "GET", &handleHotspot); @@ -100,6 +101,7 @@ void registerHandlers(HTTPServer *insecureServer, HTTPSServer *secureServer) // Secure nodes secureServer->registerNode(nodeAPIv1ToRadioOptions); secureServer->registerNode(nodeAPIv1ToRadio); + secureServer->registerNode(nodeAPIv1FromRadioOptions); secureServer->registerNode(nodeAPIv1FromRadio); // secureServer->registerNode(nodeHotspotApple); // secureServer->registerNode(nodeHotspotAndroid); @@ -121,6 +123,7 @@ void registerHandlers(HTTPServer *insecureServer, HTTPSServer *secureServer) // Insecure nodes insecureServer->registerNode(nodeAPIv1ToRadioOptions); insecureServer->registerNode(nodeAPIv1ToRadio); + insecureServer->registerNode(nodeAPIv1FromRadioOptions); insecureServer->registerNode(nodeAPIv1FromRadio); // insecureServer->registerNode(nodeHotspotApple); // insecureServer->registerNode(nodeHotspotAndroid); @@ -163,6 +166,12 @@ void handleAPIv1FromRadio(HTTPRequest *req, HTTPResponse *res) res->setHeader("Access-Control-Allow-Methods", "GET"); res->setHeader("X-Protobuf-Schema", "https://raw.githubusercontent.com/meshtastic/protobufs/master/meshtastic/mesh.proto"); + if (req->getMethod() == "OPTIONS") { + res->setStatusCode(204); // Success with no content + // res->print(""); @todo remove + return; + } + uint8_t txBuf[MAX_STREAM_BUF_SIZE]; uint32_t len = 1; From a255da3cf531a34c9f9bbfe8931576168ef8cacb Mon Sep 17 00:00:00 2001 From: jcyrio <50239349+jcyrio@users.noreply.github.com> Date: Tue, 19 Nov 2024 20:31:46 -0700 Subject: [PATCH 021/101] Make heart emoji usable (#5403) --- src/graphics/Screen.cpp | 44 ++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index 9a41bf298..f18baf276 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -958,65 +958,65 @@ static void drawTextMessageFrame(OLEDDisplay *display, OLEDDisplayUiState *state display->setColor(WHITE); #ifndef EXCLUDE_EMOJI - if (strcmp(reinterpret_cast(mp.decoded.payload.bytes), "\U0001F44D") == 0) { + const char *msg = reinterpret_cast(mp.decoded.payload.bytes); + if (strcmp(msg, "\U0001F44D") == 0) { display->drawXbm(x + (SCREEN_WIDTH - thumbs_width) / 2, y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - thumbs_height) / 2 + 2 + 5, thumbs_width, thumbs_height, thumbup); - } else if (strcmp(reinterpret_cast(mp.decoded.payload.bytes), "\U0001F44E") == 0) { + } else if (strcmp(msg, "\U0001F44E") == 0) { display->drawXbm(x + (SCREEN_WIDTH - thumbs_width) / 2, y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - thumbs_height) / 2 + 2 + 5, thumbs_width, thumbs_height, thumbdown); - } else if (strcmp(reinterpret_cast(mp.decoded.payload.bytes), "\U0001F60A") == 0 || - strcmp(reinterpret_cast(mp.decoded.payload.bytes), "\U0001F600") == 0 || - strcmp(reinterpret_cast(mp.decoded.payload.bytes), "\U0001F642") == 0 || - strcmp(reinterpret_cast(mp.decoded.payload.bytes), "\U0001F609") == 0 || - strcmp(reinterpret_cast(mp.decoded.payload.bytes), "\U0001F601") == - 0) { // matches 5 different common smileys, so that the phone user doesn't have to remember which one is - // compatible + } else if (strcmp(msg, "\U0001F60A") == 0 || strcmp(msg, "\U0001F600") == 0 || strcmp(msg, "\U0001F642") == 0 || + strcmp(msg, "\U0001F609") == 0 || + strcmp(msg, "\U0001F601") == 0) { // matches 5 different common smileys, so that the phone user doesn't have to + // remember which one is compatible display->drawXbm(x + (SCREEN_WIDTH - smiley_width) / 2, y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - smiley_height) / 2 + 2 + 5, smiley_width, smiley_height, smiley); - } else if (strcmp(reinterpret_cast(mp.decoded.payload.bytes), "❓") == 0) { + } else if (strcmp(msg, "❓") == 0) { display->drawXbm(x + (SCREEN_WIDTH - question_width) / 2, y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - question_height) / 2 + 2 + 5, question_width, question_height, question); - } else if (strcmp(reinterpret_cast(mp.decoded.payload.bytes), "‼️") == 0) { + } else if (strcmp(msg, "‼️") == 0) { display->drawXbm(x + (SCREEN_WIDTH - bang_width) / 2, y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - bang_height) / 2 + 2 + 5, bang_width, bang_height, bang); - } else if (strcmp(reinterpret_cast(mp.decoded.payload.bytes), "\U0001F4A9") == 0) { + } else if (strcmp(msg, "\U0001F4A9") == 0) { display->drawXbm(x + (SCREEN_WIDTH - poo_width) / 2, y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - poo_height) / 2 + 2 + 5, poo_width, poo_height, poo); - } else if (strcmp(reinterpret_cast(mp.decoded.payload.bytes), "\xf0\x9f\xa4\xa3") == 0) { + } else if (strcmp(msg, "\U0001F923") == 0) { display->drawXbm(x + (SCREEN_WIDTH - haha_width) / 2, y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - haha_height) / 2 + 2 + 5, haha_width, haha_height, haha); - } else if (strcmp(reinterpret_cast(mp.decoded.payload.bytes), "\U0001F44B") == 0) { + } else if (strcmp(msg, "\U0001F44B") == 0) { display->drawXbm(x + (SCREEN_WIDTH - wave_icon_width) / 2, y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - wave_icon_height) / 2 + 2 + 5, wave_icon_width, wave_icon_height, wave_icon); - } else if (strcmp(reinterpret_cast(mp.decoded.payload.bytes), "\U0001F920") == 0) { + } else if (strcmp(msg, "\U0001F920") == 0) { display->drawXbm(x + (SCREEN_WIDTH - cowboy_width) / 2, y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - cowboy_height) / 2 + 2 + 5, cowboy_width, cowboy_height, cowboy); - } else if (strcmp(reinterpret_cast(mp.decoded.payload.bytes), "\U0001F42D") == 0) { + } else if (strcmp(msg, "\U0001F42D") == 0) { display->drawXbm(x + (SCREEN_WIDTH - deadmau5_width) / 2, y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - deadmau5_height) / 2 + 2 + 5, deadmau5_width, deadmau5_height, deadmau5); - } else if (strcmp(reinterpret_cast(mp.decoded.payload.bytes), "\xE2\x98\x80\xEF\xB8\x8F") == 0) { + } else if (strcmp(msg, "\xE2\x98\x80\xEF\xB8\x8F") == 0) { display->drawXbm(x + (SCREEN_WIDTH - sun_width) / 2, y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - sun_height) / 2 + 2 + 5, sun_width, sun_height, sun); - } else if (strcmp(reinterpret_cast(mp.decoded.payload.bytes), "\u2614") == 0) { + } else if (strcmp(msg, "\u2614") == 0) { display->drawXbm(x + (SCREEN_WIDTH - rain_width) / 2, y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - rain_height) / 2 + 2 + 10, rain_width, rain_height, rain); - } else if (strcmp(reinterpret_cast(mp.decoded.payload.bytes), "☁️") == 0) { + } else if (strcmp(msg, "☁️") == 0) { display->drawXbm(x + (SCREEN_WIDTH - cloud_width) / 2, y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - cloud_height) / 2 + 2 + 5, cloud_width, cloud_height, cloud); - } else if (strcmp(reinterpret_cast(mp.decoded.payload.bytes), "🌫️") == 0) { + } else if (strcmp(msg, "🌫️") == 0) { display->drawXbm(x + (SCREEN_WIDTH - fog_width) / 2, y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - fog_height) / 2 + 2 + 5, fog_width, fog_height, fog); - } else if (strcmp(reinterpret_cast(mp.decoded.payload.bytes), "\xf0\x9f\x98\x88") == 0) { + } else if (strcmp(msg, "\U0001F608") == 0) { display->drawXbm(x + (SCREEN_WIDTH - devil_width) / 2, y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - devil_height) / 2 + 2 + 5, devil_width, devil_height, devil); - } else if (strcmp(reinterpret_cast(mp.decoded.payload.bytes), "♥️") == 0) { + } else if (strcmp(msg, "♥️") == 0 || strcmp(msg, "\U0001F9E1") == 0 || strcmp(msg, "\U00002763") == 0 || + strcmp(msg, "\U00002764") == 0 || strcmp(msg, "\U0001F495") == 0 || strcmp(msg, "\U0001F496") == 0 || + strcmp(msg, "\U0001F497") == 0 || strcmp(msg, "\U0001F496") == 0) { display->drawXbm(x + (SCREEN_WIDTH - heart_width) / 2, y + (SCREEN_HEIGHT - FONT_HEIGHT_MEDIUM - heart_height) / 2 + 2 + 5, heart_width, heart_height, heart); } else { From 485c371de488773796d022e3df6099680c11cdd5 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Tue, 19 Nov 2024 22:57:46 -0600 Subject: [PATCH 022/101] Create a specific hw_model for WisMesh Tap (#5400) * Create a specific hw_model for WisMesh Tap * Trunk * HAS_ETHERNET * Remove it altogether * Don't need these either --- src/gps/GPS.cpp | 3 ++- src/platform/nrf52/architecture.h | 2 ++ variants/rak_wismeshtap/platformio.ini | 2 +- variants/rak_wismeshtap/variant.h | 5 ----- 4 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/gps/GPS.cpp b/src/gps/GPS.cpp index 099a21f82..a6db85950 100644 --- a/src/gps/GPS.cpp +++ b/src/gps/GPS.cpp @@ -788,7 +788,8 @@ void GPS::setPowerState(GPSPowerState newState, uint32_t sleepTime) void GPS::writePinEN(bool on) { // Abort: if conflict with Canned Messages when using Wisblock(?) - if (HW_VENDOR == meshtastic_HardwareModel_RAK4631 && (rotaryEncoderInterruptImpl1 || upDownInterruptImpl1)) + if ((HW_VENDOR == meshtastic_HardwareModel_RAK4631 || HW_VENDOR == meshtastic_HardwareModel_WISMESH_TAP) && + (rotaryEncoderInterruptImpl1 || upDownInterruptImpl1)) return; // Write and log diff --git a/src/platform/nrf52/architecture.h b/src/platform/nrf52/architecture.h index b2b7b5a20..ce99244ba 100644 --- a/src/platform/nrf52/architecture.h +++ b/src/platform/nrf52/architecture.h @@ -47,6 +47,8 @@ #define HW_VENDOR meshtastic_HardwareModel_PPR #elif defined(RAK2560) #define HW_VENDOR meshtastic_HardwareModel_RAK2560 +#elif defined(WISMESH_TAP) +#define HW_VENDOR meshtastic_HardwareModel_WISMESH_TAP #elif defined(RAK4630) #define HW_VENDOR meshtastic_HardwareModel_RAK4631 #elif defined(TTGO_T_ECHO) diff --git a/variants/rak_wismeshtap/platformio.ini b/variants/rak_wismeshtap/platformio.ini index 277fdbe24..bcf46b90d 100644 --- a/variants/rak_wismeshtap/platformio.ini +++ b/variants/rak_wismeshtap/platformio.ini @@ -2,7 +2,7 @@ [env:rak_wismeshtap] extends = nrf52840_base board = wiscore_rak4631 -build_flags = ${nrf52840_base.build_flags} -Ivariants/rak_wismeshtap -D RAK_4631 +build_flags = ${nrf52840_base.build_flags} -Ivariants/rak_wismeshtap -DWISMESH_TAP -DRAK_4631 -L "${platformio.libdeps_dir}/${this.__env__}/bsec2/src/cortex-m4/fpv4-sp-d16-hard" -DGPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely. -DEINK_DISPLAY_MODEL=GxEPD2_213_BN diff --git a/variants/rak_wismeshtap/variant.h b/variants/rak_wismeshtap/variant.h index 19eb841fe..134a20227 100644 --- a/variants/rak_wismeshtap/variant.h +++ b/variants/rak_wismeshtap/variant.h @@ -271,13 +271,8 @@ SO GPIO 39/TXEN MAY NOT BE DEFINED FOR SUCCESSFUL OPERATION OF THE SX1262 - TG #define HAS_RTC 1 -#define HAS_ETHERNET 1 - #define RAK_4631 1 -#define PIN_ETHERNET_RESET 21 -#define PIN_ETHERNET_SS PIN_EINK_CS -#define ETH_SPI_PORT SPI1 #define AQ_SET_PIN 10 #ifdef __cplusplus From 2ca3cdf837ddf522522667402d94aa2796e5e4f2 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Wed, 20 Nov 2024 07:52:39 -0600 Subject: [PATCH 023/101] Fix RTC time injection and consolidate position logic (#5396) * Fix RTC time injection and consolidate position logic * Comment out unused var warning * Backerds --- src/mesh/NodeDB.cpp | 2 +- src/modules/PositionModule.cpp | 38 ++++++++++++++++++++-------------- src/modules/PositionModule.h | 1 + 3 files changed, 24 insertions(+), 17 deletions(-) diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index 55b8c0b4d..841a50d65 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -114,7 +114,7 @@ NodeDB::NodeDB() uint32_t channelFileCRC = crc32Buffer(&channelFile, sizeof(channelFile)); int saveWhat = 0; - bool hasUniqueId = false; + // bool hasUniqueId = false; // Get device unique id #if defined(ARCH_ESP32) && defined(ESP_EFUSE_OPTIONAL_UNIQUE_ID) uint32_t unique_id[4]; diff --git a/src/modules/PositionModule.cpp b/src/modules/PositionModule.cpp index fc15aabb6..d977cfdec 100644 --- a/src/modules/PositionModule.cpp +++ b/src/modules/PositionModule.cpp @@ -146,11 +146,20 @@ bool PositionModule::hasQualityTimesource() #if MESHTASTIC_EXCLUDE_GPS bool hasGpsOrRtc = (rtc_found.address != ScanI2C::ADDRESS_NONE.address); #else - bool hasGpsOrRtc = (gps && gps->isConnected()) || (rtc_found.address != ScanI2C::ADDRESS_NONE.address); + bool hasGpsOrRtc = hasGPS() || (rtc_found.address != ScanI2C::ADDRESS_NONE.address); #endif return hasGpsOrRtc || setFromPhoneOrNtpToday; } +bool PositionModule::hasGPS() +{ +#if MESHTASTIC_EXCLUDE_GPS + return false; +#else + return gps && gps->isConnected(); +#endif +} + meshtastic_MeshPacket *PositionModule::allocReply() { if (precision == 0) { @@ -194,10 +203,21 @@ meshtastic_MeshPacket *PositionModule::allocReply() p.precision_bits = precision; p.has_latitude_i = true; p.has_longitude_i = true; - p.time = getValidTime(RTCQualityNTP) > 0 ? getValidTime(RTCQualityNTP) : localPosition.time; + // Always use NTP / GPS time if available + if (getValidTime(RTCQualityNTP) > 0) { + p.time = getValidTime(RTCQualityNTP); + } else if (rtc_found.address != ScanI2C::ADDRESS_NONE.address) { + LOG_INFO("Use RTC time for position"); + p.time = getValidTime(RTCQualityDevice); + } else if (getRTCQuality() < RTCQualityNTP) { + LOG_INFO("Strip low RTCQuality (%d) time from position", getRTCQuality()); + p.time = 0; + } if (config.position.fixed_position) { p.location_source = meshtastic_Position_LocSource_LOC_MANUAL; + } else { + p.location_source = localPosition.location_source; } if (pos_flags & meshtastic_Config_PositionConfig_PositionFlags_ALTITUDE) { @@ -242,20 +262,6 @@ meshtastic_MeshPacket *PositionModule::allocReply() p.has_ground_speed = true; } - // Strip out any time information before sending packets to other nodes - to keep the wire size small (and because other - // nodes shouldn't trust it anyways) Note: we allow a device with a local GPS or NTP to include the time, so that devices - // without can get time. - if (getRTCQuality() < RTCQualityNTP) { - LOG_INFO("Strip time %u from position", p.time); - p.time = 0; - } else if (rtc_found.address != ScanI2C::ADDRESS_NONE.address) { - LOG_INFO("Use RTC time %u for position", p.time); - p.time = getValidTime(RTCQualityDevice); - } else { - p.time = getValidTime(RTCQualityNTP); - LOG_INFO("Provide time to mesh %u", p.time); - } - LOG_INFO("Position reply: time=%i lat=%i lon=%i", p.time, p.latitude_i, p.longitude_i); // TAK Tracker devices should send their position in a TAK packet over the ATAK port diff --git a/src/modules/PositionModule.h b/src/modules/PositionModule.h index 41b86b795..1e4aa5d29 100644 --- a/src/modules/PositionModule.h +++ b/src/modules/PositionModule.h @@ -61,6 +61,7 @@ class PositionModule : public ProtobufModule, private concu uint32_t precision; void sendLostAndFoundText(); bool hasQualityTimesource(); + bool hasGPS(); const uint32_t minimumTimeThreshold = Default::getConfiguredOrDefaultMs(config.position.broadcast_smart_minimum_interval_secs, 30); From 154864dfbff306d93337435d74503f1ad59967e3 Mon Sep 17 00:00:00 2001 From: GUVWAF <78759985+GUVWAF@users.noreply.github.com> Date: Wed, 20 Nov 2024 20:18:27 +0100 Subject: [PATCH 024/101] Update arduino-pico core to fix sporadic hangs (#5406) --- arch/rp2xx0/rp2040.ini | 4 ++-- arch/rp2xx0/rp2350.ini | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/arch/rp2xx0/rp2040.ini b/arch/rp2xx0/rp2040.ini index 57e5d7bc2..031a4848f 100644 --- a/arch/rp2xx0/rp2040.ini +++ b/arch/rp2xx0/rp2040.ini @@ -2,7 +2,7 @@ [rp2040_base] platform = https://github.com/maxgerhardt/platform-raspberrypi.git#a606be683748c73e9a0d46baf70163478d298f0f ; For arduino-pico 4.2.0 extends = arduino_base -platform_packages = framework-arduinopico@https://github.com/earlephilhower/arduino-pico.git#4.2.1 +platform_packages = framework-arduinopico@https://github.com/earlephilhower/arduino-pico.git#996c3bfab9758f12c07aa20cc6d352e630c16987 ; 4.2.1 with fix for sporadic hangs board_build.core = earlephilhower board_build.filesystem_size = 0.5m @@ -23,4 +23,4 @@ lib_deps = ${arduino_base.lib_deps} ${environmental_base.lib_deps} ${radiolib_base.lib_deps} - rweather/Crypto + rweather/Crypto \ No newline at end of file diff --git a/arch/rp2xx0/rp2350.ini b/arch/rp2xx0/rp2350.ini index 58c5e5554..0ae184d00 100644 --- a/arch/rp2xx0/rp2350.ini +++ b/arch/rp2xx0/rp2350.ini @@ -2,7 +2,7 @@ [rp2350_base] platform = https://github.com/maxgerhardt/platform-raspberrypi.git#a606be683748c73e9a0d46baf70163478d298f0f ; For arduino-pico 4.2.0 extends = arduino_base -platform_packages = framework-arduinopico@https://github.com/earlephilhower/arduino-pico.git#4.2.1 +platform_packages = framework-arduinopico@https://github.com/earlephilhower/arduino-pico.git#96c3bfab9758f12c07aa20cc6d352e630c16987 ; 4.2.1 with fix for sporadic hangs board_build.core = earlephilhower board_build.filesystem_size = 0.5m @@ -22,4 +22,4 @@ lib_deps = ${arduino_base.lib_deps} ${environmental_base.lib_deps} ${radiolib_base.lib_deps} - rweather/Crypto + rweather/Crypto \ No newline at end of file From 364dead3aa4a1679dc9c80d599454aa739975557 Mon Sep 17 00:00:00 2001 From: GUVWAF <78759985+GUVWAF@users.noreply.github.com> Date: Wed, 20 Nov 2024 21:53:36 +0100 Subject: [PATCH 025/101] Update platform-raspberrypi also (#5407) * Update arduino-pico core to fix sporadic hangs * Update platform-raspberrypi also --- arch/rp2xx0/rp2040.ini | 2 +- arch/rp2xx0/rp2350.ini | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/rp2xx0/rp2040.ini b/arch/rp2xx0/rp2040.ini index 031a4848f..85efa583c 100644 --- a/arch/rp2xx0/rp2040.ini +++ b/arch/rp2xx0/rp2040.ini @@ -1,6 +1,6 @@ ; Common settings for rp2040 Processor based targets [rp2040_base] -platform = https://github.com/maxgerhardt/platform-raspberrypi.git#a606be683748c73e9a0d46baf70163478d298f0f ; For arduino-pico 4.2.0 +platform = https://github.com/maxgerhardt/platform-raspberrypi.git#19e30129fb1428b823be585c787dcb4ac0d9014c ; For arduino-pico 4.2.1 extends = arduino_base platform_packages = framework-arduinopico@https://github.com/earlephilhower/arduino-pico.git#996c3bfab9758f12c07aa20cc6d352e630c16987 ; 4.2.1 with fix for sporadic hangs diff --git a/arch/rp2xx0/rp2350.ini b/arch/rp2xx0/rp2350.ini index 0ae184d00..6daf59bdf 100644 --- a/arch/rp2xx0/rp2350.ini +++ b/arch/rp2xx0/rp2350.ini @@ -1,6 +1,6 @@ ; Common settings for rp2040 Processor based targets [rp2350_base] -platform = https://github.com/maxgerhardt/platform-raspberrypi.git#a606be683748c73e9a0d46baf70163478d298f0f ; For arduino-pico 4.2.0 +platform = https://github.com/maxgerhardt/platform-raspberrypi.git#19e30129fb1428b823be585c787dcb4ac0d9014c ; For arduino-pico 4.2.1 extends = arduino_base platform_packages = framework-arduinopico@https://github.com/earlephilhower/arduino-pico.git#96c3bfab9758f12c07aa20cc6d352e630c16987 ; 4.2.1 with fix for sporadic hangs From 1752caaf19ca9ab65b0df8a192af4c50c344a4c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Gjels=C3=B8?= <36234524+gjelsoe@users.noreply.github.com> Date: Thu, 21 Nov 2024 00:21:06 +0100 Subject: [PATCH 026/101] --web added to device-install(.sh/.bat) (#5405) * Add --web * Update device-install.bat Forgot a "-" a few places. --------- Co-authored-by: Ben Meadors --- bin/device-install.bat | 15 ++++++++++++--- bin/device-install.sh | 19 +++++++++++++++++-- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/bin/device-install.bat b/bin/device-install.bat index f8ca9e408..5e0f1c847 100755 --- a/bin/device-install.bat +++ b/bin/device-install.bat @@ -1,6 +1,7 @@ @ECHO OFF set PYTHON=python +set WEB_APP=0 :: Determine the correct esptool command to use where esptool >nul 2>&1 @@ -12,13 +13,14 @@ if %ERRORLEVEL% EQU 0 ( goto GETOPTS :HELP -echo Usage: %~nx0 [-h] [-p ESPTOOL_PORT] [-P PYTHON] [-f FILENAME^|FILENAME] +echo Usage: %~nx0 [-h] [-p ESPTOOL_PORT] [-P PYTHON] [-f FILENAME^|FILENAME] [--web] echo Flash image file to device, but first erasing and writing system information echo. echo -h Display this help and exit echo -p ESPTOOL_PORT Set the environment variable for ESPTOOL_PORT. If not set, ESPTOOL iterates all ports (Dangerrous). echo -P PYTHON Specify alternate python interpreter to use to invoke esptool. (Default: %PYTHON%) echo -f FILENAME The .bin file to flash. Custom to your device type and region. +echo --web Flash WEB APP. goto EOF :GETOPTS @@ -27,6 +29,7 @@ if /I "%1"=="--help" goto HELP if /I "%1"=="-F" set "FILENAME=%2" & SHIFT if /I "%1"=="-p" set ESPTOOL_PORT=%2 & SHIFT if /I "%1"=="-P" set PYTHON=%2 & SHIFT +if /I "%1"=="--web" set WEB_APP=1 & SHIFT SHIFT IF NOT "__%1__"=="____" goto GETOPTS @@ -49,8 +52,14 @@ IF EXIST %FILENAME% IF x%FILENAME:update=%==x%FILENAME% ( ) else ( %ESPTOOL_CMD% --baud 115200 write_flash 0x260000 bleota-s3.bin ) - for %%f in (littlefs-*.bin) do ( - %ESPTOOL_CMD% --baud 115200 write_flash 0x300000 %%f + IF %WEB_APP%==1 ( + for %%f in (littlefsweb-*.bin) do ( + %ESPTOOL_CMD% --baud 115200 write_flash 0x300000 %%f + ) + ) else ( + for %%f in (littlefs-*.bin) do ( + %ESPTOOL_CMD% --baud 115200 write_flash 0x300000 %%f + ) ) ) else ( echo "Invalid file: %FILENAME%" diff --git a/bin/device-install.sh b/bin/device-install.sh index b2a5684ee..9cdf635d7 100755 --- a/bin/device-install.sh +++ b/bin/device-install.sh @@ -1,6 +1,7 @@ #!/bin/sh PYTHON=${PYTHON:-$(which python3 python | head -n 1)} +WEB_APP=false # Determine the correct esptool command to use if "$PYTHON" -m esptool version >/dev/null 2>&1; then @@ -19,16 +20,26 @@ set -e # Usage info show_help() { cat < Date: Thu, 21 Nov 2024 19:14:35 +0800 Subject: [PATCH 027/101] add GPS in indicator board (#5411) --- variants/seeed-sensecap-indicator/variant.h | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/variants/seeed-sensecap-indicator/variant.h b/variants/seeed-sensecap-indicator/variant.h index d7ed329eb..ab305422f 100644 --- a/variants/seeed-sensecap-indicator/variant.h +++ b/variants/seeed-sensecap-indicator/variant.h @@ -36,12 +36,13 @@ #define TOUCH_I2C_PORT 0 #define TOUCH_SLAVE_ADDRESS 0x48 -// Buzzer -#define PIN_BUZZER 19 +// in future, we may want to add a buzzer and add all sensors to the indicator via a data protocol for now only GPS is supported +// // Buzzer +// #define PIN_BUZZER 19 -#define HAS_GPS 0 -#undef GPS_RX_PIN -#undef GPS_TX_PIN +#define GPS_RX_PIN 20 +#define GPS_TX_PIN 19 +#define HAS_GPS 1 #define USE_SX1262 #define USE_SX1268 From fd98e9f55310a93160464cd350c0637b9fee1df6 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Thu, 21 Nov 2024 06:13:30 -0600 Subject: [PATCH 028/101] Fixed NMEA sentence issue in CalTopo as well as bug with no printing all of the nodes (#5412) --- src/gps/NMEAWPL.cpp | 2 +- src/modules/SerialModule.cpp | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/gps/NMEAWPL.cpp b/src/gps/NMEAWPL.cpp index f528c4607..f4249ca62 100644 --- a/src/gps/NMEAWPL.cpp +++ b/src/gps/NMEAWPL.cpp @@ -23,7 +23,7 @@ uint32_t printWPL(char *buf, size_t bufsz, const meshtastic_PositionLite &pos, c { GeoCoord geoCoord(pos.latitude_i, pos.longitude_i, pos.altitude); char type = isCaltopoMode ? 'P' : 'N'; - uint32_t len = snprintf(buf, bufsz, "$G%cWPL,%02d%07.4f,%c,%03d%07.4f,%c,%s", type, geoCoord.getDMSLatDeg(), + uint32_t len = snprintf(buf, bufsz, "\r\n$G%cWPL,%02d%07.4f,%c,%03d%07.4f,%c,%s", type, geoCoord.getDMSLatDeg(), (abs(geoCoord.getLatitude()) - geoCoord.getDMSLatDeg() * 1e+7) * 6e-6, geoCoord.getDMSLatCP(), geoCoord.getDMSLonDeg(), (abs(geoCoord.getLongitude()) - geoCoord.getDMSLonDeg() * 1e+7) * 6e-6, geoCoord.getDMSLonCP(), name); diff --git a/src/modules/SerialModule.cpp b/src/modules/SerialModule.cpp index 32f9d9bc6..531be274e 100644 --- a/src/modules/SerialModule.cpp +++ b/src/modules/SerialModule.cpp @@ -204,9 +204,11 @@ int32_t SerialModule::runOnce() lastNmeaTime = millis(); uint32_t readIndex = 0; const meshtastic_NodeInfoLite *tempNodeInfo = nodeDB->readNextMeshNode(readIndex); - while (tempNodeInfo != NULL && tempNodeInfo->has_user && hasValidPosition(tempNodeInfo)) { - printWPL(outbuf, sizeof(outbuf), tempNodeInfo->position, tempNodeInfo->user.long_name, true); - serialPrint->printf("%s", outbuf); + while (tempNodeInfo != NULL) { + if (tempNodeInfo->has_user && hasValidPosition(tempNodeInfo)) { + printWPL(outbuf, sizeof(outbuf), tempNodeInfo->position, tempNodeInfo->user.long_name, true); + serialPrint->printf("%s", outbuf); + } tempNodeInfo = nodeDB->readNextMeshNode(readIndex); } } From 1089469f82f1f4ea39590c54f2b978844b938586 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Gjels=C3=B8?= <36234524+gjelsoe@users.noreply.github.com> Date: Thu, 21 Nov 2024 20:27:26 +0100 Subject: [PATCH 029/101] --web littlefswebui-* typo fix (#5416) * Add --web * Update device-install.bat Forgot a "-" a few places. * Typo fix. * Typo fix --------- Co-authored-by: Ben Meadors Co-authored-by: GUVWAF <78759985+GUVWAF@users.noreply.github.com> --- bin/device-install.bat | 2 +- bin/device-install.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/device-install.bat b/bin/device-install.bat index 5e0f1c847..c18be89a8 100755 --- a/bin/device-install.bat +++ b/bin/device-install.bat @@ -53,7 +53,7 @@ IF EXIST %FILENAME% IF x%FILENAME:update=%==x%FILENAME% ( %ESPTOOL_CMD% --baud 115200 write_flash 0x260000 bleota-s3.bin ) IF %WEB_APP%==1 ( - for %%f in (littlefsweb-*.bin) do ( + for %%f in (littlefswebui-*.bin) do ( %ESPTOOL_CMD% --baud 115200 write_flash 0x300000 %%f ) ) else ( diff --git a/bin/device-install.sh b/bin/device-install.sh index 9cdf635d7..e09c61ba6 100755 --- a/bin/device-install.sh +++ b/bin/device-install.sh @@ -85,7 +85,7 @@ if [ -f "${FILENAME}" ] && [ -n "${FILENAME##*"update"*}" ]; then $ESPTOOL_CMD write_flash 0x260000 bleota-s3.bin fi if [ "$WEB_APP" = true ]; then - $ESPTOOL_CMD write_flash 0x300000 littlefsweb-*.bin + $ESPTOOL_CMD write_flash 0x300000 littlefswebui-*.bin else $ESPTOOL_CMD write_flash 0x300000 littlefs-*.bin fi From dbc5ec27f77cae59d465c60100506ffd092a3060 Mon Sep 17 00:00:00 2001 From: GUVWAF <78759985+GUVWAF@users.noreply.github.com> Date: Thu, 21 Nov 2024 21:11:50 +0100 Subject: [PATCH 030/101] Temporarily disable MDNS when MQTT is enabled (#5418) Leads to a panic --- src/mesh/wifi/WiFiAPClient.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/mesh/wifi/WiFiAPClient.cpp b/src/mesh/wifi/WiFiAPClient.cpp index 911a47093..779576d64 100644 --- a/src/mesh/wifi/WiFiAPClient.cpp +++ b/src/mesh/wifi/WiFiAPClient.cpp @@ -62,7 +62,11 @@ static void onNetworkConnected() LOG_INFO("Start WiFi network services"); // start mdns - if (!MDNS.begin("Meshtastic")) { + if ( +#ifdef ARCH_RP2040 + !moduleConfig.mqtt.enabled && // MDNS is not supported when MQTT is enabled on ARCH_RP2040 +#endif + !MDNS.begin("Meshtastic")) { LOG_ERROR("Error setting up MDNS responder!"); } else { LOG_INFO("mDNS Host: Meshtastic.local"); From f5058a9cbb76ad1a784f571666e6302d95565775 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Thu, 21 Nov 2024 14:52:54 -0600 Subject: [PATCH 031/101] Check for OkToMqtt flag presence before uplinking to MQTT (#5413) * Check for oktomqtt flag presence before uplinking to MQTT * Move to mqtt->onSend --- src/mqtt/MQTT.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/mqtt/MQTT.cpp b/src/mqtt/MQTT.cpp index 0e2710940..3d5948976 100644 --- a/src/mqtt/MQTT.cpp +++ b/src/mqtt/MQTT.cpp @@ -545,9 +545,11 @@ void MQTT::onSend(const meshtastic_MeshPacket &mp_encrypted, const meshtastic_Me // mp_decoded will not be decoded when it's PKI encrypted and not directed to us if (mp_decoded.which_payload_variant == meshtastic_MeshPacket_decoded_tag) { + // For uplinking other's packets, check if it's not OK to MQTT or if it's an older packet without the bitfield + bool dontUplink = !mp_decoded.decoded.has_bitfield || + (mp_decoded.decoded.has_bitfield && !(mp_decoded.decoded.bitfield & BITFIELD_OK_TO_MQTT_MASK)); // check for the lowest bit of the data bitfield set false, and the use of one of the default keys. - if (!isFromUs(&mp_decoded) && !isMqttServerAddressPrivate && mp_decoded.decoded.has_bitfield && - !(mp_decoded.decoded.bitfield & BITFIELD_OK_TO_MQTT_MASK) && + if (!isFromUs(&mp_decoded) && !isMqttServerAddressPrivate && dontUplink && (ch.settings.psk.size < 2 || (ch.settings.psk.size == 16 && memcmp(ch.settings.psk.bytes, defaultpsk, 16)) || (ch.settings.psk.size == 32 && memcmp(ch.settings.psk.bytes, eventpsk, 32)))) { LOG_INFO("MQTT onSend - Not forwarding packet due to DontMqttMeBro flag"); From d5bb32ff93d319d7add76e4b9f44c70bdbb88c39 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Thu, 21 Nov 2024 15:11:19 -0600 Subject: [PATCH 032/101] Temetry can respond to want-response for LocalStats variant (#5414) --- src/modules/Telemetry/DeviceTelemetry.cpp | 16 +++++++++++----- src/modules/Telemetry/DeviceTelemetry.h | 2 ++ 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/modules/Telemetry/DeviceTelemetry.cpp b/src/modules/Telemetry/DeviceTelemetry.cpp index 1f479d6f1..4989b88e2 100644 --- a/src/modules/Telemetry/DeviceTelemetry.cpp +++ b/src/modules/Telemetry/DeviceTelemetry.cpp @@ -77,9 +77,10 @@ meshtastic_MeshPacket *DeviceTelemetryModule::allocReply() // Check for a request for device metrics if (decoded->which_variant == meshtastic_Telemetry_device_metrics_tag) { LOG_INFO("Device telemetry reply to request"); - - meshtastic_Telemetry telemetry = getDeviceTelemetry(); - return allocDataProtobuf(telemetry); + return allocDataProtobuf(getDeviceTelemetry()); + } else if (decoded->which_variant == meshtastic_Telemetry_local_stats_tag) { + LOG_INFO("Device telemetry reply w/ LocalStats to request"); + return allocDataProtobuf(getLocalStatsTelemetry()); } } return NULL; @@ -112,7 +113,7 @@ meshtastic_Telemetry DeviceTelemetryModule::getDeviceTelemetry() return t; } -void DeviceTelemetryModule::sendLocalStatsToPhone() +meshtastic_Telemetry DeviceTelemetryModule::getLocalStatsTelemetry() { meshtastic_Telemetry telemetry = meshtastic_Telemetry_init_zero; telemetry.which_variant = meshtastic_Telemetry_local_stats_tag; @@ -142,7 +143,12 @@ void DeviceTelemetryModule::sendLocalStatsToPhone() LOG_INFO("num_packets_tx=%i, num_packets_rx=%i, num_packets_rx_bad=%i", telemetry.variant.local_stats.num_packets_tx, telemetry.variant.local_stats.num_packets_rx, telemetry.variant.local_stats.num_packets_rx_bad); - meshtastic_MeshPacket *p = allocDataProtobuf(telemetry); + return telemetry; +} + +void DeviceTelemetryModule::sendLocalStatsToPhone() +{ + meshtastic_MeshPacket *p = allocDataProtobuf(getLocalStatsTelemetry()); p->to = NODENUM_BROADCAST; p->decoded.want_response = false; p->priority = meshtastic_MeshPacket_Priority_BACKGROUND; diff --git a/src/modules/Telemetry/DeviceTelemetry.h b/src/modules/Telemetry/DeviceTelemetry.h index 29818d4eb..19b7d5b01 100644 --- a/src/modules/Telemetry/DeviceTelemetry.h +++ b/src/modules/Telemetry/DeviceTelemetry.h @@ -42,6 +42,8 @@ class DeviceTelemetryModule : private concurrency::OSThread, public ProtobufModu private: meshtastic_Telemetry getDeviceTelemetry(); + meshtastic_Telemetry getLocalStatsTelemetry(); + void sendLocalStatsToPhone(); uint32_t sendToPhoneIntervalMs = SECONDS_IN_MINUTE * 1000; // Send to phone every minute uint32_t sendStatsToPhoneIntervalMs = 15 * SECONDS_IN_MINUTE * 1000; // Send stats to phone every 15 minutes From e6fb6b115aebb12b31fb93ed9d1508a6109b2f03 Mon Sep 17 00:00:00 2001 From: Jonathan Bennett Date: Fri, 22 Nov 2024 05:32:35 -0600 Subject: [PATCH 033/101] Seems like the last DIY board that's not "extra" (#5420) --- variants/diy/platformio.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/variants/diy/platformio.ini b/variants/diy/platformio.ini index 00ff88da2..83e2175c8 100644 --- a/variants/diy/platformio.ini +++ b/variants/diy/platformio.ini @@ -2,6 +2,7 @@ [env:meshtastic-diy-v1] extends = esp32_base board = esp32doit-devkit-v1 +board_level = extra board_check = true build_flags = ${esp32_base.build_flags} From fdec95f9c1aae9c14b575580cec460a3942f6387 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Fri, 22 Nov 2024 14:25:09 -0600 Subject: [PATCH 034/101] Cherry pick tdeck fixes (#5422) * Try-fix (workaround) T-Deck audio crash * set T-Deck audio to unused 48 (mem mclk) * swap mclk to gpio 21 * dreamcatcher: assign GPIO44 to audio mclk --------- Co-authored-by: mverch67 --- src/AudioThread.h | 2 +- variants/dreamcatcher/platformio.ini | 2 +- variants/dreamcatcher/variant.h | 1 + variants/t-deck/platformio.ini | 2 +- variants/t-deck/variant.h | 1 + variants/t-watch-s3/platformio.ini | 2 +- variants/t-watch-s3/variant.h | 1 + 7 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/AudioThread.h b/src/AudioThread.h index bb23e8598..6d560ec55 100644 --- a/src/AudioThread.h +++ b/src/AudioThread.h @@ -64,7 +64,7 @@ class AudioThread : public concurrency::OSThread void initOutput() { audioOut = new AudioOutputI2S(1, AudioOutputI2S::EXTERNAL_I2S); - audioOut->SetPinout(DAC_I2S_BCK, DAC_I2S_WS, DAC_I2S_DOUT); + audioOut->SetPinout(DAC_I2S_BCK, DAC_I2S_WS, DAC_I2S_DOUT, DAC_I2S_MCLK); audioOut->SetGain(0.2); }; diff --git a/variants/dreamcatcher/platformio.ini b/variants/dreamcatcher/platformio.ini index 46f9b9871..c57849d96 100644 --- a/variants/dreamcatcher/platformio.ini +++ b/variants/dreamcatcher/platformio.ini @@ -11,7 +11,7 @@ build_flags = -DARDUINO_USB_CDC_ON_BOOT=1 lib_deps = ${esp32s3_base.lib_deps} - earlephilhower/ESP8266Audio@^1.9.7 + earlephilhower/ESP8266Audio@^1.9.9 earlephilhower/ESP8266SAM@^1.0.1 [env:dreamcatcher-2206] diff --git a/variants/dreamcatcher/variant.h b/variants/dreamcatcher/variant.h index eb95a95dd..7835979e1 100644 --- a/variants/dreamcatcher/variant.h +++ b/variants/dreamcatcher/variant.h @@ -60,6 +60,7 @@ #define DAC_I2S_BCK 21 #define DAC_I2S_WS 9 #define DAC_I2S_DOUT 48 +#define DAC_I2S_MCLK 44 #define BIAS_T_ENABLE 7 // needs to be low #define BIAS_T_VALUE 0 diff --git a/variants/t-deck/platformio.ini b/variants/t-deck/platformio.ini index a63ff57a7..16769e2f2 100644 --- a/variants/t-deck/platformio.ini +++ b/variants/t-deck/platformio.ini @@ -15,5 +15,5 @@ build_flags = ${esp32_base.build_flags} lib_deps = ${esp32s3_base.lib_deps} lovyan03/LovyanGFX@^1.1.9 - earlephilhower/ESP8266Audio@^1.9.7 + earlephilhower/ESP8266Audio@^1.9.9 earlephilhower/ESP8266SAM@^1.0.1 \ No newline at end of file diff --git a/variants/t-deck/variant.h b/variants/t-deck/variant.h index 9860d608f..6d398391e 100644 --- a/variants/t-deck/variant.h +++ b/variants/t-deck/variant.h @@ -73,6 +73,7 @@ #define DAC_I2S_BCK 7 #define DAC_I2S_WS 5 #define DAC_I2S_DOUT 6 +#define DAC_I2S_MCLK 21 // GPIO lrck mic // LoRa #define USE_SX1262 diff --git a/variants/t-watch-s3/platformio.ini b/variants/t-watch-s3/platformio.ini index 1f5fc278b..26d1b8fb3 100644 --- a/variants/t-watch-s3/platformio.ini +++ b/variants/t-watch-s3/platformio.ini @@ -14,5 +14,5 @@ lib_deps = ${esp32s3_base.lib_deps} lovyan03/LovyanGFX@^1.1.9 lewisxhe/PCF8563_Library@1.0.1 adafruit/Adafruit DRV2605 Library@^1.2.2 - earlephilhower/ESP8266Audio@^1.9.7 + earlephilhower/ESP8266Audio@^1.9.9 earlephilhower/ESP8266SAM@^1.0.1 \ No newline at end of file diff --git a/variants/t-watch-s3/variant.h b/variants/t-watch-s3/variant.h index 9f939d859..45bd5f23c 100644 --- a/variants/t-watch-s3/variant.h +++ b/variants/t-watch-s3/variant.h @@ -34,6 +34,7 @@ #define DAC_I2S_BCK 48 #define DAC_I2S_WS 15 #define DAC_I2S_DOUT 46 +#define DAC_I2S_MCLK 0 #define HAS_AXP2101 From c51a7b98bd2ffeaa5b18db52bb18d4f1838749ec Mon Sep 17 00:00:00 2001 From: dylanli Date: Sat, 23 Nov 2024 08:54:06 +0800 Subject: [PATCH 035/101] add canned message and keyboard in indicator board (#5410) * add canned message and keyboard in indicator board * Added virtual keyboard macro and enabled for Indicator * Cleanup macros by applying USE_VIRTUAL_KEYBOARD and DISPLAY_CLOCK_FRAME --------- Co-authored-by: Ben Meadors --- src/graphics/Screen.cpp | 6 ++--- src/graphics/Screen.h | 2 +- src/graphics/images.h | 2 +- src/mesh/NodeDB.cpp | 4 +-- src/modules/CannedMessageModule.cpp | 28 ++++++++++----------- src/modules/CannedMessageModule.h | 4 +-- variants/rak_wismeshtap/variant.h | 2 +- variants/seeed-sensecap-indicator/variant.h | 3 +++ variants/t-watch-s3/variant.h | 3 +++ 9 files changed, 30 insertions(+), 24 deletions(-) diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index f18baf276..a875c11d6 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -396,7 +396,7 @@ static void drawBattery(OLEDDisplay *display, int16_t x, int16_t y, uint8_t *img display->drawFastImage(x, y, 16, 8, imgBuffer); } -#ifdef T_WATCH_S3 +#if defined(DISPLAY_CLOCK_FRAME) void Screen::drawWatchFaceToggleButton(OLEDDisplay *display, int16_t x, int16_t y, bool digitalMode, float scale) { @@ -2068,7 +2068,7 @@ void Screen::setFrames(FrameFocus focus) focus = FOCUS_FAULT; // Change our "focus" parameter, to ensure we show the fault frame } -#ifdef T_WATCH_S3 +#if defined(DISPLAY_CLOCK_FRAME) normalFrames[numframes++] = screen->digitalWatchFace ? &Screen::drawDigitalClockFrame : &Screen::drawAnalogClockFrame; #endif @@ -2699,7 +2699,7 @@ int Screen::handleUIFrameEvent(const UIFrameEvent *event) int Screen::handleInputEvent(const InputEvent *event) { -#ifdef T_WATCH_S3 +#if defined(DISPLAY_CLOCK_FRAME) // For the T-Watch, intercept touches to the 'toggle digital/analog watch face' button uint8_t watchFaceFrame = error_code ? 1 : 0; diff --git a/src/graphics/Screen.h b/src/graphics/Screen.h index ee8de69f0..2a77ca575 100644 --- a/src/graphics/Screen.h +++ b/src/graphics/Screen.h @@ -554,7 +554,7 @@ class Screen : public concurrency::OSThread static void drawDebugInfoWiFiTrampoline(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y); -#ifdef T_WATCH_S3 +#if defined(DISPLAY_CLOCK_FRAME) static void drawAnalogClockFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y); static void drawDigitalClockFrame(OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y); diff --git a/src/graphics/images.h b/src/graphics/images.h index fb6b176fc..b757dcf30 100644 --- a/src/graphics/images.h +++ b/src/graphics/images.h @@ -14,7 +14,7 @@ const uint8_t imgUser[] PROGMEM = {0x3C, 0x42, 0x99, 0xA5, 0xA5, 0x99, 0x42, 0x3 const uint8_t imgPositionEmpty[] PROGMEM = {0x20, 0x30, 0x28, 0x24, 0x42, 0xFF}; const uint8_t imgPositionSolid[] PROGMEM = {0x20, 0x30, 0x38, 0x3C, 0x7E, 0xFF}; -#ifdef T_WATCH_S3 +#if defined(DISPLAY_CLOCK_FRAME) const uint8_t bluetoothConnectedIcon[36] PROGMEM = {0xfe, 0x01, 0xff, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x00, 0xe3, 0x1f, 0xf3, 0x3f, 0x33, 0x30, 0x33, 0x33, 0x33, 0x33, 0x03, 0x33, 0xff, 0x33, 0xfe, 0x31, 0x00, 0x30, 0x30, 0x30, 0x30, 0x30, 0xf0, 0x3f, 0xe0, 0x1f}; diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index 841a50d65..bd89261a3 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -503,7 +503,7 @@ void NodeDB::installDefaultConfig(bool preserveKey = false) #ifdef RAK4630 config.display.wake_on_tap_or_motion = true; #endif -#ifdef T_WATCH_S3 +#if defined(T_WATCH_S3) || defined(SENSECAP_INDICATOR) config.display.screen_on_secs = 30; config.display.wake_on_tap_or_motion = true; #endif @@ -527,7 +527,7 @@ void NodeDB::initConfigIntervals() config.display.screen_on_secs = default_screen_on_secs; -#if defined(T_WATCH_S3) || defined(T_DECK) || defined(RAK14014) +#if defined(T_WATCH_S3) || defined(T_DECK) || defined(RAK14014) || defined(SENSECAP_INDICATOR) config.power.is_power_saving = true; config.display.screen_on_secs = 30; config.power.wait_bluetooth_secs = 30; diff --git a/src/modules/CannedMessageModule.cpp b/src/modules/CannedMessageModule.cpp index 6d1bfdc5c..a96fcc080 100644 --- a/src/modules/CannedMessageModule.cpp +++ b/src/modules/CannedMessageModule.cpp @@ -55,7 +55,7 @@ CannedMessageModule::CannedMessageModule() LOG_INFO("CannedMessageModule is enabled"); // T-Watch interface currently has no way to select destination type, so default to 'node' -#if defined(T_WATCH_S3) || defined(RAK14014) +#if defined(USE_VIRTUAL_KEYBOARD) this->destSelect = CANNED_MESSAGE_DESTINATION_TYPE_NODE; #endif @@ -81,7 +81,7 @@ int CannedMessageModule::splitConfiguredMessages() String canned_messages = cannedMessageModuleConfig.messages; -#if defined(T_WATCH_S3) || defined(RAK14014) +#if defined(USE_VIRTUAL_KEYBOARD) String separator = canned_messages.length() ? "|" : ""; canned_messages = "[---- Free Text ----]" + separator + canned_messages; @@ -150,7 +150,7 @@ int CannedMessageModule::handleInputEvent(const InputEvent *event) } if (event->inputEvent == static_cast(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_SELECT)) { -#if defined(T_WATCH_S3) || defined(RAK14014) +#if defined(USE_VIRTUAL_KEYBOARD) if (this->currentMessageIndex == 0) { this->runState = CANNED_MESSAGE_RUN_STATE_FREETEXT; @@ -177,7 +177,7 @@ int CannedMessageModule::handleInputEvent(const InputEvent *event) e.action = UIFrameEvent::Action::REGENERATE_FRAMESET; // We want to change the list of frames shown on-screen this->currentMessageIndex = -1; -#if !defined(T_WATCH_S3) && !defined(RAK14014) +#if !defined(T_WATCH_S3) && !defined(RAK14014) && !defined(USE_VIRTUAL_KEYBOARD) this->freetext = ""; // clear freetext this->cursor = 0; this->destSelect = CANNED_MESSAGE_DESTINATION_TYPE_NONE; @@ -190,7 +190,7 @@ int CannedMessageModule::handleInputEvent(const InputEvent *event) (event->inputEvent == static_cast(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT)) || (event->inputEvent == static_cast(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT))) { -#if defined(T_WATCH_S3) || defined(RAK14014) +#if defined(USE_VIRTUAL_KEYBOARD) if (event->inputEvent == static_cast(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT)) { this->payload = INPUT_BROKER_MSG_LEFT; } else if (event->inputEvent == static_cast(meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT)) { @@ -312,7 +312,7 @@ int CannedMessageModule::handleInputEvent(const InputEvent *event) } } -#if defined(T_WATCH_S3) || defined(RAK14014) +#if defined(USE_VIRTUAL_KEYBOARD) if (this->runState == CANNED_MESSAGE_RUN_STATE_FREETEXT) { String keyTapped = keyForCoordinates(event->touchX, event->touchY); @@ -446,7 +446,7 @@ int32_t CannedMessageModule::runOnce() this->freetext = ""; // clear freetext this->cursor = 0; -#if !defined(T_WATCH_S3) && !defined(RAK14014) +#if !defined(T_WATCH_S3) && !defined(RAK14014) && !defined(SENSECAP_INDICATOR) this->destSelect = CANNED_MESSAGE_DESTINATION_TYPE_NONE; #endif @@ -459,7 +459,7 @@ int32_t CannedMessageModule::runOnce() this->freetext = ""; // clear freetext this->cursor = 0; -#if !defined(T_WATCH_S3) && !defined(RAK14014) +#if !defined(T_WATCH_S3) && !defined(RAK14014) && !defined(USE_VIRTUAL_KEYBOARD) this->destSelect = CANNED_MESSAGE_DESTINATION_TYPE_NONE; #endif @@ -479,7 +479,7 @@ int32_t CannedMessageModule::runOnce() powerFSM.trigger(EVENT_PRESS); return INT32_MAX; } else { -#if defined(T_WATCH_S3) || defined(RAK14014) +#if defined(USE_VIRTUAL_KEYBOARD) sendText(this->dest, indexChannels[this->channel], this->messages[this->currentMessageIndex], true); #else sendText(NODENUM_BROADCAST, channels.getPrimaryIndex(), this->messages[this->currentMessageIndex], true); @@ -496,7 +496,7 @@ int32_t CannedMessageModule::runOnce() this->freetext = ""; // clear freetext this->cursor = 0; -#if !defined(T_WATCH_S3) && !defined(RAK14014) +#if !defined(T_WATCH_S3) && !defined(RAK14014) && !defined(USE_VIRTUAL_KEYBOARD) this->destSelect = CANNED_MESSAGE_DESTINATION_TYPE_NONE; #endif @@ -513,7 +513,7 @@ int32_t CannedMessageModule::runOnce() this->freetext = ""; // clear freetext this->cursor = 0; -#if !defined(T_WATCH_S3) && !defined(RAK14014) +#if !defined(T_WATCH_S3) && !defined(RAK14014) && !defined(USE_VIRTUAL_KEYBOARD) this->destSelect = CANNED_MESSAGE_DESTINATION_TYPE_NONE; #endif @@ -526,7 +526,7 @@ int32_t CannedMessageModule::runOnce() this->freetext = ""; // clear freetext this->cursor = 0; -#if !defined(T_WATCH_S3) && !defined(RAK14014) +#if !defined(T_WATCH_S3) && !defined(RAK14014) && !defined(USE_VIRTUAL_KEYBOARD) this->destSelect = CANNED_MESSAGE_DESTINATION_TYPE_NONE; #endif @@ -769,7 +769,7 @@ void CannedMessageModule::showTemporaryMessage(const String &message) setIntervalFromNow(2000); } -#if defined(T_WATCH_S3) || defined(RAK14014) +#if defined(USE_VIRTUAL_KEYBOARD) String CannedMessageModule::keyForCoordinates(uint x, uint y) { @@ -1055,7 +1055,7 @@ void CannedMessageModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *st display->drawString(10 + x, 0 + y + FONT_HEIGHT_SMALL, "Canned Message\nModule disabled."); } else if (cannedMessageModule->runState == CANNED_MESSAGE_RUN_STATE_FREETEXT) { requestFocus(); // Tell Screen::setFrames to move to our module's frame -#if defined(T_WATCH_S3) || defined(RAK14014) +#if defined(USE_VIRTUAL_KEYBOARD) drawKeyboard(display, state, 0, 0); #else diff --git a/src/modules/CannedMessageModule.h b/src/modules/CannedMessageModule.h index 4427be144..fd9ffc9b6 100644 --- a/src/modules/CannedMessageModule.h +++ b/src/modules/CannedMessageModule.h @@ -102,7 +102,7 @@ class CannedMessageModule : public SinglePortModule, public Observable Date: Sat, 23 Nov 2024 02:06:31 -0800 Subject: [PATCH 036/101] Update build-native.sh (#5415) * Update build-native.sh Device-install.sh and device-update.sh are not used on native platform, skip copying to release directory after build and copy native-install.sh and native-run.sh instead. * Update build-native.sh Skip native-run.sh copy --- bin/build-native.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/bin/build-native.sh b/bin/build-native.sh index e8ed61bcf..cda77b064 100755 --- a/bin/build-native.sh +++ b/bin/build-native.sh @@ -27,5 +27,4 @@ rm -r $OUTDIR/* || true platformio pkg update --environment native || platformioFailed pio run --environment native || platformioFailed cp .pio/build/native/program "$OUTDIR/meshtasticd_linux_$(uname -m)" -cp bin/device-install.* $OUTDIR -cp bin/device-update.* $OUTDIR +cp bin/native-install.* $OUTDIR From fadcbd597fb8d8c2981fdc148e785d717c13c39c Mon Sep 17 00:00:00 2001 From: Christopher Hoover Date: Sat, 23 Nov 2024 04:10:09 -0800 Subject: [PATCH 037/101] Cleans up visibility in GPS.h (#5426) Signed-off-by: Christopher Hoover --- release/latest/.gitignore | 1 - src/gps/GPS.h | 196 +++++++++++++++++--------------------- 2 files changed, 90 insertions(+), 107 deletions(-) delete mode 100644 release/latest/.gitignore diff --git a/release/latest/.gitignore b/release/latest/.gitignore deleted file mode 100644 index fff416667..000000000 --- a/release/latest/.gitignore +++ /dev/null @@ -1 +0,0 @@ -curfirmwareversion.xml diff --git a/src/gps/GPS.h b/src/gps/GPS.h index cd61c5444..cb970f7db 100644 --- a/src/gps/GPS.h +++ b/src/gps/GPS.h @@ -64,6 +64,95 @@ const char *getDOPString(uint32_t dop); */ class GPS : private concurrency::OSThread { + public: + meshtastic_Position p = meshtastic_Position_init_default; + + /** This is normally bound to config.position.gps_en_gpio but some rare boards (like heltec tracker) need more advanced + * implementations. Those boards will set this public variable to a custom implementation. + * + * Normally set by GPS::createGPS() + */ + GpioVirtPin *enablePin = NULL; + + virtual ~GPS(); + + /** We will notify this observable anytime GPS state has changed meaningfully */ + Observable newStatus; + + /** + * Returns true if we succeeded + */ + virtual bool setup(); + + // re-enable the thread + void enable(); + + // Disable the thread + int32_t disable() override; + + // toggle between enabled/disabled + void toggleGpsMode(); + + // Change the power state of the GPS - for power saving / shutdown + void setPowerState(GPSPowerState newState, uint32_t sleepMs = 0); + + /// Returns true if we have acquired GPS lock. + virtual bool hasLock(); + + /// Returns true if there's valid data flow with the chip. + virtual bool hasFlow(); + + /// Return true if we are connected to a GPS + bool isConnected() const { return hasGPS; } + + bool isPowerSaving() const { return config.position.gps_mode != meshtastic_Config_PositionConfig_GpsMode_ENABLED; } + + // Empty the input buffer as quickly as possible + void clearBuffer(); + + virtual bool factoryReset(); + + // Creates an instance of the GPS class. + // Returns the new instance or null if the GPS is not present. + static GPS *createGps(); + + // Wake the GPS hardware - ready for an update + void up(); + + // Let the GPS hardware save power between updates + void down(); + + protected: + /// Record that we have a GPS + void setConnected(); + + /** Subclasses should look for serial rx characters here and feed it to their GPS parser + * + * Return true if we received a valid message from the GPS + */ + virtual bool whileActive(); + + /** + * Perform any processing that should be done only while the GPS is awake and looking for a fix. + * Override this method to check for new locations + * + * @return true if we've acquired a time + */ + virtual bool lookForTime(); + + /** + * Perform any processing that should be done only while the GPS is awake and looking for a fix. + * Override this method to check for new locations + * + * @return true if we've acquired a new location + */ + virtual bool lookForLocation(); + + GnssModel_t gnssModel = GNSS_MODEL_UNKNOWN; + + private: + GPS() : concurrency::OSThread("GPS") {} + TinyGPSPlus reader; uint8_t fixQual = 0; // fix quality from GPGGA uint32_t lastChecksumFailCount = 0; @@ -75,7 +164,6 @@ class GPS : private concurrency::OSThread TinyGPSCustom gsapdop; // custom extract PDOP from GPGSA uint8_t fixType = 0; // fix type from GPGSA #endif - private: #if GPS_BAUDRATE_FIXED // if GPS_BAUDRATE is specified in variant, only try that. const int serialSpeeds[1] = {GPS_BAUDRATE}; @@ -113,7 +201,6 @@ class GPS : private concurrency::OSThread CallbackObserver notifyDeepSleepObserver = CallbackObserver(this, &GPS::prepareDeepSleep); - public: /** If !NULL we will use this serial port to construct our GPS */ #if defined(ARCH_RP2040) static SerialUART *_serial_gps; @@ -167,53 +254,6 @@ class GPS : private concurrency::OSThread const char *ACK_SUCCESS_MESSAGE = "Get ack success!"; - meshtastic_Position p = meshtastic_Position_init_default; - - /** This is normally bound to config.position.gps_en_gpio but some rare boards (like heltec tracker) need more advanced - * implementations. Those boards will set this public variable to a custom implementation. - * - * Normally set by GPS::createGPS() - */ - GpioVirtPin *enablePin = NULL; - - GPS() : concurrency::OSThread("GPS") {} - - virtual ~GPS(); - - /** We will notify this observable anytime GPS state has changed meaningfully */ - Observable newStatus; - - /** - * Returns true if we succeeded - */ - virtual bool setup(); - - // re-enable the thread - void enable(); - - // Disable the thread - int32_t disable() override; - - // toggle between enabled/disabled - void toggleGpsMode(); - - // Change the power state of the GPS - for power saving / shutdown - void setPowerState(GPSPowerState newState, uint32_t sleepMs = 0); - - /// Returns true if we have acquired GPS lock. - virtual bool hasLock(); - - /// Returns true if there's valid data flow with the chip. - virtual bool hasFlow(); - - /// Return true if we are connected to a GPS - bool isConnected() const { return hasGPS; } - - bool isPowerSaving() const { return config.position.gps_mode != meshtastic_Config_PositionConfig_GpsMode_ENABLED; } - - // Empty the input buffer as quickly as possible - void clearBuffer(); - // Create a ublox packet for editing in memory uint8_t makeUBXPacket(uint8_t class_id, uint8_t msg_id, uint8_t payload_size, const uint8_t *msg); uint8_t makeCASPacket(uint8_t class_id, uint8_t msg_id, uint8_t payload_size, const uint8_t *msg); @@ -229,59 +269,6 @@ class GPS : private concurrency::OSThread GPS_RESPONSE getACKCas(uint8_t class_id, uint8_t msg_id, uint32_t waitMillis); - virtual bool factoryReset(); - - // Creates an instance of the GPS class. - // Returns the new instance or null if the GPS is not present. - static GPS *createGps(); - - // Wake the GPS hardware - ready for an update - void up(); - - // Let the GPS hardware save power between updates - void down(); - - protected: - /** - * Perform any processing that should be done only while the GPS is awake and looking for a fix. - * Override this method to check for new locations - * - * @return true if we've acquired a time - */ - - /** - * Perform any processing that should be done only while the GPS is awake and looking for a fix. - * Override this method to check for new locations - * - * @return true if we've acquired a new location - */ - - /// Record that we have a GPS - void setConnected(); - - /** Subclasses should look for serial rx characters here and feed it to their GPS parser - * - * Return true if we received a valid message from the GPS - */ - virtual bool whileActive(); - - /** - * Perform any processing that should be done only while the GPS is awake and looking for a fix. - * Override this method to check for new locations - * - * @return true if we've acquired a time - */ - virtual bool lookForTime(); - - /** - * Perform any processing that should be done only while the GPS is awake and looking for a fix. - * Override this method to check for new locations - * - * @return true if we've acquired a new location - */ - virtual bool lookForLocation(); - - private: /// Prepare the GPS for the cpu entering deep sleep, expect to be gone for at least 100s of msecs /// always returns 0 to indicate okay to sleep int prepareDeepSleep(void *unused); @@ -320,10 +307,7 @@ class GPS : private concurrency::OSThread uint8_t fixeddelayCtr = 0; const char *powerStateToString(); - - protected: - GnssModel_t gnssModel = GNSS_MODEL_UNKNOWN; }; extern GPS *gps; -#endif // Exclude GPS \ No newline at end of file +#endif // Exclude GPS From dd7140b7a154f50431d9a037571d7319fdc3b87f Mon Sep 17 00:00:00 2001 From: Mictronics Date: Sat, 23 Nov 2024 16:08:18 +0100 Subject: [PATCH 038/101] Fix admin key loading from userPrefs.h (#5417) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix LED pinout for T-Echo board marked v1.0, date 2021-6-28 * Merge PR #420 * Fixed double and missing Default class. * Use correct format specifier and fixed typo. * Removed duplicate code. * Fix error: #if with no expression * Fix warning: extra tokens at end of #endif directive. * Fix antenna switching logic. Complementary-pin control logic is required on the rp2040-lora board. * Fix deprecated macros. * Set RP2040 in dormant mode when deep sleep is triggered. * Fix array out of bounds read. * Admin key count needs to be set otherwise the key will be zero loaded after reset. * Don't reset the admin key size when loading defaults. Preserve an existing key in config if possible. * Remove log spam when reading INA voltage sensor. * Remove static declaration for admin keys from userPrefs.h. Load hard coded admin keys in case config file has empty slots. * Removed newlines from log. --------- Co-authored-by: Ben Meadors Co-authored-by: Thomas Göttgens --- src/mesh/NodeDB.cpp | 103 +++++++++++++++++++++++++++++++++++--------- userPrefs.h | 15 ++++--- 2 files changed, 91 insertions(+), 27 deletions(-) diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index bd89261a3..44a28eea2 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -61,6 +61,16 @@ meshtastic_LocalConfig config; meshtastic_LocalModuleConfig moduleConfig; meshtastic_ChannelFile channelFile; +#ifdef USERPREFS_USE_ADMIN_KEY_0 +static unsigned char userprefs_admin_key_0[] = USERPREFS_USE_ADMIN_KEY_0; +#endif +#ifdef USERPREFS_USE_ADMIN_KEY_1 +static unsigned char userprefs_admin_key_1[] = USERPREFS_USE_ADMIN_KEY_1; +#endif +#ifdef USERPREFS_USE_ADMIN_KEY_2 +static unsigned char userprefs_admin_key_2[] = USERPREFS_USE_ADMIN_KEY_2; +#endif + bool meshtastic_DeviceState_callback(pb_istream_t *istream, pb_ostream_t *ostream, const pb_field_iter_t *field) { if (ostream) { @@ -406,32 +416,37 @@ void NodeDB::installDefaultConfig(bool preserveKey = false) #else config.lora.ignore_mqtt = false; #endif -#ifdef USERPREFS_USE_ADMIN_KEY // Initialize admin_key_count to zero byte numAdminKeys = 0; +#ifdef USERPREFS_USE_ADMIN_KEY_0 // Check if USERPREFS_ADMIN_KEY_0 is non-empty - if (sizeof(USERPREFS_ADMIN_KEY_0) > 0) { - memcpy(config.security.admin_key[numAdminKeys].bytes, USERPREFS_ADMIN_KEY_0, 32); - config.security.admin_key[numAdminKeys].size = 32; + if (sizeof(userprefs_admin_key_0) > 0) { + memcpy(config.security.admin_key[0].bytes, userprefs_admin_key_0, 32); + config.security.admin_key[0].size = 32; numAdminKeys++; } - - // Check if USERPREFS_ADMIN_KEY_1 is non-empty - if (sizeof(USERPREFS_ADMIN_KEY_1) > 0) { - memcpy(config.security.admin_key[numAdminKeys].bytes, USERPREFS_ADMIN_KEY_1, 32); - config.security.admin_key[numAdminKeys].size = 32; - numAdminKeys++; - } - - // Check if USERPREFS_ADMIN_KEY_2 is non-empty - if (sizeof(USERPREFS_ADMIN_KEY_2) > 0) { - memcpy(config.security.admin_key[config.security.admin_key_count].bytes, USERPREFS_ADMIN_KEY_2, 32); - config.security.admin_key[config.security.admin_key_count].size = 32; - numAdminKeys++; - } - config.security.admin_key_count = numAdminKeys; #endif + +#ifdef USERPREFS_USE_ADMIN_KEY_1 + // Check if USERPREFS_ADMIN_KEY_1 is non-empty + if (sizeof(userprefs_admin_key_1) > 0) { + memcpy(config.security.admin_key[1].bytes, userprefs_admin_key_1, 32); + config.security.admin_key[1].size = 32; + numAdminKeys++; + } +#endif + +#ifdef USERPREFS_USE_ADMIN_KEY_2 + // Check if USERPREFS_ADMIN_KEY_2 is non-empty + if (sizeof(userprefs_admin_key_2) > 0) { + memcpy(config.security.admin_key[2].bytes, userprefs_admin_key_2, 32); + config.security.admin_key[2].size = 32; + numAdminKeys++; + } +#endif + config.security.admin_key_count = numAdminKeys; + if (shouldPreserveKey) { config.security.private_key.size = 32; memcpy(config.security.private_key.bytes, private_key_temp, config.security.private_key.size); @@ -888,6 +903,54 @@ void NodeDB::loadFromDisk() } } + // Make sure we load hard coded admin keys even when the configuration file has none. + // Initialize admin_key_count to zero + byte numAdminKeys = 0; + uint16_t sum = 0; +#ifdef USERPREFS_USE_ADMIN_KEY_0 + for (uint8_t b = 0; b < 32; b++) { + sum += config.security.admin_key[0].bytes[b]; + } + if (sum == 0) { + numAdminKeys += 1; + LOG_INFO("Admin 0 key zero. Loading hard coded key from user preferences."); + memcpy(config.security.admin_key[0].bytes, userprefs_admin_key_0, 32); + config.security.admin_key[0].size = 32; + config.security.admin_key_count = numAdminKeys; + saveToDisk(SEGMENT_CONFIG); + } +#endif + +#ifdef USERPREFS_USE_ADMIN_KEY_1 + sum = 0; + for (uint8_t b = 0; b < 32; b++) { + sum += config.security.admin_key[1].bytes[b]; + } + if (sum == 0) { + numAdminKeys += 1; + LOG_INFO("Admin 1 key zero. Loading hard coded key from user preferences."); + memcpy(config.security.admin_key[1].bytes, userprefs_admin_key_1, 32); + config.security.admin_key[1].size = 32; + config.security.admin_key_count = numAdminKeys; + saveToDisk(SEGMENT_CONFIG); + } +#endif + +#ifdef USERPREFS_USE_ADMIN_KEY_2 + sum = 0; + for (uint8_t b = 0; b < 32; b++) { + sum += config.security.admin_key[2].bytes[b]; + } + if (sum == 0) { + numAdminKeys += 1; + LOG_INFO("Admin 2 key zero. Loading hard coded key from user preferences."); + memcpy(config.security.admin_key[2].bytes, userprefs_admin_key_2, 32); + config.security.admin_key[2].size = 32; + config.security.admin_key_count = numAdminKeys; + saveToDisk(SEGMENT_CONFIG); + } +#endif + state = loadProto(moduleConfigFileName, meshtastic_LocalModuleConfig_size, sizeof(meshtastic_LocalModuleConfig), &meshtastic_LocalModuleConfig_msg, &moduleConfig); if (state != LoadFileResult::LOAD_SUCCESS) { @@ -1346,4 +1409,4 @@ void recordCriticalError(meshtastic_CriticalErrorCode code, uint32_t address, co LOG_ERROR("A critical failure occurred, portduino is exiting"); exit(2); #endif -} +} \ No newline at end of file diff --git a/userPrefs.h b/userPrefs.h index 622a491c3..00f04149a 100644 --- a/userPrefs.h +++ b/userPrefs.h @@ -72,16 +72,17 @@ static unsigned char icon_bits[] = { /* * PKI Admin keys. * If a Admin key is set with '{};' - * then it will be ignored, a PKI key must have a size of 32. + * then it will be ignored, a PKI key must have a size of 32 byte. */ /* -#define USERPREFS_USE_ADMIN_KEY 1 -static unsigned char USERPREFS_ADMIN_KEY_0[] = {0xcd, 0xc0, 0xb4, 0x3c, 0x53, 0x24, 0xdf, 0x13, 0xca, 0x5a, 0xa6, - 0x0c, 0x0d, 0xec, 0x85, 0x5a, 0x4c, 0xf6, 0x1a, 0x96, 0x04, 0x1a, - 0x3e, 0xfc, 0xbb, 0x8e, 0x33, 0x71, 0xe5, 0xfc, 0xff, 0x3c}; -static unsigned char USERPREFS_ADMIN_KEY_1[] = {}; -static unsigned char USERPREFS_ADMIN_KEY_2[] = {}; +#define USERPREFS_USE_ADMIN_KEY_0 \ + { \ + 0xcd, 0xc0, 0xb4, 0x3c, 0x53, 0x24, 0xdf, 0x13, 0xca, 0x5a, 0xa6, 0x0c, 0x0d, 0xec, 0x85, 0x5a, 0x4c, 0xf6, 0x1a, 0x96, \ + 0x04, 0x1a, 0x3e, 0xfc, 0xbb, 0x8e, 0x33, 0x71, 0xe5, 0xfc, 0xff, 0x3c \ + }; */ +// #define USERPREFS_USE_ADMIN_KEY_1 {}; +// #define USERPREFS_USE_ADMIN_KEY_2 {}; /* * USERPREF_FIXED_GPS_LAT and USERPREF_FIXED_GPS_LON must be set, USERPREF_FIXED_GPS_ALT is optional From fcfb1975719fb4a4eb47077d6aee7ed6796e6357 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Sat, 23 Nov 2024 16:56:40 +0100 Subject: [PATCH 039/101] try to detect dfrobot station to tell it apart from an ublox gps. (#5393) --- src/detect/ScanI2CTwoWire.cpp | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/detect/ScanI2CTwoWire.cpp b/src/detect/ScanI2CTwoWire.cpp index ef5e5ee00..378dcfc17 100644 --- a/src/detect/ScanI2CTwoWire.cpp +++ b/src/detect/ScanI2CTwoWire.cpp @@ -314,13 +314,27 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize) break; case INA3221_ADDR: registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0xFE), 2); - LOG_DEBUG("Register MFG_UID: 0x%x", registerValue); + LOG_DEBUG("Register MFG_UID FE: 0x%x", registerValue); if (registerValue == 0x5449) { LOG_INFO("INA3221 sensor found at address 0x%x", (uint8_t)addr.address); type = INA3221; } else { - LOG_INFO("DFRobot Lark weather station found at address 0x%x", (uint8_t)addr.address); - type = DFROBOT_LARK; + /* check the first 2 bytes of the 6 byte response register + LARK FW 1.0 should return: + RESPONSE_STATUS STATUS_SUCCESS (0x53) + RESPONSE_CMD CMD_GET_VERSION (0x05) + RESPONSE_LEN_L 0x02 + RESPONSE_LEN_H 0x00 + RESPONSE_PAYLOAD 0x01 + RESPONSE_PAYLOAD+1 0x00 + */ + registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x05), 2); + LOG_DEBUG("Register MFG_UID 05: 0x%x", registerValue); + if (registerValue == 0x5305) { + LOG_INFO("DFRobot Lark weather station found at address 0x%x", (uint8_t)addr.address); + type = DFROBOT_LARK; + } + // else: probably a RAK12500/UBLOX GPS on I2C } break; case MCP9808_ADDR: From f2ee0df01578f3eaf47f1a212a04297727be69f6 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Sat, 23 Nov 2024 17:18:22 -0600 Subject: [PATCH 040/101] Remove BMA-423 and STK8X by default (#5429) * Remove BMA-423 by default * STK * Wrong macro * Helps if you include the file --- platformio.ini | 6 +----- src/detect/ScanI2CTwoWire.cpp | 2 ++ src/motion/AccelerometerThread.h | 8 ++++++++ src/motion/BMA423Sensor.cpp | 2 +- src/motion/BMA423Sensor.h | 2 +- src/motion/STK8XXXSensor.cpp | 2 +- src/motion/STK8XXXSensor.h | 2 +- variants/radiomaster_900_bandit/platformio.ini | 4 +++- variants/t-watch-s3/platformio.ini | 4 +++- 9 files changed, 21 insertions(+), 11 deletions(-) diff --git a/platformio.ini b/platformio.ini index f7c73c190..982848f41 100644 --- a/platformio.ini +++ b/platformio.ini @@ -154,15 +154,11 @@ lib_deps = sparkfun/SparkFun 9DoF IMU Breakout - ICM 20948 - Arduino Library@1.2.13 ClosedCube OPT3001@1.1.2 emotibit/EmotiBit MLX90632@1.0.8 - dfrobot/DFRobot_RTU@1.0.3 sparkfun/SparkFun MAX3010x Pulse and Proximity Sensor Library@1.1.2 adafruit/Adafruit MLX90614 Library@2.1.5 - https://github.com/boschsensortec/Bosch-BSEC2-Library#v1.7.2502 boschsensortec/BME68x Sensor Library@1.1.40407 https://github.com/KodinLanewave/INA3221@1.0.1 - lewisxhe/SensorLib@0.2.0 mprograms/QMC5883LCompass@1.2.3 - + dfrobot/DFRobot_RTU@1.0.3 https://github.com/meshtastic/DFRobot_LarkWeatherStation#4de3a9cadef0f6a5220a8a906cf9775b02b0040d - https://github.com/gjelsoe/STK8xxx-Accelerometer.git#v0.1.1 diff --git a/src/detect/ScanI2CTwoWire.cpp b/src/detect/ScanI2CTwoWire.cpp index 378dcfc17..2413c44c9 100644 --- a/src/detect/ScanI2CTwoWire.cpp +++ b/src/detect/ScanI2CTwoWire.cpp @@ -341,6 +341,7 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize) // We need to check for STK8BAXX first, since register 0x07 is new data flag for the z-axis and can produce some // weird result. and register 0x00 doesn't seems to be colliding with MCP9808 and LIS3DH chips. { +#ifdef HAS_STK8XXX // Check register 0x00 for 0x8700 response to ID STK8BA53 chip. registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x00), 2); if (registerValue == 0x8700) { @@ -348,6 +349,7 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize) LOG_INFO("STK8BAXX accelerometer found"); break; } +#endif // Check register 0x07 for 0x0400 response to ID MCP9808 chip. registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x07), 2); diff --git a/src/motion/AccelerometerThread.h b/src/motion/AccelerometerThread.h index 8d1260195..95f09910f 100755 --- a/src/motion/AccelerometerThread.h +++ b/src/motion/AccelerometerThread.h @@ -7,7 +7,9 @@ #if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) && !MESHTASTIC_EXCLUDE_I2C #include "../concurrency/OSThread.h" +#ifdef HAS_BMA423 #include "BMA423Sensor.h" +#endif #include "BMX160Sensor.h" #include "ICM20948Sensor.h" #include "LIS3DHSensor.h" @@ -17,7 +19,9 @@ #ifdef HAS_QMA6100P #include "QMA6100PSensor.h" #endif +#ifdef HAS_STK8XXX #include "STK8XXXSensor.h" +#endif extern ScanI2C::DeviceAddress accelerometer_found; @@ -79,9 +83,11 @@ class AccelerometerThread : public concurrency::OSThread #endif switch (device.type) { +#ifdef HAS_BMA423 case ScanI2C::DeviceType::BMA423: sensor = new BMA423Sensor(device); break; +#endif case ScanI2C::DeviceType::MPU6050: sensor = new MPU6050Sensor(device); break; @@ -94,9 +100,11 @@ class AccelerometerThread : public concurrency::OSThread case ScanI2C::DeviceType::LSM6DS3: sensor = new LSM6DS3Sensor(device); break; +#ifdef HAS_STK8XXX case ScanI2C::DeviceType::STK8BAXX: sensor = new STK8XXXSensor(device); break; +#endif case ScanI2C::DeviceType::ICM20948: sensor = new ICM20948Sensor(device); break; diff --git a/src/motion/BMA423Sensor.cpp b/src/motion/BMA423Sensor.cpp index 382b595e1..d7058bab0 100755 --- a/src/motion/BMA423Sensor.cpp +++ b/src/motion/BMA423Sensor.cpp @@ -1,6 +1,6 @@ #include "BMA423Sensor.h" -#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) && !MESHTASTIC_EXCLUDE_I2C +#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) && !MESHTASTIC_EXCLUDE_I2C && defined(HAS_BMA423) using namespace MotionSensorI2C; diff --git a/src/motion/BMA423Sensor.h b/src/motion/BMA423Sensor.h index 0bc0ddf8c..455315aa9 100755 --- a/src/motion/BMA423Sensor.h +++ b/src/motion/BMA423Sensor.h @@ -4,7 +4,7 @@ #include "MotionSensor.h" -#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) && !MESHTASTIC_EXCLUDE_I2C +#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) && !MESHTASTIC_EXCLUDE_I2C && defined(HAS_BMA423) #include #include diff --git a/src/motion/STK8XXXSensor.cpp b/src/motion/STK8XXXSensor.cpp index 8e9b1a63e..377ee3c37 100755 --- a/src/motion/STK8XXXSensor.cpp +++ b/src/motion/STK8XXXSensor.cpp @@ -1,6 +1,6 @@ #include "STK8XXXSensor.h" -#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) && !MESHTASTIC_EXCLUDE_I2C +#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) && !MESHTASTIC_EXCLUDE_I2C && defined(HAS_STK8XXX) STK8XXXSensor::STK8XXXSensor(ScanI2C::FoundDevice foundDevice) : MotionSensor::MotionSensor(foundDevice) {} diff --git a/src/motion/STK8XXXSensor.h b/src/motion/STK8XXXSensor.h index 190b916b4..cff98d87d 100755 --- a/src/motion/STK8XXXSensor.h +++ b/src/motion/STK8XXXSensor.h @@ -4,7 +4,7 @@ #include "MotionSensor.h" -#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) && !MESHTASTIC_EXCLUDE_I2C +#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) && !MESHTASTIC_EXCLUDE_I2C && defined(HAS_STK8XXX) #ifdef STK8XXX_INT diff --git a/variants/radiomaster_900_bandit/platformio.ini b/variants/radiomaster_900_bandit/platformio.ini index 4ff8a6ea2..010791d8a 100644 --- a/variants/radiomaster_900_bandit/platformio.ini +++ b/variants/radiomaster_900_bandit/platformio.ini @@ -6,9 +6,11 @@ build_flags = -DRADIOMASTER_900_BANDIT -DVTABLES_IN_FLASH=1 -DCONFIG_DISABLE_HAL_LOCKS=1 + -DHAS_STK8XXX=1 -O2 -Ivariants/radiomaster_900_bandit board_build.f_cpu = 240000000L upload_protocol = esptool lib_deps = - ${esp32_base.lib_deps} \ No newline at end of file + ${esp32_base.lib_deps} + https://github.com/gjelsoe/STK8xxx-Accelerometer.git#v0.1.1 diff --git a/variants/t-watch-s3/platformio.ini b/variants/t-watch-s3/platformio.ini index 26d1b8fb3..005c4d021 100644 --- a/variants/t-watch-s3/platformio.ini +++ b/variants/t-watch-s3/platformio.ini @@ -9,10 +9,12 @@ build_flags = ${esp32_base.build_flags} -DT_WATCH_S3 -Ivariants/t-watch-s3 -DPCF8563_RTC=0x51 + -DHAS_BMA423=1 lib_deps = ${esp32s3_base.lib_deps} lovyan03/LovyanGFX@^1.1.9 lewisxhe/PCF8563_Library@1.0.1 adafruit/Adafruit DRV2605 Library@^1.2.2 earlephilhower/ESP8266Audio@^1.9.9 - earlephilhower/ESP8266SAM@^1.0.1 \ No newline at end of file + earlephilhower/ESP8266SAM@^1.0.1 + lewisxhe/SensorLib@0.2.0 From 4d69159e75c465455e471a751375583e1e7dc27f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sun, 24 Nov 2024 12:29:17 +0100 Subject: [PATCH 041/101] [create-pull-request] automated change (#5431) Co-authored-by: caveman99 <25002+caveman99@users.noreply.github.com> --- protobufs | 2 +- src/mesh/generated/meshtastic/telemetry.pb.h | 23 +++++++++++++------- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/protobufs b/protobufs index af7521c3a..c952f8a4c 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit af7521c3a77d56eb7a64efae5637a311ac33f76d +Subproject commit c952f8a4c1c30f724743ee322dd3ec3ec2f934c4 diff --git a/src/mesh/generated/meshtastic/telemetry.pb.h b/src/mesh/generated/meshtastic/telemetry.pb.h index 309c01dc7..874eef60f 100644 --- a/src/mesh/generated/meshtastic/telemetry.pb.h +++ b/src/mesh/generated/meshtastic/telemetry.pb.h @@ -77,7 +77,9 @@ typedef enum _meshtastic_TelemetrySensorType { /* MLX90614 non-contact IR temperature sensor */ meshtastic_TelemetrySensorType_MLX90614 = 31, /* SCD40/SCD41 CO2, humidity, temperature sensor */ - meshtastic_TelemetrySensorType_SCD4X = 32 + meshtastic_TelemetrySensorType_SCD4X = 32, + /* ClimateGuard RadSens, radiation, Geiger-Muller Tube */ + meshtastic_TelemetrySensorType_RADSENS = 33 } meshtastic_TelemetrySensorType; /* Struct definitions */ @@ -155,6 +157,9 @@ typedef struct _meshtastic_EnvironmentMetrics { /* Wind lull in m/s */ bool has_wind_lull; float wind_lull; + /* Radiation in µR/h */ + bool has_radiation; + float radiation; } meshtastic_EnvironmentMetrics; /* Power Metrics (voltage / current / etc) */ @@ -299,8 +304,8 @@ extern "C" { /* Helper constants for enums */ #define _meshtastic_TelemetrySensorType_MIN meshtastic_TelemetrySensorType_SENSOR_UNSET -#define _meshtastic_TelemetrySensorType_MAX meshtastic_TelemetrySensorType_SCD4X -#define _meshtastic_TelemetrySensorType_ARRAYSIZE ((meshtastic_TelemetrySensorType)(meshtastic_TelemetrySensorType_SCD4X+1)) +#define _meshtastic_TelemetrySensorType_MAX meshtastic_TelemetrySensorType_RADSENS +#define _meshtastic_TelemetrySensorType_ARRAYSIZE ((meshtastic_TelemetrySensorType)(meshtastic_TelemetrySensorType_RADSENS+1)) @@ -313,7 +318,7 @@ extern "C" { /* Initializer values for message structs */ #define meshtastic_DeviceMetrics_init_default {false, 0, false, 0, false, 0, false, 0, false, 0} -#define meshtastic_EnvironmentMetrics_init_default {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0} +#define meshtastic_EnvironmentMetrics_init_default {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0} #define meshtastic_PowerMetrics_init_default {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0} #define meshtastic_AirQualityMetrics_init_default {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0} #define meshtastic_LocalStats_init_default {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} @@ -321,7 +326,7 @@ extern "C" { #define meshtastic_Telemetry_init_default {0, 0, {meshtastic_DeviceMetrics_init_default}} #define meshtastic_Nau7802Config_init_default {0, 0} #define meshtastic_DeviceMetrics_init_zero {false, 0, false, 0, false, 0, false, 0, false, 0} -#define meshtastic_EnvironmentMetrics_init_zero {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0} +#define meshtastic_EnvironmentMetrics_init_zero {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0} #define meshtastic_PowerMetrics_init_zero {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0} #define meshtastic_AirQualityMetrics_init_zero {false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0, false, 0} #define meshtastic_LocalStats_init_zero {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} @@ -352,6 +357,7 @@ extern "C" { #define meshtastic_EnvironmentMetrics_weight_tag 15 #define meshtastic_EnvironmentMetrics_wind_gust_tag 16 #define meshtastic_EnvironmentMetrics_wind_lull_tag 17 +#define meshtastic_EnvironmentMetrics_radiation_tag 18 #define meshtastic_PowerMetrics_ch1_voltage_tag 1 #define meshtastic_PowerMetrics_ch1_current_tag 2 #define meshtastic_PowerMetrics_ch2_voltage_tag 3 @@ -422,7 +428,8 @@ X(a, STATIC, OPTIONAL, UINT32, wind_direction, 13) \ X(a, STATIC, OPTIONAL, FLOAT, wind_speed, 14) \ X(a, STATIC, OPTIONAL, FLOAT, weight, 15) \ X(a, STATIC, OPTIONAL, FLOAT, wind_gust, 16) \ -X(a, STATIC, OPTIONAL, FLOAT, wind_lull, 17) +X(a, STATIC, OPTIONAL, FLOAT, wind_lull, 17) \ +X(a, STATIC, OPTIONAL, FLOAT, radiation, 18) #define meshtastic_EnvironmentMetrics_CALLBACK NULL #define meshtastic_EnvironmentMetrics_DEFAULT NULL @@ -521,12 +528,12 @@ extern const pb_msgdesc_t meshtastic_Nau7802Config_msg; #define MESHTASTIC_MESHTASTIC_TELEMETRY_PB_H_MAX_SIZE meshtastic_Telemetry_size #define meshtastic_AirQualityMetrics_size 78 #define meshtastic_DeviceMetrics_size 27 -#define meshtastic_EnvironmentMetrics_size 85 +#define meshtastic_EnvironmentMetrics_size 91 #define meshtastic_HealthMetrics_size 11 #define meshtastic_LocalStats_size 60 #define meshtastic_Nau7802Config_size 16 #define meshtastic_PowerMetrics_size 30 -#define meshtastic_Telemetry_size 92 +#define meshtastic_Telemetry_size 98 #ifdef __cplusplus } /* extern "C" */ From 932966b896d25309a53d60b24cf5738e5b7ec9e9 Mon Sep 17 00:00:00 2001 From: jake-b <1012393+jake-b@users.noreply.github.com> Date: Sun, 24 Nov 2024 07:53:52 -0500 Subject: [PATCH 042/101] Support for the ClimateGuard RadSens Geiger-Muller tube (#5425) --- src/configuration.h | 1 + src/detect/ScanI2C.h | 3 +- src/detect/ScanI2CTwoWire.cpp | 10 +++ src/main.cpp | 1 + .../Telemetry/EnvironmentTelemetry.cpp | 42 ++++++++--- .../Telemetry/Sensor/CGRadSensSensor.cpp | 75 +++++++++++++++++++ .../Telemetry/Sensor/CGRadSensSensor.h | 30 ++++++++ src/serialization/MeshPacketSerializer.cpp | 1 + .../MeshPacketSerializer_nRF52.cpp | 1 + 9 files changed, 154 insertions(+), 10 deletions(-) create mode 100644 src/modules/Telemetry/Sensor/CGRadSensSensor.cpp create mode 100644 src/modules/Telemetry/Sensor/CGRadSensSensor.h diff --git a/src/configuration.h b/src/configuration.h index 15912be3f..2e81557b1 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -148,6 +148,7 @@ along with this program. If not, see . #define NAU7802_ADDR 0x2A #define MAX30102_ADDR 0x57 #define MLX90614_ADDR_DEF 0x5A +#define CGRADSENS_ADDR 0x66 // ----------------------------------------------------------------------------- // ACCELEROMETER diff --git a/src/detect/ScanI2C.h b/src/detect/ScanI2C.h index 8591b8433..f4516458b 100644 --- a/src/detect/ScanI2C.h +++ b/src/detect/ScanI2C.h @@ -63,7 +63,8 @@ class ScanI2C ICM20948, MAX30102, TPS65233, - MPR121KB + MPR121KB, + CGRADSENS } DeviceType; // typedef uint8_t DeviceAddress; diff --git a/src/detect/ScanI2CTwoWire.cpp b/src/detect/ScanI2CTwoWire.cpp index 2413c44c9..55f13c5a0 100644 --- a/src/detect/ScanI2CTwoWire.cpp +++ b/src/detect/ScanI2CTwoWire.cpp @@ -479,6 +479,16 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize) } break; + case CGRADSENS_ADDR: + // Register 0x00 of the RadSens sensor contains is product identifier 0x7D + registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x00), 1); + if (registerValue == 0x7D) { + type = CGRADSENS; + LOG_INFO("ClimateGuard RadSens Geiger-Muller Sensor found"); + break; + } + break; + default: LOG_INFO("Device found at address 0x%x was not able to be enumerated", addr.address); } diff --git a/src/main.cpp b/src/main.cpp index 97a64a378..df18dae98 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -614,6 +614,7 @@ void setup() SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::DFROBOT_LARK, meshtastic_TelemetrySensorType_DFROBOT_LARK) SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::ICM20948, meshtastic_TelemetrySensorType_ICM20948) SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::MAX30102, meshtastic_TelemetrySensorType_MAX30102) + SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::CGRADSENS, meshtastic_TelemetrySensorType_RADSENS) i2cScanner.reset(); #endif diff --git a/src/modules/Telemetry/EnvironmentTelemetry.cpp b/src/modules/Telemetry/EnvironmentTelemetry.cpp index 4ef68d4b7..92d964f7d 100644 --- a/src/modules/Telemetry/EnvironmentTelemetry.cpp +++ b/src/modules/Telemetry/EnvironmentTelemetry.cpp @@ -25,6 +25,7 @@ #include "Sensor/BMP085Sensor.h" #include "Sensor/BMP280Sensor.h" #include "Sensor/BMP3XXSensor.h" +#include "Sensor/CGRadSensSensor.h" #include "Sensor/DFRobotLarkSensor.h" #include "Sensor/LPS22HBSensor.h" #include "Sensor/MCP9808Sensor.h" @@ -60,6 +61,7 @@ BMP3XXSensor bmp3xxSensor; #ifdef T1000X_SENSOR_EN T1000xSensor t1000xSensor; #endif +CGRadSensSensor cgRadSens; #define FAILED_STATE_SENSOR_READ_MULTIPLIER 10 #define DISPLAY_RECEIVEID_MEASUREMENTS_ON_SCREEN true @@ -147,6 +149,8 @@ int32_t EnvironmentTelemetryModule::runOnce() result = nau7802Sensor.runOnce(); if (max17048Sensor.hasSensor()) result = max17048Sensor.runOnce(); + if (cgRadSens.hasSensor()) + result = cgRadSens.runOnce(); #endif } return result; @@ -210,16 +214,19 @@ void EnvironmentTelemetryModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiSt // Display "Env. From: ..." on its own display->drawString(x, y, "Env. From: " + String(lastSender) + "(" + String(agoSecs) + "s)"); - String last_temp = String(lastMeasurement.variant.environment_metrics.temperature, 0) + "°C"; - if (moduleConfig.telemetry.environment_display_fahrenheit) { - last_temp = - String(UnitConversions::CelsiusToFahrenheit(lastMeasurement.variant.environment_metrics.temperature), 0) + "°F"; - } + if (lastMeasurement.variant.environment_metrics.has_temperature || + lastMeasurement.variant.environment_metrics.has_relative_humidity) { + String last_temp = String(lastMeasurement.variant.environment_metrics.temperature, 0) + "°C"; + if (moduleConfig.telemetry.environment_display_fahrenheit) { + last_temp = + String(UnitConversions::CelsiusToFahrenheit(lastMeasurement.variant.environment_metrics.temperature), 0) + "°F"; + } - // Continue with the remaining details - display->drawString(x, y += _fontHeight(FONT_SMALL), - "Temp/Hum: " + last_temp + " / " + - String(lastMeasurement.variant.environment_metrics.relative_humidity, 0) + "%"); + // Continue with the remaining details + display->drawString(x, y += _fontHeight(FONT_SMALL), + "Temp/Hum: " + last_temp + " / " + + String(lastMeasurement.variant.environment_metrics.relative_humidity, 0) + "%"); + } if (lastMeasurement.variant.environment_metrics.barometric_pressure != 0) { display->drawString(x, y += _fontHeight(FONT_SMALL), @@ -243,6 +250,10 @@ void EnvironmentTelemetryModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiSt if (lastMeasurement.variant.environment_metrics.weight != 0) display->drawString(x, y += _fontHeight(FONT_SMALL), "Weight: " + String(lastMeasurement.variant.environment_metrics.weight, 0) + "kg"); + + if (lastMeasurement.variant.environment_metrics.radiation != 0) + display->drawString(x, y += _fontHeight(FONT_SMALL), + "Rad: " + String(lastMeasurement.variant.environment_metrics.radiation, 2) + "µR/h"); } bool EnvironmentTelemetryModule::handleReceivedProtobuf(const meshtastic_MeshPacket &mp, meshtastic_Telemetry *t) @@ -263,6 +274,8 @@ bool EnvironmentTelemetryModule::handleReceivedProtobuf(const meshtastic_MeshPac t->variant.environment_metrics.wind_speed, t->variant.environment_metrics.wind_direction, t->variant.environment_metrics.weight); + LOG_INFO("(Received from %s): radiation=%fµR/h", sender, t->variant.environment_metrics.radiation); + #endif // release previous packet before occupying a new spot if (lastMeasurementPacket != nullptr) @@ -390,6 +403,10 @@ bool EnvironmentTelemetryModule::getEnvironmentTelemetry(meshtastic_Telemetry *m valid = valid && max17048Sensor.getMetrics(m); hasSensor = true; } + if (cgRadSens.hasSensor()) { + valid = valid && cgRadSens.getMetrics(m); + hasSensor = true; + } #endif return valid && hasSensor; @@ -443,6 +460,8 @@ bool EnvironmentTelemetryModule::sendTelemetry(NodeNum dest, bool phoneOnly) LOG_INFO("Send: wind speed=%fm/s, direction=%d degrees, weight=%fkg", m.variant.environment_metrics.wind_speed, m.variant.environment_metrics.wind_direction, m.variant.environment_metrics.weight); + LOG_INFO("Send: radiation=%fµR/h", m.variant.environment_metrics.radiation); + sensor_read_error_count = 0; meshtastic_MeshPacket *p = allocDataProtobuf(m); @@ -585,6 +604,11 @@ AdminMessageHandleResult EnvironmentTelemetryModule::handleAdminMessageForModule if (result != AdminMessageHandleResult::NOT_HANDLED) return result; } + if (cgRadSens.hasSensor()) { + result = cgRadSens.handleAdminMessage(mp, request, response); + if (result != AdminMessageHandleResult::NOT_HANDLED) + return result; + } return result; } diff --git a/src/modules/Telemetry/Sensor/CGRadSensSensor.cpp b/src/modules/Telemetry/Sensor/CGRadSensSensor.cpp new file mode 100644 index 000000000..5e69cc22f --- /dev/null +++ b/src/modules/Telemetry/Sensor/CGRadSensSensor.cpp @@ -0,0 +1,75 @@ +/* + * Support for the ClimateGuard RadSens Dosimeter + * A fun and educational sensor for Meshtastic; not for safety critical applications. + */ +#include "configuration.h" + +#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR + +#include "../mesh/generated/meshtastic/telemetry.pb.h" +#include "CGRadSensSensor.h" +#include "TelemetrySensor.h" +#include +#include + +CGRadSensSensor::CGRadSensSensor() : TelemetrySensor(meshtastic_TelemetrySensorType_RADSENS, "RadSens") {} + +int32_t CGRadSensSensor::runOnce() +{ + // Initialize the sensor following the same pattern as RCWL9620Sensor + LOG_INFO("Init sensor: %s", sensorName); + if (!hasSensor()) { + return DEFAULT_SENSOR_MINIMUM_WAIT_TIME_BETWEEN_READS; + } + + status = true; + begin(nodeTelemetrySensorsMap[sensorType].second, nodeTelemetrySensorsMap[sensorType].first); + + return initI2CSensor(); +} + +void CGRadSensSensor::setup() {} + +void CGRadSensSensor::begin(TwoWire *wire, uint8_t addr) +{ + // Store the Wire and address to the sensor following the same pattern as RCWL9620Sensor + _wire = wire; + _addr = addr; + _wire->begin(); +} + +float CGRadSensSensor::getStaticRadiation() +{ + // Read a register, following the same pattern as the RCWL9620Sensor + uint32_t data; + _wire->beginTransmission(_addr); // Transfer data to addr. + _wire->write(0x06); // Radiation intensity (static period T = 500 sec) + if (_wire->endTransmission() == 0) { + if (_wire->requestFrom(_addr, (uint8_t)3)) { + ; // Request 3 bytes + data = _wire->read(); + data <<= 8; + data |= _wire->read(); + data <<= 8; + data |= _wire->read(); + + // As per the data sheet for the RadSens + // Register 0x06 contains the reading in 0.1 * μR / h + float microRadPerHr = float(data) / 10.0; + return microRadPerHr; + } + } + return -1.0; +} + +bool CGRadSensSensor::getMetrics(meshtastic_Telemetry *measurement) +{ + // Store the meansurement in the the appropriate fields of the protobuf + measurement->variant.environment_metrics.has_radiation = true; + + LOG_DEBUG("CGRADSENS getMetrics"); + measurement->variant.environment_metrics.radiation = getStaticRadiation(); + + return true; +} +#endif \ No newline at end of file diff --git a/src/modules/Telemetry/Sensor/CGRadSensSensor.h b/src/modules/Telemetry/Sensor/CGRadSensSensor.h new file mode 100644 index 000000000..3b15a19a2 --- /dev/null +++ b/src/modules/Telemetry/Sensor/CGRadSensSensor.h @@ -0,0 +1,30 @@ +/* + * Support for the ClimateGuard RadSens Dosimeter + * A fun and educational sensor for Meshtastic; not for safety critical applications. + */ +#include "configuration.h" + +#if !MESHTASTIC_EXCLUDE_ENVIRONMENTAL_SENSOR + +#include "../mesh/generated/meshtastic/telemetry.pb.h" +#include "TelemetrySensor.h" +#include + +class CGRadSensSensor : public TelemetrySensor +{ + private: + uint8_t _addr = 0x66; + TwoWire *_wire = &Wire; + + protected: + virtual void setup() override; + void begin(TwoWire *wire = &Wire, uint8_t addr = 0x66); + float getStaticRadiation(); + + public: + CGRadSensSensor(); + virtual int32_t runOnce() override; + virtual bool getMetrics(meshtastic_Telemetry *measurement) override; +}; + +#endif \ No newline at end of file diff --git a/src/serialization/MeshPacketSerializer.cpp b/src/serialization/MeshPacketSerializer.cpp index 05a98f7a6..b4603186b 100644 --- a/src/serialization/MeshPacketSerializer.cpp +++ b/src/serialization/MeshPacketSerializer.cpp @@ -78,6 +78,7 @@ std::string MeshPacketSerializer::JsonSerialize(const meshtastic_MeshPacket *mp, msgPayload["wind_direction"] = new JSONValue((uint)decoded->variant.environment_metrics.wind_direction); msgPayload["wind_gust"] = new JSONValue(decoded->variant.environment_metrics.wind_gust); msgPayload["wind_lull"] = new JSONValue(decoded->variant.environment_metrics.wind_lull); + msgPayload["radiation"] = new JSONValue(decoded->variant.environment_metrics.radiation); } else if (decoded->which_variant == meshtastic_Telemetry_air_quality_metrics_tag) { msgPayload["pm10"] = new JSONValue((unsigned int)decoded->variant.air_quality_metrics.pm10_standard); msgPayload["pm25"] = new JSONValue((unsigned int)decoded->variant.air_quality_metrics.pm25_standard); diff --git a/src/serialization/MeshPacketSerializer_nRF52.cpp b/src/serialization/MeshPacketSerializer_nRF52.cpp index 15b8b1a34..89ecddfad 100644 --- a/src/serialization/MeshPacketSerializer_nRF52.cpp +++ b/src/serialization/MeshPacketSerializer_nRF52.cpp @@ -77,6 +77,7 @@ std::string MeshPacketSerializer::JsonSerialize(const meshtastic_MeshPacket *mp, jsonObj["payload"]["wind_direction"] = (uint)decoded->variant.environment_metrics.wind_direction; jsonObj["payload"]["wind_gust"] = decoded->variant.environment_metrics.wind_gust; jsonObj["payload"]["wind_lull"] = decoded->variant.environment_metrics.wind_lull; + jsonObj["payload"]["radiation"] = decoded->variant.environment_metrics.radiation; } else if (decoded->which_variant == meshtastic_Telemetry_air_quality_metrics_tag) { jsonObj["payload"]["pm10"] = (unsigned int)decoded->variant.air_quality_metrics.pm10_standard; jsonObj["payload"]["pm25"] = (unsigned int)decoded->variant.air_quality_metrics.pm25_standard; From ad9d7a49723e1101c1ef6dcde4bc63ed305e2112 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Sun, 24 Nov 2024 14:28:36 +0100 Subject: [PATCH 043/101] fixes https://github.com/meshtastic/firmware/issues/5434 (#5435) * update libpax * fix interval init --- arch/esp32/esp32.ini | 2 +- src/modules/esp32/PaxcounterModule.cpp | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/esp32/esp32.ini b/arch/esp32/esp32.ini index 1f17bc691..d6a756bec 100644 --- a/arch/esp32/esp32.ini +++ b/arch/esp32/esp32.ini @@ -46,7 +46,7 @@ lib_deps = ${radiolib_base.lib_deps} https://github.com/meshtastic/esp32_https_server.git#23665b3adc080a311dcbb586ed5941b5f94d6ea2 h2zero/NimBLE-Arduino@^1.4.2 - https://github.com/dbSuS/libpax.git#7bcd3fcab75037505be9b122ab2b24cc5176b587 + https://github.com/dbinfrago/libpax.git#3cdc0371c375676a97967547f4065607d4c53fd1 lewisxhe/XPowersLib@^0.2.6 https://github.com/meshtastic/ESP32_Codec2.git#633326c78ac251c059ab3a8c430fcdf25b41672f rweather/Crypto@^0.4.0 diff --git a/src/modules/esp32/PaxcounterModule.cpp b/src/modules/esp32/PaxcounterModule.cpp index 89e486f82..b27586771 100644 --- a/src/modules/esp32/PaxcounterModule.cpp +++ b/src/modules/esp32/PaxcounterModule.cpp @@ -95,7 +95,9 @@ int32_t PaxcounterModule::runOnce() // internal processing initialization libpax_counter_init(handlePaxCounterReportRequest, &count_from_libpax, - moduleConfig.paxcounter.paxcounter_update_interval, 0); + Default::getConfiguredOrDefault(moduleConfig.paxcounter.paxcounter_update_interval, + default_telemetry_broadcast_interval_secs), + 0); libpax_counter_start(); } else { sendInfo(NODENUM_BROADCAST); From 37da78919a679a632eea29f4b3d6d1a4cbbd84fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9sar=20de=20Tassis=20Filho?= Date: Mon, 25 Nov 2024 01:05:06 -0300 Subject: [PATCH 044/101] Fix memory leaks by adding missing `free()` calls before early returns in `MQTT::onReceive` (#5439) This fix addresses memory leaks in the `MQTT::onReceive` function by ensuring that dynamically allocated resources (`e.channel_id`, `e.gateway_id` and `e.packet`) are properly freed before each early return. Previously, these resources were only freed at the end of the function, leaving them unhandled in certain exit paths. Adding the missing `free()` calls prevents memory leaks and ensures proper resource cleanup in all scenarios. --- src/mqtt/MQTT.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/mqtt/MQTT.cpp b/src/mqtt/MQTT.cpp index 3d5948976..967b7ba50 100644 --- a/src/mqtt/MQTT.cpp +++ b/src/mqtt/MQTT.cpp @@ -167,17 +167,26 @@ void MQTT::onReceive(char *topic, byte *payload, size_t length) if (isFromUs(p)) { LOG_INFO("Ignore downlink message we originally sent"); packetPool.release(p); + free(e.channel_id); + free(e.gateway_id); + free(e.packet); return; } if (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag) { if (moduleConfig.mqtt.encryption_enabled) { LOG_INFO("Ignore decoded message on MQTT, encryption is enabled"); packetPool.release(p); + free(e.channel_id); + free(e.gateway_id); + free(e.packet); return; } if (p->decoded.portnum == meshtastic_PortNum_ADMIN_APP) { LOG_INFO("Ignore decoded admin packet"); packetPool.release(p); + free(e.channel_id); + free(e.gateway_id); + free(e.packet); return; } p->channel = ch.index; @@ -771,4 +780,4 @@ bool MQTT::isPrivateIpAddress(const char address[]) int octet2Num = atoi(octet2); return octet2Num >= 16 && octet2Num <= 31; -} \ No newline at end of file +} From 6018c0a830ba105b536feec8742e0e19ff7ab22e Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Mon, 25 Nov 2024 05:14:48 -0600 Subject: [PATCH 045/101] Removing 1.0 legacy boards from releases and completely removing Heltec wireless capsule from support (#5436) Co-authored-by: Tom Fifield --- platformio.ini | 1 - .../heltec_capsule_sensor_v3/platformio.ini | 11 ---- variants/heltec_capsule_sensor_v3/variant.h | 53 ------------------- .../heltec_wireless_paper_v1/platformio.ini | 1 + .../platformio.ini | 3 +- 5 files changed, 2 insertions(+), 67 deletions(-) delete mode 100644 variants/heltec_capsule_sensor_v3/platformio.ini delete mode 100644 variants/heltec_capsule_sensor_v3/variant.h diff --git a/platformio.ini b/platformio.ini index 982848f41..7f4fbc3a5 100644 --- a/platformio.ini +++ b/platformio.ini @@ -34,7 +34,6 @@ default_envs = tbeam ;default_envs = radiomaster_900_bandit_nano ;default_envs = radiomaster_900_bandit_micro ;default_envs = radiomaster_900_bandit -;default_envs = heltec_capsule_sensor_v3 ;default_envs = heltec_vision_master_t190 ;default_envs = heltec_vision_master_e213 ;default_envs = heltec_vision_master_e290 diff --git a/variants/heltec_capsule_sensor_v3/platformio.ini b/variants/heltec_capsule_sensor_v3/platformio.ini deleted file mode 100644 index f1aef925d..000000000 --- a/variants/heltec_capsule_sensor_v3/platformio.ini +++ /dev/null @@ -1,11 +0,0 @@ -[env:heltec_capsule_sensor_v3] -extends = esp32s3_base -board = heltec_wifi_lora_32_V3 -board_check = true - -build_flags = - ${esp32s3_base.build_flags} -I variants/heltec_capsule_sensor_v3 - -D HELTEC_CAPSULE_SENSOR_V3 - -D GPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely. - ;-D DEBUG_DISABLED ; uncomment this line to disable DEBUG output - diff --git a/variants/heltec_capsule_sensor_v3/variant.h b/variants/heltec_capsule_sensor_v3/variant.h deleted file mode 100644 index 415de0559..000000000 --- a/variants/heltec_capsule_sensor_v3/variant.h +++ /dev/null @@ -1,53 +0,0 @@ -#define LED_PIN 33 -#define LED_PIN2 34 -#define EXT_PWR_DETECT 35 - -#define BUTTON_PIN 18 - -#define BATTERY_PIN 7 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage -#define ADC_CHANNEL ADC1_GPIO7_CHANNEL -#define ADC_ATTENUATION ADC_ATTEN_DB_2_5 // lower dB for high resistance voltage divider -#define ADC_MULTIPLIER (4.9 * 1.045) -#define ADC_CTRL 36 // active HIGH, powers the voltage divider. Only on 1.1 -#define ADC_CTRL_ENABLED HIGH - -#undef GPS_RX_PIN -#undef GPS_TX_PIN -#define GPS_RX_PIN 5 -#define GPS_TX_PIN 4 -#define PIN_GPS_RESET 3 -#define GPS_RESET_MODE LOW -#define PIN_GPS_PPS 1 -#define PIN_GPS_EN 21 -#define GPS_EN_ACTIVE HIGH - -#define USE_SX1262 -#define LORA_DIO0 -1 // a No connect on the SX1262 module -#define LORA_RESET 12 -#define LORA_DIO1 14 // SX1262 IRQ -#define LORA_DIO2 13 // SX1262 BUSY -#define LORA_DIO3 // Not connected on PCB, but internally on the TTGO SX1262, if DIO3 is high the TXCO is enabled - -#define LORA_SCK 9 -#define LORA_MISO 11 -#define LORA_MOSI 10 -#define LORA_CS 8 - -#define SX126X_CS LORA_CS -#define SX126X_DIO1 LORA_DIO1 -#define SX126X_BUSY LORA_DIO2 -#define SX126X_RESET LORA_RESET - -#define SX126X_DIO2_AS_RF_SWITCH -#define SX126X_DIO3_TCXO_VOLTAGE 1.8 - -#define I2C_SDA 1 -#define I2C_SCL 2 -#define HAS_SCREEN 0 -#define SENSOR_POWER_CTRL_PIN 21 -#define SENSOR_POWER_ON 1 - -#define PERIPHERAL_WARMUP_MS 100 -#define SENSOR_GPS_CONFLICT - -#define ESP32S3_WAKE_TYPE ESP_EXT1_WAKEUP_ANY_HIGH \ No newline at end of file diff --git a/variants/heltec_wireless_paper_v1/platformio.ini b/variants/heltec_wireless_paper_v1/platformio.ini index 999f1586a..c94bcacca 100644 --- a/variants/heltec_wireless_paper_v1/platformio.ini +++ b/variants/heltec_wireless_paper_v1/platformio.ini @@ -1,5 +1,6 @@ [env:heltec-wireless-paper-v1_0] extends = esp32s3_base +board_level = extra board = heltec_wifi_lora_32_V3 build_flags = ${esp32s3_base.build_flags} diff --git a/variants/heltec_wireless_tracker_V1_0/platformio.ini b/variants/heltec_wireless_tracker_V1_0/platformio.ini index 303e27dbf..0e48c72f2 100644 --- a/variants/heltec_wireless_tracker_V1_0/platformio.ini +++ b/variants/heltec_wireless_tracker_V1_0/platformio.ini @@ -1,14 +1,13 @@ [env:heltec-wireless-tracker-V1-0] extends = esp32s3_base +board_level = extra board = heltec_wireless_tracker upload_protocol = esptool - build_flags = ${esp32s3_base.build_flags} -I variants/heltec_wireless_tracker_V1_0 -D HELTEC_TRACKER_V1_0 -D GPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely. ;-D DEBUG_DISABLED ; uncomment this line to disable DEBUG output - lib_deps = ${esp32s3_base.lib_deps} lovyan03/LovyanGFX@^1.1.8 \ No newline at end of file From 0048e3cdcb80d114f4f934529b0d74489699d788 Mon Sep 17 00:00:00 2001 From: Christopher Hoover Date: Mon, 25 Nov 2024 03:32:04 -0800 Subject: [PATCH 046/101] A second round of cleanup on GPS.h. (#5433) * Move yet more stuff out of GPS.h and into file scope. * Protect code macros from eating semicolons. * Remove unused (and unimplemented) getDOPString. * clang-format with project style file on affected files. Signed-off-by: Christopher Hoover --- src/gps/GPS.cpp | 46 +++++++++++--------- src/gps/GPS.h | 53 ----------------------- src/gps/cas.h | 8 ++-- src/gps/ubx.h | 112 ++++++++++++++++++++++++------------------------ 4 files changed, 86 insertions(+), 133 deletions(-) diff --git a/src/gps/GPS.cpp b/src/gps/GPS.cpp index a6db85950..d49092fff 100644 --- a/src/gps/GPS.cpp +++ b/src/gps/GPS.cpp @@ -33,24 +33,26 @@ HardwareSerial *GPS::_serial_gps = &Serial1; #elif defined(ARCH_RP2040) SerialUART *GPS::_serial_gps = &Serial1; #else -HardwareSerial *GPS::_serial_gps = NULL; +HardwareSerial *GPS::_serial_gps = nullptr; #endif GPS *gps = nullptr; -GPSUpdateScheduling scheduling; +static const char *ACK_SUCCESS_MESSAGE = "Get ack success!"; + +static GPSUpdateScheduling scheduling; /// Multiple GPS instances might use the same serial port (in sequence), but we can /// only init that port once. static bool didSerialInit; -struct uBloxGnssModelInfo info; -uint8_t uBloxProtocolVersion; +static struct uBloxGnssModelInfo info; +static uint8_t uBloxProtocolVersion; #define GPS_SOL_EXPIRY_MS 5000 // in millis. give 1 second time to combine different sentences. NMEA Frequency isn't higher anyway #define NMEA_MSG_GXGSA "GNGSA" // GSA message (GPGSA, GNGSA etc) // For logging -const char *getGPSPowerStateString(GPSPowerState state) +static const char *getGPSPowerStateString(GPSPowerState state) { switch (state) { case GPS_ACTIVE: @@ -69,7 +71,7 @@ const char *getGPSPowerStateString(GPSPowerState state) } } -void GPS::UBXChecksum(uint8_t *message, size_t length) +static void UBXChecksum(uint8_t *message, size_t length) { uint8_t CK_A = 0, CK_B = 0; @@ -85,7 +87,7 @@ void GPS::UBXChecksum(uint8_t *message, size_t length) } // Calculate the checksum for a CAS packet -void GPS::CASChecksum(uint8_t *message, size_t length) +static void CASChecksum(uint8_t *message, size_t length) { uint32_t cksum = ((uint32_t)message[5] << 24); // Message ID cksum += ((uint32_t)message[4]) << 16; // Class @@ -419,7 +421,6 @@ int GPS::getACK(uint8_t *buffer, uint16_t size, uint8_t requestedClass, uint8_t */ bool GPS::setup() { - if (!didSerialInit) { int msglen = 0; if (tx_gpio && gnssModel == GNSS_MODEL_UNKNOWN) { @@ -718,6 +719,7 @@ GPS::~GPS() // we really should unregister our sleep observer notifyDeepSleepObserver.unobserve(¬ifyDeepSleep); } + // Put the GPS hardware into a specified state void GPS::setPowerState(GPSPowerState newState, uint32_t sleepTime) { @@ -882,17 +884,17 @@ void GPS::setPowerUBLOX(bool on, uint32_t sleepMs) if (gnssModel != GNSS_MODEL_UBLOX10) { // Encode the sleep time in millis into the packet for (int i = 0; i < 4; i++) - gps->_message_PMREQ[0 + i] = sleepMs >> (i * 8); + _message_PMREQ[0 + i] = sleepMs >> (i * 8); // Record the message length - msglen = gps->makeUBXPacket(0x02, 0x41, sizeof(_message_PMREQ), gps->_message_PMREQ); + msglen = gps->makeUBXPacket(0x02, 0x41, sizeof(_message_PMREQ), _message_PMREQ); } else { // Encode the sleep time in millis into the packet for (int i = 0; i < 4; i++) - gps->_message_PMREQ_10[4 + i] = sleepMs >> (i * 8); + _message_PMREQ_10[4 + i] = sleepMs >> (i * 8); // Record the message length - msglen = gps->makeUBXPacket(0x02, 0x41, sizeof(_message_PMREQ_10), gps->_message_PMREQ_10); + msglen = gps->makeUBXPacket(0x02, 0x41, sizeof(_message_PMREQ_10), _message_PMREQ_10); } // Send the UBX packet @@ -1099,17 +1101,19 @@ int GPS::prepareDeepSleep(void *unused) return 0; } -const char *PROBE_MESSAGE = "Trying %s (%s)..."; -const char *DETECTED_MESSAGE = "%s detected, using %s Module"; +static const char *PROBE_MESSAGE = "Trying %s (%s)..."; +static const char *DETECTED_MESSAGE = "%s detected, using %s Module"; #define PROBE_SIMPLE(CHIP, TOWRITE, RESPONSE, DRIVER, TIMEOUT, ...) \ - LOG_DEBUG(PROBE_MESSAGE, TOWRITE, CHIP); \ - clearBuffer(); \ - _serial_gps->write(TOWRITE "\r\n"); \ - if (getACK(RESPONSE, TIMEOUT) == GNSS_RESPONSE_OK) { \ - LOG_INFO(DETECTED_MESSAGE, CHIP, #DRIVER); \ - return DRIVER; \ - } + do { \ + LOG_DEBUG(PROBE_MESSAGE, TOWRITE, CHIP); \ + clearBuffer(); \ + _serial_gps->write(TOWRITE "\r\n"); \ + if (getACK(RESPONSE, TIMEOUT) == GNSS_RESPONSE_OK) { \ + LOG_INFO(DETECTED_MESSAGE, CHIP, #DRIVER); \ + return DRIVER; \ + } \ + } while (0) GnssModel_t GPS::probe(int serialSpeed) { diff --git a/src/gps/GPS.h b/src/gps/GPS.h index cb970f7db..cc72350d2 100644 --- a/src/gps/GPS.h +++ b/src/gps/GPS.h @@ -54,9 +54,6 @@ enum GPSPowerState : uint8_t { GPS_OFF // Powered off indefinitely }; -// Generate a string representation of DOP -const char *getDOPString(uint32_t dop); - /** * A gps class that only reads from the GPS periodically and keeps the gps powered down except when reading * @@ -207,52 +204,6 @@ class GPS : private concurrency::OSThread #else static HardwareSerial *_serial_gps; #endif - static uint8_t _message_PMREQ[]; - static uint8_t _message_PMREQ_10[]; - static const uint8_t _message_CFG_RXM_PSM[]; - static const uint8_t _message_CFG_RXM_ECO[]; - static const uint8_t _message_CFG_PM2[]; - static const uint8_t _message_GNSS_7[]; - static const uint8_t _message_GNSS_8[]; - static const uint8_t _message_JAM_6_7[]; - static const uint8_t _message_JAM_8[]; - static const uint8_t _message_NAVX5[]; - static const uint8_t _message_NAVX5_8[]; - static const uint8_t _message_NMEA[]; - static const uint8_t _message_DISABLE_TXT_INFO[]; - static const uint8_t _message_1HZ[]; - static const uint8_t _message_GLL[]; - static const uint8_t _message_GSA[]; - static const uint8_t _message_GSV[]; - static const uint8_t _message_VTG[]; - static const uint8_t _message_RMC[]; - static const uint8_t _message_AID[]; - static const uint8_t _message_GGA[]; - static const uint8_t _message_PMS[]; - static const uint8_t _message_SAVE[]; - static const uint8_t _message_SAVE_10[]; - - // VALSET Commands for M10 - static const uint8_t _message_VALSET_PM[]; - static const uint8_t _message_VALSET_PM_RAM[]; - static const uint8_t _message_VALSET_PM_BBR[]; - static const uint8_t _message_VALSET_ITFM_RAM[]; - static const uint8_t _message_VALSET_ITFM_BBR[]; - static const uint8_t _message_VALSET_DISABLE_NMEA_RAM[]; - static const uint8_t _message_VALSET_DISABLE_NMEA_BBR[]; - static const uint8_t _message_VALSET_DISABLE_TXT_INFO_RAM[]; - static const uint8_t _message_VALSET_DISABLE_TXT_INFO_BBR[]; - static const uint8_t _message_VALSET_ENABLE_NMEA_RAM[]; - static const uint8_t _message_VALSET_ENABLE_NMEA_BBR[]; - static const uint8_t _message_VALSET_DISABLE_SBAS_RAM[]; - static const uint8_t _message_VALSET_DISABLE_SBAS_BBR[]; - - // CASIC commands for ATGM336H - static const uint8_t _message_CAS_CFG_RST_FACTORY[]; - static const uint8_t _message_CAS_CFG_NAVX_CONF[]; - static const uint8_t _message_CAS_CFG_RATE_1HZ[]; - - const char *ACK_SUCCESS_MESSAGE = "Get ack success!"; // Create a ublox packet for editing in memory uint8_t makeUBXPacket(uint8_t class_id, uint8_t msg_id, uint8_t payload_size, const uint8_t *msg); @@ -273,10 +224,6 @@ class GPS : private concurrency::OSThread /// always returns 0 to indicate okay to sleep int prepareDeepSleep(void *unused); - // Calculate checksum - void UBXChecksum(uint8_t *message, size_t length); - void CASChecksum(uint8_t *message, size_t length); - /** Set power with EN pin, if relevant */ void writePinEN(bool on); diff --git a/src/gps/cas.h b/src/gps/cas.h index 53d75cda9..725fd07b3 100644 --- a/src/gps/cas.h +++ b/src/gps/cas.h @@ -21,7 +21,7 @@ // CFG-RST (0x06, 0x02) // Factory reset -const uint8_t GPS::_message_CAS_CFG_RST_FACTORY[] = { +static const uint8_t _message_CAS_CFG_RST_FACTORY[] = { 0xFF, 0x03, // Fields to clear 0x01, // Reset Mode: Controlled Software reset 0x03 // Startup Mode: Factory @@ -30,7 +30,7 @@ const uint8_t GPS::_message_CAS_CFG_RST_FACTORY[] = { // CFG_RATE (0x06, 0x01) // 1HZ update rate, this should always be the case after // factory reset but update it regardless -const uint8_t GPS::_message_CAS_CFG_RATE_1HZ[] = { +static const uint8_t _message_CAS_CFG_RATE_1HZ[] = { 0xE8, 0x03, // Update Rate: 0x03E8 = 1000ms 0x00, 0x00 // Reserved }; @@ -39,7 +39,7 @@ const uint8_t GPS::_message_CAS_CFG_RATE_1HZ[] = { // Initial ATGM33H-5N configuration, Updates for Dynamic Mode, Fix Mode, and SV system // Qwirk: The ATGM33H-5N-31 should only support GPS+BDS, however it will happily enable // and use GPS+BDS+GLONASS iff the correct CFG_NAVX command is used. -const uint8_t GPS::_message_CAS_CFG_NAVX_CONF[] = { +static const uint8_t _message_CAS_CFG_NAVX_CONF[] = { 0x03, 0x01, 0x00, 0x00, // Update Mask: Dynamic Mode, Fix Mode, Nav Settings 0x03, // Dynamic Mode: Automotive 0x03, // Fix Mode: Auto 2D/3D @@ -60,4 +60,4 @@ const uint8_t GPS::_message_CAS_CFG_NAVX_CONF[] = { 0x00, 0x00, 0x00, 0x00, // Position Accuracy Max 0x00, 0x00, 0x00, 0x00, // Time Accuracy Max 0x00, 0x00, 0x00, 0x00 // Static Hold Threshold -}; \ No newline at end of file +}; diff --git a/src/gps/ubx.h b/src/gps/ubx.h index 551921384..d674bed51 100644 --- a/src/gps/ubx.h +++ b/src/gps/ubx.h @@ -1,20 +1,22 @@ -const char *failMessage = "Unable to %s"; +static const char *failMessage = "Unable to %s"; #define SEND_UBX_PACKET(TYPE, ID, DATA, ERRMSG, TIMEOUT) \ - msglen = makeUBXPacket(TYPE, ID, sizeof(DATA), DATA); \ - _serial_gps->write(UBXscratch, msglen); \ - if (getACK(TYPE, ID, TIMEOUT) != GNSS_RESPONSE_OK) { \ - LOG_WARN(failMessage, #ERRMSG); \ - } + do { \ + msglen = makeUBXPacket(TYPE, ID, sizeof(DATA), DATA); \ + _serial_gps->write(UBXscratch, msglen); \ + if (getACK(TYPE, ID, TIMEOUT) != GNSS_RESPONSE_OK) { \ + LOG_WARN(failMessage, #ERRMSG); \ + } \ + } while (0) // Power Management -uint8_t GPS::_message_PMREQ[] PROGMEM = { +static uint8_t _message_PMREQ[] PROGMEM = { 0x00, 0x00, 0x00, 0x00, // 4 bytes duration of request task (milliseconds) 0x02, 0x00, 0x00, 0x00 // Bitfield, set backup = 1 }; -uint8_t GPS::_message_PMREQ_10[] PROGMEM = { +static uint8_t _message_PMREQ_10[] PROGMEM = { 0x00, // version (0 for this version) 0x00, 0x00, 0x00, // Reserved 1 0x00, 0x00, 0x00, 0x00, // 4 bytes duration of request task (milliseconds) @@ -22,18 +24,18 @@ uint8_t GPS::_message_PMREQ_10[] PROGMEM = { 0x08, 0x00, 0x00, 0x00 // wakeupSources Wake on uartrx }; -const uint8_t GPS::_message_CFG_RXM_PSM[] PROGMEM = { +static const uint8_t _message_CFG_RXM_PSM[] PROGMEM = { 0x08, // Reserved 0x01 // Power save mode }; // only for Neo-6 -const uint8_t GPS::_message_CFG_RXM_ECO[] PROGMEM = { +static const uint8_t _message_CFG_RXM_ECO[] PROGMEM = { 0x08, // Reserved 0x04 // eco mode }; -const uint8_t GPS::_message_CFG_PM2[] PROGMEM = { +static const uint8_t _message_CFG_PM2[] PROGMEM = { 0x01, // version 0x00, // Reserved 1, set to 0x06 by u-Center 0x00, // Reserved 2 @@ -58,7 +60,7 @@ const uint8_t GPS::_message_CFG_PM2[] PROGMEM = { // Constallation setup, none required for Neo-6 // For Neo-7 GPS & SBAS -const uint8_t GPS::_message_GNSS_7[] = { +static const uint8_t _message_GNSS_7[] = { 0x00, // msgVer (0 for this version) 0x00, // numTrkChHw (max number of hardware channels, read only, so it's always 0) 0xff, // numTrkChUse (max number of channels to use, 0xff = max available) @@ -76,7 +78,7 @@ const uint8_t GPS::_message_GNSS_7[] = { // There is also a possibility that the module may be GPS-only. // For M8 GPS, GLONASS, Galileo, SBAS, QZSS -const uint8_t GPS::_message_GNSS_8[] = { +static const uint8_t _message_GNSS_8[] = { 0x00, // msgVer (0 for this version) 0x00, // numTrkChHw (max number of hardware channels, read only, so it's always 0) 0xff, // numTrkChUse (max number of channels to use, 0xff = max available) @@ -90,7 +92,7 @@ const uint8_t GPS::_message_GNSS_8[] = { }; /* // For M8 GPS, GLONASS, BeiDou, SBAS, QZSS -const uint8_t GPS::_message_GNSS_8_B[] = { +static const uint8_t _message_GNSS_8_B[] = { 0x00, // msgVer (0 for this version) 0x00, // numTrkChHw (max number of hardware channels, read only, so it's always 0) 0xff, // numTrkChUse (max number of channels to use, 0xff = max available) read only for protocol >23 @@ -105,7 +107,7 @@ const uint8_t GPS::_message_GNSS_8_B[] = { */ // For M8 we want to enable NMEA version 4.10 messages to allow for Galileo and or BeiDou -const uint8_t GPS::_message_NMEA[]{ +static const uint8_t _message_NMEA[]{ 0x00, // filter flags 0x41, // NMEA Version 0x00, // Max number of SVs to report per TaklerId @@ -121,13 +123,13 @@ const uint8_t GPS::_message_NMEA[]{ // Enable jamming/interference monitor // For Neo-6, Max-7 and Neo-7 -const uint8_t GPS::_message_JAM_6_7[] = { +static const uint8_t _message_JAM_6_7[] = { 0xf3, 0xac, 0x62, 0xad, // config1 bbThreshold = 3, cwThreshold = 15, enable = 1, reserved bits 0x16B156 0x1e, 0x03, 0x00, 0x00 // config2 antennaSetting Unknown = 0, reserved 3, = 0x00,0x00, reserved 2 = 0x31E }; // For M8 -const uint8_t GPS::_message_JAM_8[] = { +static const uint8_t _message_JAM_8[] = { 0xf3, 0xac, 0x62, 0xad, // config1 bbThreshold = 3, cwThreshold = 15, enable1 = 1, reserved bits 0x16B156 0x1e, 0x43, 0x00, 0x00 // config2 antennaSetting Unknown = 0, enable2 = 1, generalBits = 0x31E }; @@ -137,7 +139,7 @@ const uint8_t GPS::_message_JAM_8[] = { // ToDo: check UBX-MON-VER for module type and protocol version // For the Neo-6 -const uint8_t GPS::_message_NAVX5[] = { +static const uint8_t _message_NAVX5[] = { 0x00, 0x00, // msgVer (0 for this version) 0x4c, 0x66, // mask1 0x00, 0x00, 0x00, 0x00, // Reserved 0 @@ -166,7 +168,7 @@ const uint8_t GPS::_message_NAVX5[] = { 0x00, 0x00, 0x00, 0x00 // Reserved 4 }; // For the M8 -const uint8_t GPS::_message_NAVX5_8[] = { +static const uint8_t _message_NAVX5_8[] = { 0x02, 0x00, // msgVer (2 for this version) 0x4c, 0x66, // mask1 0x00, 0x00, 0x00, 0x00, // mask2 @@ -197,7 +199,7 @@ const uint8_t GPS::_message_NAVX5_8[] = { // Additionally, for some new modules like the M9/M10, an update rate lower than 5Hz // is recommended to avoid a known issue with satellites disappearing. // The module defaults for M8, M9, M10 are the same as we use here so no update is necessary -const uint8_t GPS::_message_1HZ[] = { +static const uint8_t _message_1HZ[] = { 0xE8, 0x03, // Measurement Rate (1000ms for 1Hz) 0x01, 0x00, // Navigation rate, always 1 in GPS mode 0x01, 0x00 // Time reference @@ -205,7 +207,7 @@ const uint8_t GPS::_message_1HZ[] = { // Disable GLL. GLL - Geographic position (latitude and longitude), which provides the current geographical // coordinates. -const uint8_t GPS::_message_GLL[] = { +static const uint8_t _message_GLL[] = { 0xF0, 0x01, // NMEA ID for GLL 0x00, // Rate for DDC 0x00, // Rate for UART1 @@ -217,7 +219,7 @@ const uint8_t GPS::_message_GLL[] = { // Disable GSA. GSA - GPS DOP and active satellites, used for detailing the satellites used in the positioning and // the DOP (Dilution of Precision) -const uint8_t GPS::_message_GSA[] = { +static const uint8_t _message_GSA[] = { 0xF0, 0x02, // NMEA ID for GSA 0x00, // Rate for DDC 0x00, // Rate for UART1 @@ -228,7 +230,7 @@ const uint8_t GPS::_message_GSA[] = { }; // Disable GSV. GSV - Satellites in view, details the number and location of satellites in view. -const uint8_t GPS::_message_GSV[] = { +static const uint8_t _message_GSV[] = { 0xF0, 0x03, // NMEA ID for GSV 0x00, // Rate for DDC 0x00, // Rate for UART1 @@ -240,7 +242,7 @@ const uint8_t GPS::_message_GSV[] = { // Disable VTG. VTG - Track made good and ground speed, which provides course and speed information relative to // the ground. -const uint8_t GPS::_message_VTG[] = { +static const uint8_t _message_VTG[] = { 0xF0, 0x05, // NMEA ID for VTG 0x00, // Rate for DDC 0x00, // Rate for UART1 @@ -251,7 +253,7 @@ const uint8_t GPS::_message_VTG[] = { }; // Enable RMC. RMC - Recommended Minimum data, the essential gps pvt (position, velocity, time) data. -const uint8_t GPS::_message_RMC[] = { +static const uint8_t _message_RMC[] = { 0xF0, 0x04, // NMEA ID for RMC 0x00, // Rate for DDC 0x01, // Rate for UART1 @@ -262,7 +264,7 @@ const uint8_t GPS::_message_RMC[] = { }; // Enable GGA. GGA - Global Positioning System Fix Data, which provides 3D location and accuracy data. -const uint8_t GPS::_message_GGA[] = { +static const uint8_t _message_GGA[] = { 0xF0, 0x00, // NMEA ID for GGA 0x00, // Rate for DDC 0x01, // Rate for UART1 @@ -274,7 +276,7 @@ const uint8_t GPS::_message_GGA[] = { // Disable UBX-AID-ALPSRV as it may confuse TinyGPS. The Neo-6 seems to send this message // whether the AID Autonomous is enabled or not -const uint8_t GPS::_message_AID[] = { +static const uint8_t _message_AID[] = { 0x0B, 0x32, // NMEA ID for UBX-AID-ALPSRV 0x00, // Rate for DDC 0x00, // Rate for UART1 @@ -287,7 +289,7 @@ const uint8_t GPS::_message_AID[] = { // Turn off TEXT INFO Messages for all but M10 series // B5 62 06 02 0A 00 01 00 00 00 03 03 00 03 03 00 1F 20 -const uint8_t GPS::_message_DISABLE_TXT_INFO[] = { +static const uint8_t _message_DISABLE_TXT_INFO[] = { 0x01, // Protocol ID for NMEA 0x00, 0x00, 0x00, // Reserved 0x03, // I2C @@ -310,7 +312,7 @@ const uint8_t GPS::_message_DISABLE_TXT_INFO[] = { // and must be smaller than the period. It is only valid when the powerSetupValue is set to Interval; otherwise, // it must be set to '0'. // This command applies to M8 products -const uint8_t GPS::_message_PMS[] = { +static const uint8_t _message_PMS[] = { 0x00, // Version (0) 0x03, // Power setup value 3 = Agresssive 1Hz 0x00, 0x00, // period: not applicable, set to 0 @@ -318,14 +320,14 @@ const uint8_t GPS::_message_PMS[] = { 0x00, 0x00 // reserved, generated by u-center }; -const uint8_t GPS::_message_SAVE[] = { +static const uint8_t _message_SAVE[] = { 0x00, 0x00, 0x00, 0x00, // clearMask: no sections cleared 0xFF, 0xFF, 0x00, 0x00, // saveMask: save all sections 0x00, 0x00, 0x00, 0x00, // loadMask: no sections loaded 0x17 // deviceMask: BBR, Flash, EEPROM, and SPI Flash }; -const uint8_t GPS::_message_SAVE_10[] = { +static const uint8_t _message_SAVE_10[] = { 0x00, 0x00, 0x00, 0x00, // clearMask: no sections cleared 0xFF, 0xFF, 0x00, 0x00, // saveMask: save all sections 0x00, 0x00, 0x00, 0x00, // loadMask: no sections loaded @@ -375,12 +377,12 @@ LIMITPEAKCURRENT L 1 // b5 62 06 8a 26 00 00 02 00 00 01 00 d0 20 02 02 00 d0 40 05 00 00 00 05 00 d0 30 01 00 08 00 d0 10 01 09 00 d0 10 01 10 00 d0 // 10 01 8c 03 */ -const uint8_t GPS::_message_VALSET_PM_RAM[] = {0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0xd0, 0x20, 0x02, 0x02, 0x00, 0xd0, 0x40, - 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0xd0, 0x30, 0x01, 0x00, 0x08, 0x00, 0xd0, - 0x10, 0x01, 0x09, 0x00, 0xd0, 0x10, 0x01, 0x10, 0x00, 0xd0, 0x10, 0x01}; -const uint8_t GPS::_message_VALSET_PM_BBR[] = {0x00, 0x02, 0x00, 0x00, 0x01, 0x00, 0xd0, 0x20, 0x02, 0x02, 0x00, 0xd0, 0x40, - 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0xd0, 0x30, 0x01, 0x00, 0x08, 0x00, 0xd0, - 0x10, 0x01, 0x09, 0x00, 0xd0, 0x10, 0x01, 0x10, 0x00, 0xd0, 0x10, 0x01}; +static const uint8_t _message_VALSET_PM_RAM[] = {0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0xd0, 0x20, 0x02, 0x02, 0x00, 0xd0, 0x40, + 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0xd0, 0x30, 0x01, 0x00, 0x08, 0x00, 0xd0, + 0x10, 0x01, 0x09, 0x00, 0xd0, 0x10, 0x01, 0x10, 0x00, 0xd0, 0x10, 0x01}; +static const uint8_t _message_VALSET_PM_BBR[] = {0x00, 0x02, 0x00, 0x00, 0x01, 0x00, 0xd0, 0x20, 0x02, 0x02, 0x00, 0xd0, 0x40, + 0x05, 0x00, 0x00, 0x00, 0x05, 0x00, 0xd0, 0x30, 0x01, 0x00, 0x08, 0x00, 0xd0, + 0x10, 0x01, 0x09, 0x00, 0xd0, 0x10, 0x01, 0x10, 0x00, 0xd0, 0x10, 0x01}; /* CFG-ITFM replaced by 5 valset messages which can be combined into one for RAM and one for BBR @@ -394,10 +396,10 @@ CFG-ITFM replaced by 5 valset messages which can be combined into one for RAM an b5 62 06 8a 0e 00 00 01 00 00 0d 00 41 10 01 13 00 41 10 01 63 c6 */ -const uint8_t GPS::_message_VALSET_ITFM_RAM[] = {0x00, 0x01, 0x00, 0x00, 0x0d, 0x00, 0x41, - 0x10, 0x01, 0x13, 0x00, 0x41, 0x10, 0x01}; -const uint8_t GPS::_message_VALSET_ITFM_BBR[] = {0x00, 0x02, 0x00, 0x00, 0x0d, 0x00, 0x41, - 0x10, 0x01, 0x13, 0x00, 0x41, 0x10, 0x01}; +static const uint8_t _message_VALSET_ITFM_RAM[] = {0x00, 0x01, 0x00, 0x00, 0x0d, 0x00, 0x41, + 0x10, 0x01, 0x13, 0x00, 0x41, 0x10, 0x01}; +static const uint8_t _message_VALSET_ITFM_BBR[] = {0x00, 0x02, 0x00, 0x00, 0x0d, 0x00, 0x41, + 0x10, 0x01, 0x13, 0x00, 0x41, 0x10, 0x01}; // Turn off all NMEA messages: // Ram layer config message: @@ -407,13 +409,13 @@ const uint8_t GPS::_message_VALSET_ITFM_BBR[] = {0x00, 0x02, 0x00, 0x00, 0x0d, 0 // BBR layer config message: // b5 62 06 8a 13 00 00 02 00 00 ca 00 91 20 00 c5 00 91 20 00 b1 00 91 20 00 f8 4e -const uint8_t GPS::_message_VALSET_DISABLE_NMEA_RAM[] = { +static const uint8_t _message_VALSET_DISABLE_NMEA_RAM[] = { /*0x00, 0x01, 0x00, 0x00, 0xca, 0x00, 0x91, 0x20, 0x00, 0xc5, 0x00, 0x91, 0x20, 0x00, 0xb1, 0x00, 0x91, 0x20, 0x00 */ 0x00, 0x01, 0x00, 0x00, 0xc0, 0x00, 0x91, 0x20, 0x00, 0xca, 0x00, 0x91, 0x20, 0x00, 0xc5, 0x00, 0x91, 0x20, 0x00, 0xac, 0x00, 0x91, 0x20, 0x00, 0xb1, 0x00, 0x91, 0x20, 0x00, 0xbb, 0x00, 0x91, 0x20, 0x00}; -const uint8_t GPS::_message_VALSET_DISABLE_NMEA_BBR[] = {0x00, 0x02, 0x00, 0x00, 0xca, 0x00, 0x91, 0x20, 0x00, 0xc5, - 0x00, 0x91, 0x20, 0x00, 0xb1, 0x00, 0x91, 0x20, 0x00}; +static const uint8_t _message_VALSET_DISABLE_NMEA_BBR[] = {0x00, 0x02, 0x00, 0x00, 0xca, 0x00, 0x91, 0x20, 0x00, 0xc5, + 0x00, 0x91, 0x20, 0x00, 0xb1, 0x00, 0x91, 0x20, 0x00}; // Turn off text info messages: // Ram layer config message: @@ -432,17 +434,17 @@ const uint8_t GPS::_message_VALSET_DISABLE_NMEA_BBR[] = {0x00, 0x02, 0x00, 0x00, // b5 62 06 8a 0e 00 00 04 00 00 bb 00 91 20 01 ac 00 91 20 01 6d b6 // Doing this for the FLASH layer isn't really required since we save the config to flash later -const uint8_t GPS::_message_VALSET_DISABLE_TXT_INFO_RAM[] = {0x00, 0x01, 0x00, 0x00, 0x07, 0x00, 0x92, 0x20, 0x03}; -const uint8_t GPS::_message_VALSET_DISABLE_TXT_INFO_BBR[] = {0x00, 0x02, 0x00, 0x00, 0x07, 0x00, 0x92, 0x20, 0x03}; +static const uint8_t _message_VALSET_DISABLE_TXT_INFO_RAM[] = {0x00, 0x01, 0x00, 0x00, 0x07, 0x00, 0x92, 0x20, 0x03}; +static const uint8_t _message_VALSET_DISABLE_TXT_INFO_BBR[] = {0x00, 0x02, 0x00, 0x00, 0x07, 0x00, 0x92, 0x20, 0x03}; -const uint8_t GPS::_message_VALSET_ENABLE_NMEA_RAM[] = {0x00, 0x01, 0x00, 0x00, 0xbb, 0x00, 0x91, - 0x20, 0x01, 0xac, 0x00, 0x91, 0x20, 0x01}; -const uint8_t GPS::_message_VALSET_ENABLE_NMEA_BBR[] = {0x00, 0x02, 0x00, 0x00, 0xbb, 0x00, 0x91, - 0x20, 0x01, 0xac, 0x00, 0x91, 0x20, 0x01}; -const uint8_t GPS::_message_VALSET_DISABLE_SBAS_RAM[] = {0x00, 0x01, 0x00, 0x00, 0x20, 0x00, 0x31, - 0x10, 0x00, 0x05, 0x00, 0x31, 0x10, 0x00}; -const uint8_t GPS::_message_VALSET_DISABLE_SBAS_BBR[] = {0x00, 0x02, 0x00, 0x00, 0x20, 0x00, 0x31, - 0x10, 0x00, 0x05, 0x00, 0x31, 0x10, 0x00}; +static const uint8_t _message_VALSET_ENABLE_NMEA_RAM[] = {0x00, 0x01, 0x00, 0x00, 0xbb, 0x00, 0x91, + 0x20, 0x01, 0xac, 0x00, 0x91, 0x20, 0x01}; +static const uint8_t _message_VALSET_ENABLE_NMEA_BBR[] = {0x00, 0x02, 0x00, 0x00, 0xbb, 0x00, 0x91, + 0x20, 0x01, 0xac, 0x00, 0x91, 0x20, 0x01}; +static const uint8_t _message_VALSET_DISABLE_SBAS_RAM[] = {0x00, 0x01, 0x00, 0x00, 0x20, 0x00, 0x31, + 0x10, 0x00, 0x05, 0x00, 0x31, 0x10, 0x00}; +static const uint8_t _message_VALSET_DISABLE_SBAS_BBR[] = {0x00, 0x02, 0x00, 0x00, 0x20, 0x00, 0x31, + 0x10, 0x00, 0x05, 0x00, 0x31, 0x10, 0x00}; /* Operational issues with the M10: @@ -475,4 +477,4 @@ b5 62 06 8a 0e 00 00 01 00 00 20 00 31 10 00 05 00 31 10 00 46 87 BBR layer config message: b5 62 06 8a 0e 00 00 02 00 00 20 00 31 10 00 05 00 31 10 00 47 94 -*/ \ No newline at end of file +*/ From 7c2b6778cb427ed434d1c79241a0084e13c470a3 Mon Sep 17 00:00:00 2001 From: Tomas Dubec Date: Mon, 25 Nov 2024 13:12:19 +0100 Subject: [PATCH 047/101] enable MQTT with TLS on RPi picow (#5442) Co-authored-by: Ben Meadors --- src/mqtt/MQTT.cpp | 2 +- src/mqtt/MQTT.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mqtt/MQTT.cpp b/src/mqtt/MQTT.cpp index 967b7ba50..967db04d6 100644 --- a/src/mqtt/MQTT.cpp +++ b/src/mqtt/MQTT.cpp @@ -345,7 +345,7 @@ void MQTT::reconnect() mqttPassword = moduleConfig.mqtt.password; } #if HAS_WIFI && !defined(ARCH_PORTDUINO) -#if !defined(CONFIG_IDF_TARGET_ESP32C6) && !defined(RPI_PICO) +#if !defined(CONFIG_IDF_TARGET_ESP32C6) if (moduleConfig.mqtt.tls_enabled) { // change default for encrypted to 8883 try { diff --git a/src/mqtt/MQTT.h b/src/mqtt/MQTT.h index fcefb94a2..7e0378238 100644 --- a/src/mqtt/MQTT.h +++ b/src/mqtt/MQTT.h @@ -35,7 +35,7 @@ class MQTT : private concurrency::OSThread #if HAS_WIFI WiFiClient mqttClient; #if !defined(ARCH_PORTDUINO) -#if defined(ESP_ARDUINO_VERSION_MAJOR) && ESP_ARDUINO_VERSION_MAJOR < 3 +#if (defined(ESP_ARDUINO_VERSION_MAJOR) && ESP_ARDUINO_VERSION_MAJOR < 3) || defined(RPI_PICO) WiFiClientSecure wifiSecureClient; #endif #endif @@ -130,4 +130,4 @@ class MQTT : private concurrency::OSThread void mqttInit(); -extern MQTT *mqtt; \ No newline at end of file +extern MQTT *mqtt; From 58c957f2c7e73c8f6ab77a12520918900f52a2d6 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Mon, 25 Nov 2024 06:53:05 -0600 Subject: [PATCH 048/101] Don't powersave on Wifi (#5443) * Don't go into light sleep with wifi enabled * Move * Trunk --- src/PowerFSM.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/PowerFSM.cpp b/src/PowerFSM.cpp index 00dd6c942..4c4d203c2 100644 --- a/src/PowerFSM.cpp +++ b/src/PowerFSM.cpp @@ -19,6 +19,10 @@ #include "sleep.h" #include "target_specific.h" +#if HAS_WIFI && !defined(ARCH_PORTDUINO) +#include "mesh/wifi/WiFiAPClient.h" +#endif + #ifndef SLEEP_TIME #define SLEEP_TIME 30 #endif @@ -377,9 +381,9 @@ void PowerFSM_setup() // We never enter light-sleep or NB states on NRF52 (because the CPU uses so little power normally) #ifdef ARCH_ESP32 // See: https://github.com/meshtastic/firmware/issues/1071 - // Don't add power saving transitions if we are a power saving tracker or sensor. Sleep will be initiated through the - // modules - if ((isRouter || config.power.is_power_saving) && !isTrackerOrSensor) { + // Don't add power saving transitions if we are a power saving tracker or sensor or have Wifi enabled. Sleep will be initiated + // through the modules + if ((isRouter || config.power.is_power_saving) && !isWifiAvailable() && !isTrackerOrSensor) { powerFSM.add_timed_transition(&stateNB, &stateLS, Default::getConfiguredOrDefaultMs(config.power.min_wake_secs, default_min_wake_secs), NULL, "Min wake timeout"); From d5af8f0a9714a6f3193b2a90e2ee30e9f49ce94e Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Mon, 25 Nov 2024 21:09:55 -0600 Subject: [PATCH 049/101] Revert "Seems like the last DIY board that's not "extra" (#5420)" (#5446) This reverts commit e6fb6b115aebb12b31fb93ed9d1508a6109b2f03. --- variants/diy/platformio.ini | 1 - 1 file changed, 1 deletion(-) diff --git a/variants/diy/platformio.ini b/variants/diy/platformio.ini index 83e2175c8..00ff88da2 100644 --- a/variants/diy/platformio.ini +++ b/variants/diy/platformio.ini @@ -2,7 +2,6 @@ [env:meshtastic-diy-v1] extends = esp32_base board = esp32doit-devkit-v1 -board_level = extra board_check = true build_flags = ${esp32_base.build_flags} From ae4f54224ed21ca5d2a7b9c8706d74c9a6b955e5 Mon Sep 17 00:00:00 2001 From: Jonathan Bennett Date: Mon, 25 Nov 2024 22:49:13 -0600 Subject: [PATCH 050/101] Actually gunzip all the files when building a .deb (#5449) --- .github/workflows/package_amd64.yml | 2 +- .github/workflows/package_raspbian.yml | 2 +- .github/workflows/package_raspbian_armv7l.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/package_amd64.yml b/.github/workflows/package_amd64.yml index 4f6636712..c11566deb 100644 --- a/.github/workflows/package_amd64.yml +++ b/.github/workflows/package_amd64.yml @@ -58,7 +58,7 @@ jobs: if [ -d .debpkg/usr/share/doc/meshtasticd/web/build ]; then mv .debpkg/usr/share/doc/meshtasticd/web/build/* .debpkg/usr/share/doc/meshtasticd/web/; fi if [ -d .debpkg/usr/share/doc/meshtasticd/web/build ]; then rmdir .debpkg/usr/share/doc/meshtasticd/web/build; fi if [ -d .debpkg/usr/share/doc/meshtasticd/web/.DS_Store]; then rm -f .debpkg/usr/share/doc/meshtasticd/web/.DS_Store; fi - gunzip .debpkg/usr/share/doc/meshtasticd/web/*.gz + gunzip .debpkg/usr/share/doc/meshtasticd/web/ -r cp release/meshtasticd_linux_x86_64 .debpkg/usr/sbin/meshtasticd cp bin/config-dist.yaml .debpkg/etc/meshtasticd/config.yaml cp bin/config.d/* .debpkg/etc/meshtasticd/available.d/ diff --git a/.github/workflows/package_raspbian.yml b/.github/workflows/package_raspbian.yml index d9b12d6da..56b683fdd 100644 --- a/.github/workflows/package_raspbian.yml +++ b/.github/workflows/package_raspbian.yml @@ -58,7 +58,7 @@ jobs: if [ -d .debpkg/usr/share/doc/meshtasticd/web/build ]; then mv .debpkg/usr/share/doc/meshtasticd/web/build/* .debpkg/usr/share/doc/meshtasticd/web/; fi if [ -d .debpkg/usr/share/doc/meshtasticd/web/build ]; then rmdir .debpkg/usr/share/doc/meshtasticd/web/build; fi if [ -d .debpkg/usr/share/doc/meshtasticd/web/.DS_Store]; then rm -f .debpkg/usr/share/doc/meshtasticd/web/.DS_Store; fi - gunzip .debpkg/usr/share/doc/meshtasticd/web/*.gz + gunzip .debpkg/usr/share/doc/meshtasticd/web/ -r cp release/meshtasticd_linux_aarch64 .debpkg/usr/sbin/meshtasticd cp bin/config-dist.yaml .debpkg/etc/meshtasticd/config.yaml cp bin/config.d/* .debpkg/etc/meshtasticd/available.d/ diff --git a/.github/workflows/package_raspbian_armv7l.yml b/.github/workflows/package_raspbian_armv7l.yml index e19df9d17..663903e10 100644 --- a/.github/workflows/package_raspbian_armv7l.yml +++ b/.github/workflows/package_raspbian_armv7l.yml @@ -58,7 +58,7 @@ jobs: if [ -d .debpkg/usr/share/doc/meshtasticd/web/build ]; then mv .debpkg/usr/share/doc/meshtasticd/web/build/* .debpkg/usr/share/doc/meshtasticd/web/; fi if [ -d .debpkg/usr/share/doc/meshtasticd/web/build ]; then rmdir .debpkg/usr/share/doc/meshtasticd/web/build; fi if [ -d .debpkg/usr/share/doc/meshtasticd/web/.DS_Store]; then rm -f .debpkg/usr/share/doc/meshtasticd/web/.DS_Store; fi - gunzip .debpkg/usr/share/doc/meshtasticd/web/*.gz + gunzip .debpkg/usr/share/doc/meshtasticd/web/ -r cp release/meshtasticd_linux_armv7l .debpkg/usr/sbin/meshtasticd cp bin/config-dist.yaml .debpkg/etc/meshtasticd/config.yaml cp bin/config.d/* .debpkg/etc/meshtasticd/available.d/ From 09286a3beb42ef1484e2a5759780a8410def46fc Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 26 Nov 2024 08:32:02 -0600 Subject: [PATCH 051/101] [create-pull-request] automated change (#5457) Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com> --- protobufs | 2 +- src/mesh/generated/meshtastic/mesh.pb.h | 12 ++++++------ src/mesh/generated/meshtastic/storeforward.pb.h | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/protobufs b/protobufs index c952f8a4c..02e6576ef 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit c952f8a4c1c30f724743ee322dd3ec3ec2f934c4 +Subproject commit 02e6576efaa2f691be9504b8c1c6261703f7a277 diff --git a/src/mesh/generated/meshtastic/mesh.pb.h b/src/mesh/generated/meshtastic/mesh.pb.h index 3e195e7f5..a173adb4d 100644 --- a/src/mesh/generated/meshtastic/mesh.pb.h +++ b/src/mesh/generated/meshtastic/mesh.pb.h @@ -229,7 +229,7 @@ typedef enum _meshtastic_Constants { /* From mesh.options note: this payload length is ONLY the bytes that are sent inside of the Data protobuf (excluding protobuf overhead). The 16 byte header is outside of this envelope */ - meshtastic_Constants_DATA_PAYLOAD_LEN = 237 + meshtastic_Constants_DATA_PAYLOAD_LEN = 233 } meshtastic_Constants; /* Error codes for critical errors @@ -603,7 +603,7 @@ typedef struct _meshtastic_Routing { }; } meshtastic_Routing; -typedef PB_BYTES_ARRAY_T(237) meshtastic_Data_payload_t; +typedef PB_BYTES_ARRAY_T(233) meshtastic_Data_payload_t; /* (Formerly called SubPacket) The payload portion fo a packet, this is the actual bytes that are sent inside a radio packet (because from/to are broken out by the comms library) */ @@ -882,7 +882,7 @@ typedef struct _meshtastic_FileInfo { uint32_t size_bytes; } meshtastic_FileInfo; -typedef PB_BYTES_ARRAY_T(237) meshtastic_Compressed_data_t; +typedef PB_BYTES_ARRAY_T(233) meshtastic_Compressed_data_t; /* Compressed message payload */ typedef struct _meshtastic_Compressed { /* PortNum to determine the how to handle the compressed payload. */ @@ -1730,14 +1730,14 @@ extern const pb_msgdesc_t meshtastic_ChunkedPayloadResponse_msg; #define MESHTASTIC_MESHTASTIC_MESH_PB_H_MAX_SIZE meshtastic_FromRadio_size #define meshtastic_ChunkedPayload_size 245 #define meshtastic_ClientNotification_size 415 -#define meshtastic_Compressed_size 243 -#define meshtastic_Data_size 273 +#define meshtastic_Compressed_size 239 +#define meshtastic_Data_size 269 #define meshtastic_DeviceMetadata_size 54 #define meshtastic_FileInfo_size 236 #define meshtastic_FromRadio_size 510 #define meshtastic_Heartbeat_size 0 #define meshtastic_LogRecord_size 426 -#define meshtastic_MeshPacket_size 375 +#define meshtastic_MeshPacket_size 371 #define meshtastic_MqttClientProxyMessage_size 501 #define meshtastic_MyNodeInfo_size 77 #define meshtastic_NeighborInfo_size 258 diff --git a/src/mesh/generated/meshtastic/storeforward.pb.h b/src/mesh/generated/meshtastic/storeforward.pb.h index 71f2fcad5..44ffd098c 100644 --- a/src/mesh/generated/meshtastic/storeforward.pb.h +++ b/src/mesh/generated/meshtastic/storeforward.pb.h @@ -91,7 +91,7 @@ typedef struct _meshtastic_StoreAndForward_Heartbeat { uint32_t secondary; } meshtastic_StoreAndForward_Heartbeat; -typedef PB_BYTES_ARRAY_T(237) meshtastic_StoreAndForward_text_t; +typedef PB_BYTES_ARRAY_T(233) meshtastic_StoreAndForward_text_t; /* TODO: REPLACE */ typedef struct _meshtastic_StoreAndForward { /* TODO: REPLACE */ @@ -211,7 +211,7 @@ extern const pb_msgdesc_t meshtastic_StoreAndForward_Heartbeat_msg; #define meshtastic_StoreAndForward_Heartbeat_size 12 #define meshtastic_StoreAndForward_History_size 18 #define meshtastic_StoreAndForward_Statistics_size 50 -#define meshtastic_StoreAndForward_size 242 +#define meshtastic_StoreAndForward_size 238 #ifdef __cplusplus } /* extern "C" */ From fe86c40145cf1fa5314e2d16d3d872cfbbd05dcb Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Tue, 26 Nov 2024 13:59:50 -0600 Subject: [PATCH 052/101] Cleanup i2c scan logs and macro to save some bytes and remain consistent (#5455) * Cleanup i2c scan logs and macro to save some bytes and remain consistent * Functions are better than macros * Exclude i2c scan for STM32 * Useless log --- src/detect/ScanI2CTwoWire.cpp | 135 +++++++++++++++++----------------- src/detect/ScanI2CTwoWire.h | 2 + src/main.cpp | 87 +++++++++++----------- src/main.h | 7 ++ 4 files changed, 121 insertions(+), 110 deletions(-) diff --git a/src/detect/ScanI2CTwoWire.cpp b/src/detect/ScanI2CTwoWire.cpp index 55f13c5a0..cd0c3d144 100644 --- a/src/detect/ScanI2CTwoWire.cpp +++ b/src/detect/ScanI2CTwoWire.cpp @@ -72,10 +72,10 @@ ScanI2C::DeviceType ScanI2CTwoWire::probeOLED(ScanI2C::DeviceAddress addr) const r &= 0x0f; if (r == 0x08 || r == 0x00) { - LOG_INFO("sh1106 display found"); + logFoundDevice("SH1106", (uint8_t)addr.address); o_probe = SCREEN_SH1106; // SH1106 } else if (r == 0x03 || r == 0x04 || r == 0x06 || r == 0x07) { - LOG_INFO("ssd1306 display found"); + logFoundDevice("SSD1306", (uint8_t)addr.address); o_probe = SCREEN_SSD1306; // SSD1306 } c++; @@ -129,7 +129,6 @@ uint16_t ScanI2CTwoWire::getRegisterValue(const ScanI2CTwoWire::RegisterLocation i2cBus->endTransmission(); delay(20); i2cBus->requestFrom(registerLocation.i2cAddress.address, responseWidth); - LOG_DEBUG("Wire.available() = %d", i2cBus->available()); if (i2cBus->available() == 2) { // Read MSB, then LSB value = (uint16_t)i2cBus->read() << 8; @@ -142,7 +141,7 @@ uint16_t ScanI2CTwoWire::getRegisterValue(const ScanI2CTwoWire::RegisterLocation #define SCAN_SIMPLE_CASE(ADDR, T, ...) \ case ADDR: \ - LOG_INFO(__VA_ARGS__); \ + logFoundDevice(__VA_ARGS__); \ type = T; \ break; @@ -184,9 +183,9 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize) for (addr.address = 8; addr.address < 120; addr.address++) { if (asize != 0) { - if (!in_array(address, asize, addr.address)) + if (!in_array(address, asize, (uint8_t)addr.address)) continue; - LOG_DEBUG("Scan address 0x%x", addr.address); + LOG_DEBUG("Scan address 0x%x", (uint8_t)addr.address); } i2cBus->beginTransmission(addr.address); #ifdef ARCH_PORTDUINO @@ -199,8 +198,6 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize) #endif type = NONE; if (err == 0) { - LOG_DEBUG("I2C device found at address 0x%x", addr.address); - switch (addr.address) { case SSD1306_ADDRESS: type = probeOLED(addr); @@ -227,7 +224,7 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize) case RV3028_RTC: // foundDevices[addr] = RTC_RV3028; type = RTC_RV3028; - LOG_INFO("RV3028 RTC found"); + logFoundDevice("RV3028", (uint8_t)addr.address); rtc.initI2C(*i2cBus); rtc.writeToRegister(0x35, 0x07); // no Clkout rtc.writeToRegister(0x37, 0xB4); @@ -235,7 +232,7 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize) #endif #ifdef PCF8563_RTC - SCAN_SIMPLE_CASE(PCF8563_RTC, RTC_PCF8563, "PCF8563 RTC found") + SCAN_SIMPLE_CASE(PCF8563_RTC, RTC_PCF8563, "PCF8563", (uint8_t)addr.address) #endif case CARDKB_ADDR: @@ -243,50 +240,50 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize) registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x04), 1); if (registerValue == 0x02) { // KEYPAD_VERSION - LOG_INFO("RAK14004 found"); + logFoundDevice("RAK14004", (uint8_t)addr.address); type = RAK14004; } else { - LOG_INFO("m5 cardKB found"); + logFoundDevice("M5 cardKB", (uint8_t)addr.address); type = CARDKB; } break; - SCAN_SIMPLE_CASE(TDECK_KB_ADDR, TDECKKB, "T-Deck keyboard found"); - SCAN_SIMPLE_CASE(BBQ10_KB_ADDR, BBQ10KB, "BB Q10 keyboard found"); + SCAN_SIMPLE_CASE(TDECK_KB_ADDR, TDECKKB, "T-Deck keyboard", (uint8_t)addr.address); + SCAN_SIMPLE_CASE(BBQ10_KB_ADDR, BBQ10KB, "BB Q10", (uint8_t)addr.address); - SCAN_SIMPLE_CASE(ST7567_ADDRESS, SCREEN_ST7567, "st7567 display found"); + SCAN_SIMPLE_CASE(ST7567_ADDRESS, SCREEN_ST7567, "ST7567", (uint8_t)addr.address); #ifdef HAS_NCP5623 - SCAN_SIMPLE_CASE(NCP5623_ADDR, NCP5623, "NCP5623 RGB LED found"); + SCAN_SIMPLE_CASE(NCP5623_ADDR, NCP5623, "NCP5623", (uint8_t)addr.address); #endif #ifdef HAS_PMU - SCAN_SIMPLE_CASE(XPOWERS_AXP192_AXP2101_ADDRESS, PMU_AXP192_AXP2101, "axp192/axp2101 PMU found") + SCAN_SIMPLE_CASE(XPOWERS_AXP192_AXP2101_ADDRESS, PMU_AXP192_AXP2101, "AXP192/AXP2101", (uint8_t)addr.address) #endif case BME_ADDR: case BME_ADDR_ALTERNATE: registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0xD0), 1); // GET_ID switch (registerValue) { case 0x61: - LOG_INFO("BME-680 sensor found at address 0x%x", (uint8_t)addr.address); + logFoundDevice("BME680", (uint8_t)addr.address); type = BME_680; break; case 0x60: - LOG_INFO("BME-280 sensor found at address 0x%x", (uint8_t)addr.address); + logFoundDevice("BME280", (uint8_t)addr.address); type = BME_280; break; case 0x55: - LOG_INFO("BMP-085 or BMP-180 sensor found at address 0x%x", (uint8_t)addr.address); + logFoundDevice("BMP085/BMP180", (uint8_t)addr.address); type = BMP_085; break; default: registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x00), 1); // GET_ID switch (registerValue) { case 0x50: // BMP-388 should be 0x50 - LOG_INFO("BMP-388 sensor found at address 0x%x", (uint8_t)addr.address); + logFoundDevice("BMP-388", (uint8_t)addr.address); type = BMP_3XX; break; case 0x58: // BMP-280 should be 0x58 default: - LOG_INFO("BMP-280 sensor found at address 0x%x", (uint8_t)addr.address); + logFoundDevice("BMP-280", (uint8_t)addr.address); type = BMP_280; break; } @@ -295,7 +292,7 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize) break; #ifndef HAS_NCP5623 case AHT10_ADDR: - LOG_INFO("AHT10 sensor found at address 0x%x", (uint8_t)addr.address); + logFoundDevice("AHT10", (uint8_t)addr.address); type = AHT10; break; #endif @@ -305,10 +302,10 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize) registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0xFE), 2); LOG_DEBUG("Register MFG_UID: 0x%x", registerValue); if (registerValue == 0x5449) { - LOG_INFO("INA260 sensor found at address 0x%x", (uint8_t)addr.address); + logFoundDevice("INA260", (uint8_t)addr.address); type = INA260; } else { // Assume INA219 if INA260 ID is not found - LOG_INFO("INA219 sensor found at address 0x%x", (uint8_t)addr.address); + logFoundDevice("INA219", (uint8_t)addr.address); type = INA219; } break; @@ -316,7 +313,7 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize) registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0xFE), 2); LOG_DEBUG("Register MFG_UID FE: 0x%x", registerValue); if (registerValue == 0x5449) { - LOG_INFO("INA3221 sensor found at address 0x%x", (uint8_t)addr.address); + logFoundDevice("INA3221", (uint8_t)addr.address); type = INA3221; } else { /* check the first 2 bytes of the 6 byte response register @@ -331,7 +328,7 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize) registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x05), 2); LOG_DEBUG("Register MFG_UID 05: 0x%x", registerValue); if (registerValue == 0x5305) { - LOG_INFO("DFRobot Lark weather station found at address 0x%x", (uint8_t)addr.address); + logFoundDevice("DFRobot Lark", (uint8_t)addr.address); type = DFROBOT_LARK; } // else: probably a RAK12500/UBLOX GPS on I2C @@ -346,7 +343,7 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize) registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x00), 2); if (registerValue == 0x8700) { type = STK8BAXX; - LOG_INFO("STK8BAXX accelerometer found"); + logFoundDevice("STK8BAXX", (uint8_t)addr.address); break; } #endif @@ -355,7 +352,7 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize) registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x07), 2); if (registerValue == 0x0400) { type = MCP9808; - LOG_INFO("MCP9808 sensor found"); + logFoundDevice("MCP9808", (uint8_t)addr.address); break; } @@ -363,7 +360,7 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize) registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x0F), 2); if (registerValue == 0x3300 || registerValue == 0x3333) { // RAK4631 WisBlock has LIS3DH register at 0x3333 type = LIS3DH; - LOG_INFO("LIS3DH accelerometer found"); + logFoundDevice("LIS3DH", (uint8_t)addr.address); } break; } @@ -371,93 +368,92 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize) registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x89), 2); if (registerValue == 0x11a2 || registerValue == 0x11da || registerValue == 0xe9c) { type = SHT4X; - LOG_INFO("SHT4X sensor found"); + logFoundDevice("SHT4X", (uint8_t)addr.address); } else if (getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x7E), 2) == 0x5449) { type = OPT3001; - LOG_INFO("OPT3001 light sensor found"); + logFoundDevice("OPT3001", (uint8_t)addr.address); } else { type = SHT31; - LOG_INFO("SHT31 sensor found"); + logFoundDevice("SHT31", (uint8_t)addr.address); } break; - SCAN_SIMPLE_CASE(SHTC3_ADDR, SHTC3, "SHTC3 sensor found") + SCAN_SIMPLE_CASE(SHTC3_ADDR, SHTC3, "SHTC3", (uint8_t)addr.address) case RCWL9620_ADDR: // get MAX30102 PARTID registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0xFF), 1); if (registerValue == 0x15) { type = MAX30102; - LOG_INFO("MAX30102 Health sensor found"); + logFoundDevice("MAX30102", (uint8_t)addr.address); break; } else { type = RCWL9620; - LOG_INFO("RCWL9620 sensor found"); + logFoundDevice("RCWL9620", (uint8_t)addr.address); } break; case LPS22HB_ADDR_ALT: - SCAN_SIMPLE_CASE(LPS22HB_ADDR, LPS22HB, "LPS22HB sensor found") - - SCAN_SIMPLE_CASE(QMC6310_ADDR, QMC6310, "QMC6310 Highrate 3-Axis magnetic sensor found") + SCAN_SIMPLE_CASE(LPS22HB_ADDR, LPS22HB, "LPS22HB", (uint8_t)addr.address) + SCAN_SIMPLE_CASE(QMC6310_ADDR, QMC6310, "QMC6310", (uint8_t)addr.address) case QMI8658_ADDR: registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x0A), 1); // get ID if (registerValue == 0xC0) { type = BQ24295; - LOG_INFO("BQ24295 PMU found"); + logFoundDevice("BQ24295", (uint8_t)addr.address); break; } registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x0F), 1); // get ID if (registerValue == 0x6A) { type = LSM6DS3; - LOG_INFO("LSM6DS3 accelerometer found at address 0x%x", (uint8_t)addr.address); + logFoundDevice("LSM6DS3", (uint8_t)addr.address); } else { type = QMI8658; - LOG_INFO("QMI8658 Highrate 6-Axis inertial measurement sensor found"); + logFoundDevice("QMI8658", (uint8_t)addr.address); } break; - SCAN_SIMPLE_CASE(QMC5883L_ADDR, QMC5883L, "QMC5883L Highrate 3-Axis magnetic sensor found") - SCAN_SIMPLE_CASE(HMC5883L_ADDR, HMC5883L, "HMC5883L 3-Axis digital compass found") + SCAN_SIMPLE_CASE(QMC5883L_ADDR, QMC5883L, "QMC5883L", (uint8_t)addr.address) + SCAN_SIMPLE_CASE(HMC5883L_ADDR, HMC5883L, "HMC5883L", (uint8_t)addr.address) #ifdef HAS_QMA6100P - SCAN_SIMPLE_CASE(QMA6100P_ADDR, QMA6100P, "QMA6100P accelerometer found") + SCAN_SIMPLE_CASE(QMA6100P_ADDR, QMA6100P, "QMA6100P", (uint8_t)addr.address) #else - SCAN_SIMPLE_CASE(PMSA0031_ADDR, PMSA0031, "PMSA0031 air quality sensor found") + SCAN_SIMPLE_CASE(PMSA0031_ADDR, PMSA0031, "PMSA0031", (uint8_t)addr.address) #endif case BMA423_ADDR: // this can also be LIS3DH_ADDR_ALT registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x0F), 2); if (registerValue == 0x3300 || registerValue == 0x3333) { // RAK4631 WisBlock has LIS3DH register at 0x3333 type = LIS3DH; - LOG_INFO("LIS3DH accelerometer found"); + logFoundDevice("LIS3DH", (uint8_t)addr.address); } else { type = BMA423; - LOG_INFO("BMA423 accelerometer found"); + logFoundDevice("BMA423", (uint8_t)addr.address); } break; - SCAN_SIMPLE_CASE(LSM6DS3_ADDR, LSM6DS3, "LSM6DS3 accelerometer found at address 0x%x", (uint8_t)addr.address); - SCAN_SIMPLE_CASE(TCA9535_ADDR, TCA9535, "TCA9535 I2C expander found"); - SCAN_SIMPLE_CASE(TCA9555_ADDR, TCA9555, "TCA9555 I2C expander found"); - SCAN_SIMPLE_CASE(VEML7700_ADDR, VEML7700, "VEML7700 light sensor found"); - SCAN_SIMPLE_CASE(TSL25911_ADDR, TSL2591, "TSL2591 light sensor found"); - SCAN_SIMPLE_CASE(OPT3001_ADDR, OPT3001, "OPT3001 light sensor found"); - SCAN_SIMPLE_CASE(MLX90632_ADDR, MLX90632, "MLX90632 IR temp sensor found"); - SCAN_SIMPLE_CASE(NAU7802_ADDR, NAU7802, "NAU7802 based scale found"); - SCAN_SIMPLE_CASE(FT6336U_ADDR, FT6336U, "FT6336U touchscreen found"); - SCAN_SIMPLE_CASE(MAX1704X_ADDR, MAX17048, "MAX17048 lipo fuel gauge found"); + SCAN_SIMPLE_CASE(LSM6DS3_ADDR, LSM6DS3, "LSM6DS3", (uint8_t)addr.address); + SCAN_SIMPLE_CASE(TCA9535_ADDR, TCA9535, "TCA9535", (uint8_t)addr.address); + SCAN_SIMPLE_CASE(TCA9555_ADDR, TCA9555, "TCA9555", (uint8_t)addr.address); + SCAN_SIMPLE_CASE(VEML7700_ADDR, VEML7700, "VEML7700", (uint8_t)addr.address); + SCAN_SIMPLE_CASE(TSL25911_ADDR, TSL2591, "TSL2591", (uint8_t)addr.address); + SCAN_SIMPLE_CASE(OPT3001_ADDR, OPT3001, "OPT3001", (uint8_t)addr.address); + SCAN_SIMPLE_CASE(MLX90632_ADDR, MLX90632, "MLX90632", (uint8_t)addr.address); + SCAN_SIMPLE_CASE(NAU7802_ADDR, NAU7802, "NAU7802", (uint8_t)addr.address); + SCAN_SIMPLE_CASE(FT6336U_ADDR, FT6336U, "FT6336U", (uint8_t)addr.address); + SCAN_SIMPLE_CASE(MAX1704X_ADDR, MAX17048, "MAX17048", (uint8_t)addr.address); #ifdef HAS_TPS65233 - SCAN_SIMPLE_CASE(TPS65233_ADDR, TPS65233, "TPS65233 BIAS-T found"); + SCAN_SIMPLE_CASE(TPS65233_ADDR, TPS65233, "TPS65233", (uint8_t)addr.address); #endif case MLX90614_ADDR_DEF: registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x0e), 1); if (registerValue == 0x5a) { type = MLX90614; - LOG_INFO("MLX90614 IR temp sensor found"); + logFoundDevice("MLX90614", (uint8_t)addr.address); } else { type = MPR121KB; - LOG_INFO("MPR121KB keyboard found"); + logFoundDevice("MPR121KB", (uint8_t)addr.address); } break; @@ -466,15 +462,15 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize) registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x00), 1); if (registerValue == 0xEA) { type = ICM20948; - LOG_INFO("ICM20948 9-dof motion processor found"); + logFoundDevice("ICM20948", (uint8_t)addr.address); break; } else if (addr.address == BMX160_ADDR) { type = BMX160; - LOG_INFO("BMX160 accelerometer found"); + logFoundDevice("BMX160", (uint8_t)addr.address); break; } else { type = MPU6050; - LOG_INFO("MPU6050 accelerometer found"); + logFoundDevice("MPU6050", (uint8_t)addr.address); break; } break; @@ -484,16 +480,16 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize) registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x00), 1); if (registerValue == 0x7D) { type = CGRADSENS; - LOG_INFO("ClimateGuard RadSens Geiger-Muller Sensor found"); + logFoundDevice("ClimateGuard RadSens", (uint8_t)addr.address); break; } break; default: - LOG_INFO("Device found at address 0x%x was not able to be enumerated", addr.address); + LOG_INFO("Device found at address 0x%x was not able to be enumerated", (uint8_t)addr.address); } } else if (err == 4) { - LOG_ERROR("Unknown error at address 0x%x", addr.address); + LOG_ERROR("Unknown error at address 0x%x", (uint8_t)addr.address); } // Check if a type was found for the enumerated device - save, if so @@ -526,4 +522,9 @@ size_t ScanI2CTwoWire::countDevices() const { return foundDevices.size(); } + +void ScanI2CTwoWire::logFoundDevice(const char *device, uint8_t address) +{ + LOG_INFO("%s found at address 0x%x", device, address); +} #endif \ No newline at end of file diff --git a/src/detect/ScanI2CTwoWire.h b/src/detect/ScanI2CTwoWire.h index c8dd96469..e9f242512 100644 --- a/src/detect/ScanI2CTwoWire.h +++ b/src/detect/ScanI2CTwoWire.h @@ -58,5 +58,7 @@ class ScanI2CTwoWire : public ScanI2C uint16_t getRegisterValue(const RegisterLocation &, ResponseWidth) const; DeviceType probeOLED(ScanI2C::DeviceAddress) const; + + static void logFoundDevice(const char *device, uint8_t address); }; #endif \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index df18dae98..63c7fd29b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -572,49 +572,37 @@ void setup() LOG_DEBUG("acc_info = %i", acc_info.type); #endif -#define STRING(S) #S - -#define SCANNER_TO_SENSORS_MAP(SCANNER_T, PB_T) \ - { \ - auto found = i2cScanner->find(SCANNER_T); \ - if (found.type != ScanI2C::DeviceType::NONE) { \ - nodeTelemetrySensorsMap[PB_T].first = found.address.address; \ - nodeTelemetrySensorsMap[PB_T].second = i2cScanner->fetchI2CBus(found.address); \ - LOG_DEBUG("found i2c sensor %s", STRING(PB_T)); \ - } \ - } - - SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::BME_680, meshtastic_TelemetrySensorType_BME680) - SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::BME_280, meshtastic_TelemetrySensorType_BME280) - SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::BMP_280, meshtastic_TelemetrySensorType_BMP280) - SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::BMP_3XX, meshtastic_TelemetrySensorType_BMP3XX) - SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::BMP_085, meshtastic_TelemetrySensorType_BMP085) - SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::INA260, meshtastic_TelemetrySensorType_INA260) - SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::INA219, meshtastic_TelemetrySensorType_INA219) - SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::INA3221, meshtastic_TelemetrySensorType_INA3221) - SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::MAX17048, meshtastic_TelemetrySensorType_MAX17048) - SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::MCP9808, meshtastic_TelemetrySensorType_MCP9808) - SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::MCP9808, meshtastic_TelemetrySensorType_MCP9808) - SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::SHT31, meshtastic_TelemetrySensorType_SHT31) - SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::SHTC3, meshtastic_TelemetrySensorType_SHTC3) - SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::LPS22HB, meshtastic_TelemetrySensorType_LPS22) - SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::QMC6310, meshtastic_TelemetrySensorType_QMC6310) - SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::QMI8658, meshtastic_TelemetrySensorType_QMI8658) - SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::QMC5883L, meshtastic_TelemetrySensorType_QMC5883L) - SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::HMC5883L, meshtastic_TelemetrySensorType_QMC5883L) - SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::PMSA0031, meshtastic_TelemetrySensorType_PMSA003I) - SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::RCWL9620, meshtastic_TelemetrySensorType_RCWL9620) - SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::VEML7700, meshtastic_TelemetrySensorType_VEML7700) - SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::TSL2591, meshtastic_TelemetrySensorType_TSL25911FN) - SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::OPT3001, meshtastic_TelemetrySensorType_OPT3001) - SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::MLX90632, meshtastic_TelemetrySensorType_MLX90632) - SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::MLX90614, meshtastic_TelemetrySensorType_MLX90614) - SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::SHT4X, meshtastic_TelemetrySensorType_SHT4X) - SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::AHT10, meshtastic_TelemetrySensorType_AHT10) - SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::DFROBOT_LARK, meshtastic_TelemetrySensorType_DFROBOT_LARK) - SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::ICM20948, meshtastic_TelemetrySensorType_ICM20948) - SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::MAX30102, meshtastic_TelemetrySensorType_MAX30102) - SCANNER_TO_SENSORS_MAP(ScanI2C::DeviceType::CGRADSENS, meshtastic_TelemetrySensorType_RADSENS) + scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::BME_680, meshtastic_TelemetrySensorType_BME680); + scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::BME_280, meshtastic_TelemetrySensorType_BME280); + scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::BMP_280, meshtastic_TelemetrySensorType_BMP280); + scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::BMP_3XX, meshtastic_TelemetrySensorType_BMP3XX); + scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::BMP_085, meshtastic_TelemetrySensorType_BMP085); + scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::INA260, meshtastic_TelemetrySensorType_INA260); + scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::INA219, meshtastic_TelemetrySensorType_INA219); + scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::INA3221, meshtastic_TelemetrySensorType_INA3221); + scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::MAX17048, meshtastic_TelemetrySensorType_MAX17048); + scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::MCP9808, meshtastic_TelemetrySensorType_MCP9808); + scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::MCP9808, meshtastic_TelemetrySensorType_MCP9808); + scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::SHT31, meshtastic_TelemetrySensorType_SHT31); + scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::SHTC3, meshtastic_TelemetrySensorType_SHTC3); + scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::LPS22HB, meshtastic_TelemetrySensorType_LPS22); + scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::QMC6310, meshtastic_TelemetrySensorType_QMC6310); + scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::QMI8658, meshtastic_TelemetrySensorType_QMI8658); + scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::QMC5883L, meshtastic_TelemetrySensorType_QMC5883L); + scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::HMC5883L, meshtastic_TelemetrySensorType_QMC5883L); + scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::PMSA0031, meshtastic_TelemetrySensorType_PMSA003I); + scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::RCWL9620, meshtastic_TelemetrySensorType_RCWL9620); + scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::VEML7700, meshtastic_TelemetrySensorType_VEML7700); + scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::TSL2591, meshtastic_TelemetrySensorType_TSL25911FN); + scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::OPT3001, meshtastic_TelemetrySensorType_OPT3001); + scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::MLX90632, meshtastic_TelemetrySensorType_MLX90632); + scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::MLX90614, meshtastic_TelemetrySensorType_MLX90614); + scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::SHT4X, meshtastic_TelemetrySensorType_SHT4X); + scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::AHT10, meshtastic_TelemetrySensorType_AHT10); + scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::DFROBOT_LARK, meshtastic_TelemetrySensorType_DFROBOT_LARK); + scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::ICM20948, meshtastic_TelemetrySensorType_ICM20948); + scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::MAX30102, meshtastic_TelemetrySensorType_MAX30102); + scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::CGRADSENS, meshtastic_TelemetrySensorType_RADSENS); i2cScanner.reset(); #endif @@ -1192,6 +1180,19 @@ extern meshtastic_DeviceMetadata getDeviceMetadata() #endif return deviceMetadata; } + +#if !MESHTASTIC_EXCLUDE_I2C +void scannerToSensorsMap(const std::unique_ptr &i2cScanner, ScanI2C::DeviceType deviceType, + meshtastic_TelemetrySensorType sensorType) +{ + auto found = i2cScanner->find(deviceType); + if (found.type != ScanI2C::DeviceType::NONE) { + nodeTelemetrySensorsMap[sensorType].first = found.address.address; + nodeTelemetrySensorsMap[sensorType].second = i2cScanner->fetchI2CBus(found.address); + } +} +#endif + #ifndef PIO_UNIT_TESTING void loop() { diff --git a/src/main.h b/src/main.h index 5722f7cf0..1816aef53 100644 --- a/src/main.h +++ b/src/main.h @@ -21,6 +21,9 @@ extern NimbleBluetooth *nimbleBluetooth; #include "NRF52Bluetooth.h" extern NRF52Bluetooth *nrf52Bluetooth; #endif +#if !MESHTASTIC_EXCLUDE_I2C +#include "detect/ScanI2CTwoWire.h" +#endif #if ARCH_PORTDUINO extern HardwareSPI *DisplaySPI; @@ -84,6 +87,10 @@ extern bool pauseBluetoothLogging; void nrf52Setup(), esp32Setup(), nrf52Loop(), esp32Loop(), rp2040Setup(), clearBonds(), enterDfuMode(); meshtastic_DeviceMetadata getDeviceMetadata(); +#if !MESHTASTIC_EXCLUDE_I2C +void scannerToSensorsMap(const std::unique_ptr &i2cScanner, ScanI2C::DeviceType deviceType, + meshtastic_TelemetrySensorType sensorType); +#endif // We default to 4MHz SPI, SPI mode 0 extern SPISettings spiSettings; \ No newline at end of file From 474f9b5bfbf53be509a5bf8b0e8609979a1103c8 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Tue, 26 Nov 2024 14:00:10 -0600 Subject: [PATCH 053/101] Clean up some inline functions (#5454) --- src/gps/GeoCoord.cpp | 20 ++++++++++++++++++++ src/gps/GeoCoord.h | 29 ++++++----------------------- src/graphics/Screen.cpp | 6 +++--- src/mesh/MeshService.cpp | 2 +- src/mesh/NodeDB.cpp | 7 +++++++ src/mesh/NodeDB.h | 9 ++------- src/mesh/aes-ccm.cpp | 2 +- src/modules/PositionModule.cpp | 8 ++++---- src/modules/SerialModule.cpp | 6 +++--- src/modules/WaypointModule.cpp | 2 +- 10 files changed, 48 insertions(+), 43 deletions(-) diff --git a/src/gps/GeoCoord.cpp b/src/gps/GeoCoord.cpp index 5abb25a06..6d1f2da6d 100644 --- a/src/gps/GeoCoord.cpp +++ b/src/gps/GeoCoord.cpp @@ -574,3 +574,23 @@ const char *GeoCoord::degreesToBearing(unsigned int degrees) else return "N"; } + +double GeoCoord::pow_neg(double base, double exponent) +{ + if (exponent == 0) { + return 1; + } else if (exponent > 0) { + return pow(base, exponent); + } + return 1 / pow(base, -exponent); +} + +double GeoCoord::toRadians(double deg) +{ + return deg * PI / 180; +} + +double GeoCoord::toDegrees(double r) +{ + return r * 180 / PI; +} \ No newline at end of file diff --git a/src/gps/GeoCoord.h b/src/gps/GeoCoord.h index ecdaf0ec7..658c177b3 100644 --- a/src/gps/GeoCoord.h +++ b/src/gps/GeoCoord.h @@ -13,28 +13,6 @@ #define OLC_CODE_LEN 11 #define DEG_CONVERT (180 / PI) -// Helper functions -// Raises a number to an exponent, handling negative exponents. -static inline double pow_neg(double base, double exponent) -{ - if (exponent == 0) { - return 1; - } else if (exponent > 0) { - return pow(base, exponent); - } - return 1 / pow(base, -exponent); -} - -static inline double toRadians(double deg) -{ - return deg * PI / 180; -} - -static inline double toDegrees(double r) -{ - return r * 180 / PI; -} - // GeoCoord structs/classes // A struct to hold the data for a DMS coordinate. struct DMS { @@ -120,6 +98,11 @@ class GeoCoord static unsigned int bearingToDegrees(const char *bearing); static const char *degreesToBearing(unsigned int degrees); + // Raises a number to an exponent, handling negative exponents. + static double pow_neg(double base, double exponent); + static double toRadians(double deg); + static double toDegrees(double r); + // Point to point conversions int32_t distanceTo(const GeoCoord &pointB); int32_t bearingTo(const GeoCoord &pointB); @@ -162,4 +145,4 @@ class GeoCoord // OLC getter void getOLCCode(char *code) { strncpy(code, _olc.code, OLC_CODE_LEN + 1); } // +1 for null termination -}; +}; \ No newline at end of file diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index a875c11d6..dfef162ba 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -1420,7 +1420,7 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_ } bool hasNodeHeading = false; - if (ourNode && (hasValidPosition(ourNode) || screen->hasHeading())) { + if (ourNode && (nodeDB->hasValidPosition(ourNode) || screen->hasHeading())) { const meshtastic_PositionLite &op = ourNode->position; float myHeading; if (screen->hasHeading()) @@ -1429,7 +1429,7 @@ static void drawNodeInfo(OLEDDisplay *display, OLEDDisplayUiState *state, int16_ myHeading = screen->estimatedHeading(DegD(op.latitude_i), DegD(op.longitude_i)); screen->drawCompassNorth(display, compassX, compassY, myHeading); - if (hasValidPosition(node)) { + if (nodeDB->hasValidPosition(node)) { // display direction toward node hasNodeHeading = true; const meshtastic_PositionLite &p = node->position; @@ -2757,4 +2757,4 @@ int Screen::handleAdminMessage(const meshtastic_AdminMessage *arg) } // namespace graphics #else graphics::Screen::Screen(ScanI2C::DeviceAddress, meshtastic_Config_DisplayConfig_OledType, OLEDDISPLAY_GEOMETRY) {} -#endif // HAS_SCREEN +#endif // HAS_SCREEN \ No newline at end of file diff --git a/src/mesh/MeshService.cpp b/src/mesh/MeshService.cpp index 50a13da6a..8f7717585 100644 --- a/src/mesh/MeshService.cpp +++ b/src/mesh/MeshService.cpp @@ -271,7 +271,7 @@ bool MeshService::trySendPosition(NodeNum dest, bool wantReplies) assert(node); - if (hasValidPosition(node)) { + if (nodeDB->hasValidPosition(node)) { #if HAS_GPS && !MESHTASTIC_EXCLUDE_GPS if (positionModule) { LOG_INFO("Send position ping to 0x%x, wantReplies=%d, channel=%d", dest, wantReplies, node->channel); diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index 44a28eea2..22c32d98d 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -1387,6 +1387,13 @@ meshtastic_NodeInfoLite *NodeDB::getOrCreateMeshNode(NodeNum n) return lite; } +/// Sometimes we will have Position objects that only have a time, so check for +/// valid lat/lon +bool NodeDB::hasValidPosition(const meshtastic_NodeInfoLite *n) +{ + return n->has_position && (n->position.latitude_i != 0 || n->position.longitude_i != 0); +} + /// Record an error that should be reported via analytics void recordCriticalError(meshtastic_CriticalErrorCode code, uint32_t address, const char *filename) { diff --git a/src/mesh/NodeDB.h b/src/mesh/NodeDB.h index 2f9980f14..7e51a1240 100644 --- a/src/mesh/NodeDB.h +++ b/src/mesh/NodeDB.h @@ -165,6 +165,8 @@ class NodeDB localPosition = position; } + bool hasValidPosition(const meshtastic_NodeInfoLite *n); + private: uint32_t lastNodeDbSave = 0; // when we last saved our db to flash /// Find a node in our DB, create an empty NodeInfoLite if missing @@ -217,13 +219,6 @@ extern NodeDB *nodeDB; prefs.is_power_saving = True */ -/// Sometimes we will have Position objects that only have a time, so check for -/// valid lat/lon -static inline bool hasValidPosition(const meshtastic_NodeInfoLite *n) -{ - return n->has_position && (n->position.latitude_i != 0 || n->position.longitude_i != 0); -} - /** The current change # for radio settings. Starts at 0 on boot and any time the radio settings * might have changed is incremented. Allows others to detect they might now be on a new channel. */ diff --git a/src/mesh/aes-ccm.cpp b/src/mesh/aes-ccm.cpp index b9af14fdb..8bc2989bf 100644 --- a/src/mesh/aes-ccm.cpp +++ b/src/mesh/aes-ccm.cpp @@ -10,7 +10,7 @@ #include "aes-ccm.h" #if !MESHTASTIC_EXCLUDE_PKI -static inline void WPA_PUT_BE16(uint8_t *a, uint16_t val) +static void WPA_PUT_BE16(uint8_t *a, uint16_t val) { a[0] = val >> 8; a[1] = val & 0xff; diff --git a/src/modules/PositionModule.cpp b/src/modules/PositionModule.cpp index d977cfdec..6285d7aa5 100644 --- a/src/modules/PositionModule.cpp +++ b/src/modules/PositionModule.cpp @@ -389,7 +389,7 @@ int32_t PositionModule::runOnce() } if (lastGpsSend == 0 || msSinceLastSend >= intervalMs) { - if (hasValidPosition(node)) { + if (nodeDB->hasValidPosition(node)) { lastGpsSend = now; lastGpsLatitude = node->position.latitude_i; @@ -403,7 +403,7 @@ int32_t PositionModule::runOnce() } else if (config.position.position_broadcast_smart_enabled) { const meshtastic_NodeInfoLite *node2 = service->refreshLocalMeshNode(); // should guarantee there is now a position - if (hasValidPosition(node2)) { + if (nodeDB->hasValidPosition(node2)) { // The minimum time (in seconds) that would pass before we are able to send a new position packet. auto smartPosition = getDistanceTraveledSinceLastSend(node->position); @@ -464,7 +464,7 @@ void PositionModule::handleNewPosition() meshtastic_NodeInfoLite *node = nodeDB->getMeshNode(nodeDB->getNodeNum()); const meshtastic_NodeInfoLite *node2 = service->refreshLocalMeshNode(); // should guarantee there is now a position // We limit our GPS broadcasts to a max rate - if (hasValidPosition(node2)) { + if (nodeDB->hasValidPosition(node2)) { auto smartPosition = getDistanceTraveledSinceLastSend(node->position); uint32_t msSinceLastSend = millis() - lastGpsSend; if (smartPosition.hasTraveledOverThreshold && @@ -483,4 +483,4 @@ void PositionModule::handleNewPosition() } } -#endif +#endif \ No newline at end of file diff --git a/src/modules/SerialModule.cpp b/src/modules/SerialModule.cpp index 531be274e..bf53b1748 100644 --- a/src/modules/SerialModule.cpp +++ b/src/modules/SerialModule.cpp @@ -205,7 +205,7 @@ int32_t SerialModule::runOnce() uint32_t readIndex = 0; const meshtastic_NodeInfoLite *tempNodeInfo = nodeDB->readNextMeshNode(readIndex); while (tempNodeInfo != NULL) { - if (tempNodeInfo->has_user && hasValidPosition(tempNodeInfo)) { + if (tempNodeInfo->has_user && nodeDB->hasValidPosition(tempNodeInfo)) { printWPL(outbuf, sizeof(outbuf), tempNodeInfo->position, tempNodeInfo->user.long_name, true); serialPrint->printf("%s", outbuf); } @@ -474,7 +474,7 @@ void SerialModule::processWXSerial() if (windDirPos != NULL) { // Extract data after "=" for WindDir strcpy(windDir, windDirPos + 15); // Add 15 to skip "WindDir = " - double radians = toRadians(strtof(windDir, nullptr)); + double radians = GeoCoord::toRadians(strtof(windDir, nullptr)); dir_sum_sin += sin(radians); dir_sum_cos += cos(radians); dirCount++; @@ -541,7 +541,7 @@ void SerialModule::processWXSerial() double avgCos = dir_sum_cos / dirCount; double avgRadians = atan2(avgSin, avgCos); - float dirAvg = toDegrees(avgRadians); + float dirAvg = GeoCoord::toDegrees(avgRadians); if (dirAvg < 0) { dirAvg += 360.0; diff --git a/src/modules/WaypointModule.cpp b/src/modules/WaypointModule.cpp index 48e0c4242..b8b738309 100644 --- a/src/modules/WaypointModule.cpp +++ b/src/modules/WaypointModule.cpp @@ -126,7 +126,7 @@ void WaypointModule::drawFrame(OLEDDisplay *display, OLEDDisplayUiState *state, } // If our node has a position: - if (ourNode && (hasValidPosition(ourNode) || screen->hasHeading())) { + if (ourNode && (nodeDB->hasValidPosition(ourNode) || screen->hasHeading())) { const meshtastic_PositionLite &op = ourNode->position; float myHeading; if (screen->hasHeading()) From 502a83bb8abd5bc2098aa6c1c940f9b705c8c816 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Tue, 26 Nov 2024 16:39:16 -0600 Subject: [PATCH 054/101] Use isWithinTimespanMs to avoid refererence to NodeDb instance inside of NodeDb (#5453) --- src/mesh/NodeDB.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index 22c32d98d..b529fa934 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -1275,10 +1275,14 @@ bool NodeDB::updateUser(uint32_t nodeId, meshtastic_User &p, uint8_t channelInde powerFSM.trigger(EVENT_NODEDB_UPDATED); notifyObservers(true); // Force an update whether or not our node counts have changed - // We just changed something about the user, store our DB - Throttle::execute( - &lastNodeDbSave, ONE_MINUTE_MS, []() { nodeDB->saveToDisk(SEGMENT_DEVICESTATE); }, - []() { LOG_DEBUG("Defer NodeDB saveToDisk for now"); }); // since we saved less than a minute ago + // We just changed something about a User, + // store our DB unless we just did so less than a minute ago + if (!Throttle::isWithinTimespanMs(lastNodeDbSave, ONE_MINUTE_MS)) { + saveToDisk(SEGMENT_DEVICESTATE); + lastNodeDbSave = millis(); + } else { + LOG_DEBUG("Defer NodeDB saveToDisk for now"); + } } return changed; From 601d912c6f554fd3c7f23017a9eb1362de2bbf8a Mon Sep 17 00:00:00 2001 From: Liam Cottle Date: Wed, 27 Nov 2024 21:45:31 +1300 Subject: [PATCH 055/101] fix cors for meshtasticd to allow use of cross origin clients (#5463) --- src/mesh/raspihttp/PiWebServer.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/mesh/raspihttp/PiWebServer.cpp b/src/mesh/raspihttp/PiWebServer.cpp index f9ba9c235..846d70723 100644 --- a/src/mesh/raspihttp/PiWebServer.cpp +++ b/src/mesh/raspihttp/PiWebServer.cpp @@ -232,9 +232,9 @@ int handleAPIv1ToRadio(const struct _u_request *req, struct _u_response *res, vo ulfius_add_header_to_response(res, "X-Protobuf-Schema", "https://raw.githubusercontent.com/meshtastic/protobufs/master/meshtastic/mesh.proto"); - if (req->http_verb == "OPTIONS") { + if (strcmp(req->http_verb, "OPTIONS") == 0) { ulfius_set_response_properties(res, U_OPT_STATUS, 204); - return U_CALLBACK_CONTINUE; + return U_CALLBACK_COMPLETE; } byte buffer[MAX_TO_FROM_RADIO_SIZE]; @@ -269,6 +269,11 @@ int handleAPIv1FromRadio(const struct _u_request *req, struct _u_response *res, ulfius_add_header_to_response(res, "X-Protobuf-Schema", "https://raw.githubusercontent.com/meshtastic/protobufs/master/meshtastic/mesh.proto"); + if (strcmp(req->http_verb, "OPTIONS") == 0) { + ulfius_set_response_properties(res, U_OPT_STATUS, 204); + return U_CALLBACK_COMPLETE; + } + uint8_t txBuf[MAX_STREAM_BUF_SIZE]; uint32_t len = 1; @@ -493,7 +498,9 @@ PiWebServerThread::PiWebServerThread() // Maximum body size sent by the client is 1 Kb instanceWeb.max_post_body_size = 1024; ulfius_add_endpoint_by_val(&instanceWeb, "GET", PREFIX, "/api/v1/fromradio/*", 1, &handleAPIv1FromRadio, NULL); + ulfius_add_endpoint_by_val(&instanceWeb, "OPTIONS", PREFIX, "/api/v1/fromradio/*", 1, &handleAPIv1FromRadio, NULL); ulfius_add_endpoint_by_val(&instanceWeb, "PUT", PREFIX, "/api/v1/toradio/*", 1, &handleAPIv1ToRadio, configWeb.rootPath); + ulfius_add_endpoint_by_val(&instanceWeb, "OPTIONS", PREFIX, "/api/v1/toradio/*", 1, &handleAPIv1ToRadio, NULL); // Add callback function to all endpoints for the Web Server ulfius_add_endpoint_by_val(&instanceWeb, "GET", NULL, "/*", 2, &callback_static_file, &configWeb); From 08323884825add46505fad2e6eebcfe69e452d17 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Wed, 27 Nov 2024 02:45:54 -0600 Subject: [PATCH 056/101] Remove ATECC crypto chip placeholder code (#5461) --- platformio.ini | 3 +- src/configuration.h | 3 +- src/detect/ScanI2C.h | 1 - src/detect/ScanI2CTwoWire.cpp | 52 ----------------------------------- src/detect/ScanI2CTwoWire.h | 2 -- src/main.cpp | 4 --- src/main.h | 7 ----- 7 files changed, 2 insertions(+), 70 deletions(-) diff --git a/platformio.ini b/platformio.ini index 7f4fbc3a5..cc08b33a0 100644 --- a/platformio.ini +++ b/platformio.ini @@ -109,7 +109,6 @@ framework = arduino lib_deps = ${env.lib_deps} end2endzone/NonBlockingRTTTL@1.3.0 - https://github.com/meshtastic/SparkFun_ATECCX08a_Arduino_Library.git#5cf62b36c6f30bc72a07bdb2c11fc9a22d1e31da build_flags = ${env.build_flags} -Os build_src_filter = ${env.build_src_filter} - @@ -160,4 +159,4 @@ lib_deps = https://github.com/KodinLanewave/INA3221@1.0.1 mprograms/QMC5883LCompass@1.2.3 dfrobot/DFRobot_RTU@1.0.3 - https://github.com/meshtastic/DFRobot_LarkWeatherStation#4de3a9cadef0f6a5220a8a906cf9775b02b0040d + https://github.com/meshtastic/DFRobot_LarkWeatherStation#4de3a9cadef0f6a5220a8a906cf9775b02b0040d \ No newline at end of file diff --git a/src/configuration.h b/src/configuration.h index 2e81557b1..b5727508d 100644 --- a/src/configuration.h +++ b/src/configuration.h @@ -171,7 +171,6 @@ along with this program. If not, see . // ----------------------------------------------------------------------------- // Security // ----------------------------------------------------------------------------- -#define ATECC608B_ADDR 0x35 // ----------------------------------------------------------------------------- // IO Expander @@ -362,4 +361,4 @@ along with this program. If not, see . #endif #include "DebugConfiguration.h" -#include "RF95Configuration.h" +#include "RF95Configuration.h" \ No newline at end of file diff --git a/src/detect/ScanI2C.h b/src/detect/ScanI2C.h index f4516458b..7fe3aac89 100644 --- a/src/detect/ScanI2C.h +++ b/src/detect/ScanI2C.h @@ -12,7 +12,6 @@ class ScanI2C SCREEN_SH1106, SCREEN_UNKNOWN, // has the same address as the two above but does not respond to the same commands SCREEN_ST7567, - ATECC608B, RTC_RV3028, RTC_PCF8563, CARDKB, diff --git a/src/detect/ScanI2CTwoWire.cpp b/src/detect/ScanI2CTwoWire.cpp index cd0c3d144..d29e5be8e 100644 --- a/src/detect/ScanI2CTwoWire.cpp +++ b/src/detect/ScanI2CTwoWire.cpp @@ -7,7 +7,6 @@ #include "linux/LinuxHardwareI2C.h" #endif #if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) -#include "main.h" // atecc #include "meshUtils.h" // vformat #endif @@ -84,40 +83,6 @@ ScanI2C::DeviceType ScanI2CTwoWire::probeOLED(ScanI2C::DeviceAddress addr) const return o_probe; } -void ScanI2CTwoWire::printATECCInfo() const -{ -#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) - atecc.readConfigZone(false); - - std::string atecc_numbers = "ATECC608B Serial Number: "; - for (int i = 0; i < 9; i++) { - atecc_numbers += vformat("%02x", atecc.serialNumber[i]); - } - - atecc_numbers += ", Rev Number: "; - for (int i = 0; i < 4; i++) { - atecc_numbers += vformat("%02x", atecc.revisionNumber[i]); - } - LOG_DEBUG(atecc_numbers.c_str()); - - LOG_DEBUG("ATECC608B Config %s, Data %s, Slot 0 %s", atecc.configLockStatus ? "Locked" : "Unlocked", - atecc.dataOTPLockStatus ? "Locked" : "Unlocked", atecc.slot0LockStatus ? "Locked" : "Unlocked"); - - std::string atecc_publickey = ""; - if (atecc.configLockStatus && atecc.dataOTPLockStatus && atecc.slot0LockStatus) { - if (atecc.generatePublicKey() == false) { - atecc_publickey += "ATECC608B Error generating public key"; - } else { - atecc_publickey += "ATECC608B Public Key: "; - for (int i = 0; i < 64; i++) { - atecc_publickey += vformat("%02x", atecc.publicKey64Bytes[i]); - } - } - LOG_DEBUG(atecc_publickey.c_str()); - } -#endif -} - uint16_t ScanI2CTwoWire::getRegisterValue(const ScanI2CTwoWire::RegisterLocation ®isterLocation, ScanI2CTwoWire::ResponseWidth responseWidth) const { @@ -203,23 +168,6 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize) type = probeOLED(addr); break; -#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) - case ATECC608B_ADDR: -#ifdef RP2040_SLOW_CLOCK - if (atecc.begin(addr.address, Wire, Serial2) == true) -#else - if (atecc.begin(addr.address) == true) -#endif - - { - LOG_INFO("ATECC608B initialized"); - } else { - LOG_WARN("ATECC608B initialization failed"); - } - printATECCInfo(); - break; -#endif - #ifdef RV3028_RTC case RV3028_RTC: // foundDevices[addr] = RTC_RV3028; diff --git a/src/detect/ScanI2CTwoWire.h b/src/detect/ScanI2CTwoWire.h index e9f242512..d0af7cde6 100644 --- a/src/detect/ScanI2CTwoWire.h +++ b/src/detect/ScanI2CTwoWire.h @@ -53,8 +53,6 @@ class ScanI2CTwoWire : public ScanI2C concurrency::Lock lock; - void printATECCInfo() const; - uint16_t getRegisterValue(const RegisterLocation &, ResponseWidth) const; DeviceType probeOLED(ScanI2C::DeviceAddress) const; diff --git a/src/main.cpp b/src/main.cpp index 63c7fd29b..9036cd59c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -150,10 +150,6 @@ ScanI2C::DeviceAddress accelerometer_found = ScanI2C::ADDRESS_NONE; // The I2C address of the RGB LED (if found) ScanI2C::FoundDevice rgb_found = ScanI2C::FoundDevice(ScanI2C::DeviceType::NONE, ScanI2C::ADDRESS_NONE); -#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) -ATECCX08A atecc; -#endif - #ifdef T_WATCH_S3 Adafruit_DRV2605 drv; #endif diff --git a/src/main.h b/src/main.h index 1816aef53..b3f58ae4b 100644 --- a/src/main.h +++ b/src/main.h @@ -10,9 +10,6 @@ #include "mesh/generated/meshtastic/telemetry.pb.h" #include #include -#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) -#include -#endif #if defined(ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32S2) #include "nimble/NimbleBluetooth.h" extern NimbleBluetooth *nimbleBluetooth; @@ -42,10 +39,6 @@ extern bool pmu_found; extern bool isCharging; extern bool isUSBPowered; -#if !defined(ARCH_PORTDUINO) && !defined(ARCH_STM32WL) -extern ATECCX08A atecc; -#endif - #ifdef T_WATCH_S3 #include extern Adafruit_DRV2605 drv; From b00c05012d70e4a0233f5caa749abe5aa975313c Mon Sep 17 00:00:00 2001 From: Christopher Hoover Date: Wed, 27 Nov 2024 02:56:25 -0800 Subject: [PATCH 057/101] GPS.h cleanups round 3. (#5447) * GPS.h cleanups round 3. No effective behavior change. Protected members can be private so make it so. (Supporting subclasses needs a lot more work.) Moves uBloxGnssModelInfo into file scope. Moves uBloxProtocolVersion into uBloxGnssModelInfo. Moves baud rate arrays into file scope. Removes unused/ unimplemented powerStateToString. Signed-off-by: Christopher Hoover * Trunk Format. --------- Signed-off-by: Christopher Hoover Co-authored-by: Tom Fifield --- src/gps/GPS.cpp | 81 +++++++++++++++++++++++++++++++------------------ src/gps/GPS.h | 24 ++------------- 2 files changed, 54 insertions(+), 51 deletions(-) diff --git a/src/gps/GPS.cpp b/src/gps/GPS.cpp index d49092fff..dcece305a 100644 --- a/src/gps/GPS.cpp +++ b/src/gps/GPS.cpp @@ -28,6 +28,12 @@ #define GPS_RESET_MODE HIGH #endif +// Not all platforms have std::size(). +template std::size_t array_count(const T (&)[N]) +{ + return N; +} + #if defined(NRF52840_XXAA) || defined(NRF52833_XXAA) || defined(ARCH_ESP32) || defined(ARCH_PORTDUINO) HardwareSerial *GPS::_serial_gps = &Serial1; #elif defined(ARCH_RP2040) @@ -46,8 +52,14 @@ static GPSUpdateScheduling scheduling; /// only init that port once. static bool didSerialInit; -static struct uBloxGnssModelInfo info; -static uint8_t uBloxProtocolVersion; +static struct uBloxGnssModelInfo { + char swVersion[30]; + char hwVersion[10]; + uint8_t extensionNo; + char extension[10][30]; + uint8_t protocol_version; +} ublox_info; + #define GPS_SOL_EXPIRY_MS 5000 // in millis. give 1 second time to combine different sentences. NMEA Frequency isn't higher anyway #define NMEA_MSG_GXGSA "GNGSA" // GSA message (GPGSA, GNGSA etc) @@ -412,6 +424,15 @@ int GPS::getACK(uint8_t *buffer, uint16_t size, uint8_t requestedClass, uint8_t return 0; } +#if GPS_BAUDRATE_FIXED +// if GPS_BAUDRATE is specified in variant, only try that. +static const int serialSpeeds[1] = {GPS_BAUDRATE}; +static const int rareSerialSpeeds[1] = {GPS_BAUDRATE}; +#else +static const int serialSpeeds[3] = {9600, 115200, 38400}; +static const int rareSerialSpeeds[3] = {4800, 57600, GPS_BAUDRATE}; +#endif + /** * @brief Setup the GPS based on the model detected. * We detect the GPS by cycling through a set of baud rates, first common then rare. @@ -428,7 +449,7 @@ bool GPS::setup() LOG_DEBUG("Probe for GPS at %d", serialSpeeds[speedSelect]); gnssModel = probe(serialSpeeds[speedSelect]); if (gnssModel == GNSS_MODEL_UNKNOWN) { - if (++speedSelect == sizeof(serialSpeeds) / sizeof(int)) { + if (++speedSelect == array_count(serialSpeeds)) { speedSelect = 0; ++probeTries; } @@ -439,7 +460,7 @@ bool GPS::setup() LOG_DEBUG("Probe for GPS at %d", rareSerialSpeeds[speedSelect]); gnssModel = probe(rareSerialSpeeds[speedSelect]); if (gnssModel == GNSS_MODEL_UNKNOWN) { - if (++speedSelect == sizeof(rareSerialSpeeds) / sizeof(int)) { + if (++speedSelect == array_count(rareSerialSpeeds)) { LOG_WARN("Give up on GPS probe and set to %d", GPS_BAUDRATE); return true; } @@ -635,7 +656,7 @@ bool GPS::setup() SEND_UBX_PACKET(0x06, 0x01, _message_RMC, "enable NMEA RMC", 500); SEND_UBX_PACKET(0x06, 0x01, _message_GGA, "enable NMEA GGA", 500); - if (uBloxProtocolVersion >= 18) { + if (ublox_info.protocol_version >= 18) { clearBuffer(); SEND_UBX_PACKET(0x06, 0x86, _message_PMS, "enable powersave for GPS", 500); SEND_UBX_PACKET(0x06, 0x3B, _message_CFG_PM2, "enable powersave details for GPS", 500); @@ -1131,7 +1152,7 @@ GnssModel_t GPS::probe(int serialSpeed) } #endif - memset(&info, 0, sizeof(struct uBloxGnssModelInfo)); + memset(&ublox_info, 0, sizeof(ublox_info)); uint8_t buffer[768] = {0}; delay(100); @@ -1198,64 +1219,64 @@ GnssModel_t GPS::probe(int serialSpeed) if (len) { uint16_t position = 0; for (int i = 0; i < 30; i++) { - info.swVersion[i] = buffer[position]; + ublox_info.swVersion[i] = buffer[position]; position++; } for (int i = 0; i < 10; i++) { - info.hwVersion[i] = buffer[position]; + ublox_info.hwVersion[i] = buffer[position]; position++; } while (len >= position + 30) { for (int i = 0; i < 30; i++) { - info.extension[info.extensionNo][i] = buffer[position]; + ublox_info.extension[ublox_info.extensionNo][i] = buffer[position]; position++; } - info.extensionNo++; - if (info.extensionNo > 9) + ublox_info.extensionNo++; + if (ublox_info.extensionNo > 9) break; } LOG_DEBUG("Module Info : "); - LOG_DEBUG("Soft version: %s", info.swVersion); - LOG_DEBUG("Hard version: %s", info.hwVersion); - LOG_DEBUG("Extensions:%d", info.extensionNo); - for (int i = 0; i < info.extensionNo; i++) { - LOG_DEBUG(" %s", info.extension[i]); + LOG_DEBUG("Soft version: %s", ublox_info.swVersion); + LOG_DEBUG("Hard version: %s", ublox_info.hwVersion); + LOG_DEBUG("Extensions:%d", ublox_info.extensionNo); + for (int i = 0; i < ublox_info.extensionNo; i++) { + LOG_DEBUG(" %s", ublox_info.extension[i]); } memset(buffer, 0, sizeof(buffer)); // tips: extensionNo field is 0 on some 6M GNSS modules - for (int i = 0; i < info.extensionNo; ++i) { - if (!strncmp(info.extension[i], "MOD=", 4)) { - strncpy((char *)buffer, &(info.extension[i][4]), sizeof(buffer)); - } else if (!strncmp(info.extension[i], "PROTVER", 7)) { + for (int i = 0; i < ublox_info.extensionNo; ++i) { + if (!strncmp(ublox_info.extension[i], "MOD=", 4)) { + strncpy((char *)buffer, &(ublox_info.extension[i][4]), sizeof(buffer)); + } else if (!strncmp(ublox_info.extension[i], "PROTVER", 7)) { char *ptr = nullptr; memset(buffer, 0, sizeof(buffer)); - strncpy((char *)buffer, &(info.extension[i][8]), sizeof(buffer)); + strncpy((char *)buffer, &(ublox_info.extension[i][8]), sizeof(buffer)); LOG_DEBUG("Protocol Version:%s", (char *)buffer); if (strlen((char *)buffer)) { - uBloxProtocolVersion = strtoul((char *)buffer, &ptr, 10); - LOG_DEBUG("ProtVer=%d", uBloxProtocolVersion); + ublox_info.protocol_version = strtoul((char *)buffer, &ptr, 10); + LOG_DEBUG("ProtVer=%d", ublox_info.protocol_version); } else { - uBloxProtocolVersion = 0; + ublox_info.protocol_version = 0; } } } - if (strncmp(info.hwVersion, "00040007", 8) == 0) { + if (strncmp(ublox_info.hwVersion, "00040007", 8) == 0) { LOG_INFO(DETECTED_MESSAGE, "U-blox 6", "6"); return GNSS_MODEL_UBLOX6; - } else if (strncmp(info.hwVersion, "00070000", 8) == 0) { + } else if (strncmp(ublox_info.hwVersion, "00070000", 8) == 0) { LOG_INFO(DETECTED_MESSAGE, "U-blox 7", "7"); return GNSS_MODEL_UBLOX7; - } else if (strncmp(info.hwVersion, "00080000", 8) == 0) { + } else if (strncmp(ublox_info.hwVersion, "00080000", 8) == 0) { LOG_INFO(DETECTED_MESSAGE, "U-blox 8", "8"); return GNSS_MODEL_UBLOX8; - } else if (strncmp(info.hwVersion, "00190000", 8) == 0) { + } else if (strncmp(ublox_info.hwVersion, "00190000", 8) == 0) { LOG_INFO(DETECTED_MESSAGE, "U-blox 9", "9"); return GNSS_MODEL_UBLOX9; - } else if (strncmp(info.hwVersion, "000A0000", 8) == 0) { + } else if (strncmp(ublox_info.hwVersion, "000A0000", 8) == 0) { LOG_INFO(DETECTED_MESSAGE, "U-blox 10", "10"); return GNSS_MODEL_UBLOX10; } @@ -1729,4 +1750,4 @@ void GPS::toggleGpsMode() enable(); } } -#endif // Exclude GPS +#endif // Exclude GPS \ No newline at end of file diff --git a/src/gps/GPS.h b/src/gps/GPS.h index cc72350d2..74d73e39a 100644 --- a/src/gps/GPS.h +++ b/src/gps/GPS.h @@ -16,13 +16,6 @@ #define GPS_EN_ACTIVE 1 #endif -struct uBloxGnssModelInfo { - char swVersion[30]; - char hwVersion[10]; - uint8_t extensionNo; - char extension[10][30]; -}; - typedef enum { GNSS_MODEL_ATGM336H, GNSS_MODEL_MTK, @@ -119,7 +112,9 @@ class GPS : private concurrency::OSThread // Let the GPS hardware save power between updates void down(); - protected: + private: + GPS() : concurrency::OSThread("GPS") {} + /// Record that we have a GPS void setConnected(); @@ -147,9 +142,6 @@ class GPS : private concurrency::OSThread GnssModel_t gnssModel = GNSS_MODEL_UNKNOWN; - private: - GPS() : concurrency::OSThread("GPS") {} - TinyGPSPlus reader; uint8_t fixQual = 0; // fix quality from GPGGA uint32_t lastChecksumFailCount = 0; @@ -161,14 +153,6 @@ class GPS : private concurrency::OSThread TinyGPSCustom gsapdop; // custom extract PDOP from GPGSA uint8_t fixType = 0; // fix type from GPGSA #endif -#if GPS_BAUDRATE_FIXED - // if GPS_BAUDRATE is specified in variant, only try that. - const int serialSpeeds[1] = {GPS_BAUDRATE}; - const int rareSerialSpeeds[1] = {GPS_BAUDRATE}; -#else - const int serialSpeeds[3] = {9600, 115200, 38400}; - const int rareSerialSpeeds[3] = {4800, 57600, GPS_BAUDRATE}; -#endif uint32_t lastWakeStartMsec = 0, lastSleepStartMsec = 0, lastFixStartMsec = 0; uint32_t rx_gpio = 0; @@ -252,8 +236,6 @@ class GPS : private concurrency::OSThread // delay counter to allow more sats before fixed position stops GPS thread uint8_t fixeddelayCtr = 0; - - const char *powerStateToString(); }; extern GPS *gps; From 8df7a035e2939fcdc5eaac90e85da02d7d1f8187 Mon Sep 17 00:00:00 2001 From: panaceya Date: Thu, 28 Nov 2024 13:34:09 +0200 Subject: [PATCH 058/101] Fix ukrainian fonts (#5468) * FIX: rollback to !4624 * UPDATE: new 16 and 24 UA Fonts and fixes --- src/graphics/Screen.cpp | 3 +- src/graphics/Screen.h | 1 + src/graphics/ScreenFonts.h | 12 +- src/graphics/fonts/OLEDDisplayFontsUA.cpp | 1759 ++++++++++++++++++-- src/graphics/fonts/OLEDDisplayFontsUA.h | 2 + src/modules/ExternalNotificationModule.cpp | 3 +- 6 files changed, 1645 insertions(+), 135 deletions(-) diff --git a/src/graphics/Screen.cpp b/src/graphics/Screen.cpp index dfef162ba..2ab413bc5 100644 --- a/src/graphics/Screen.cpp +++ b/src/graphics/Screen.cpp @@ -20,7 +20,6 @@ along with this program. If not, see . */ #include "Screen.h" -#include "../userPrefs.h" #include "PowerMon.h" #include "Throttle.h" #include "configuration.h" @@ -2757,4 +2756,4 @@ int Screen::handleAdminMessage(const meshtastic_AdminMessage *arg) } // namespace graphics #else graphics::Screen::Screen(ScanI2C::DeviceAddress, meshtastic_Config_DisplayConfig_OledType, OLEDDISPLAY_GEOMETRY) {} -#endif // HAS_SCREEN \ No newline at end of file +#endif // HAS_SCREEN diff --git a/src/graphics/Screen.h b/src/graphics/Screen.h index 2a77ca575..41c90ca9a 100644 --- a/src/graphics/Screen.h +++ b/src/graphics/Screen.h @@ -1,5 +1,6 @@ #pragma once +#include "../userPrefs.h" #include "configuration.h" #include "detect/ScanI2C.h" diff --git a/src/graphics/ScreenFonts.h b/src/graphics/ScreenFonts.h index c9ce961fa..032348d54 100644 --- a/src/graphics/ScreenFonts.h +++ b/src/graphics/ScreenFonts.h @@ -27,14 +27,22 @@ #define FONT_SMALL ArialMT_Plain_10_RU #else #ifdef OLED_UA -#define FONT_SMALL ArialMT_Plain_10_UA +#define FONT_SMALL ArialMT_Plain_10_UA // Height: 13 #else #define FONT_SMALL ArialMT_Plain_10 // Height: 13 #endif #endif #endif +#ifdef OLED_UA +#define FONT_MEDIUM ArialMT_Plain_16_UA // Height: 19 +#else #define FONT_MEDIUM ArialMT_Plain_16 // Height: 19 -#define FONT_LARGE ArialMT_Plain_24 // Height: 28 +#endif +#ifdef OLED_UA +#define FONT_LARGE ArialMT_Plain_24_UA // Height: 28 +#else +#define FONT_LARGE ArialMT_Plain_24 // Height: 28 +#endif #endif #define _fontHeight(font) ((font)[1] + 1) // height is position 1 diff --git a/src/graphics/fonts/OLEDDisplayFontsUA.cpp b/src/graphics/fonts/OLEDDisplayFontsUA.cpp index 0295ee6ba..2a97526ef 100644 --- a/src/graphics/fonts/OLEDDisplayFontsUA.cpp +++ b/src/graphics/fonts/OLEDDisplayFontsUA.cpp @@ -166,71 +166,71 @@ const uint8_t ArialMT_Plain_10_UA[] PROGMEM = { 0x04, 0x6F, 0x10, 0x09, // 188 0x04, 0x7F, 0x10, 0x09, // 189 0x04, 0x8F, 0x10, 0x09, // 190 - 0x04, 0x9F, 0x0A, 0x06, // 191 - 0x04, 0xA9, 0x0C, 0x07, // 192 - 0x04, 0xB5, 0x0C, 0x07, // 193 - 0x04, 0xC1, 0x0C, 0x07, // 194 - 0x04, 0xCD, 0x0B, 0x07, // 195 - 0x04, 0xD8, 0x0C, 0x07, // 196 - 0x04, 0xE4, 0x0C, 0x07, // 197 - 0x04, 0xF0, 0x0C, 0x07, // 198 - 0x04, 0xFC, 0x0C, 0x07, // 199 - 0x05, 0x08, 0x0C, 0x07, // 200 - 0x05, 0x14, 0x0C, 0x07, // 201 - 0x05, 0x20, 0x0C, 0x07, // 202 - 0x05, 0x2C, 0x0C, 0x07, // 203 - 0x05, 0x38, 0x0C, 0x07, // 204 - 0x05, 0x44, 0x0C, 0x07, // 205 - 0x05, 0x50, 0x0C, 0x07, // 206 - 0x05, 0x5C, 0x0C, 0x07, // 207 - 0x05, 0x68, 0x0B, 0x07, // 208 - 0x05, 0x73, 0x0C, 0x07, // 209 - 0x05, 0x7F, 0x0B, 0x07, // 210 - 0x05, 0x8A, 0x0C, 0x07, // 211 - 0x05, 0x96, 0x0B, 0x07, // 212 - 0x05, 0xA1, 0x0C, 0x07, // 213 - 0x05, 0xAD, 0x0C, 0x07, // 214 - 0x05, 0xB9, 0x0C, 0x07, // 215 - 0x05, 0xC5, 0x0C, 0x07, // 216 - 0x05, 0xD1, 0x0E, 0x08, // 217 - 0x05, 0xDF, 0x0C, 0x07, // 218 - 0x05, 0xEB, 0x0C, 0x07, // 219 - 0x05, 0xF7, 0x0C, 0x07, // 220 - 0x06, 0x03, 0x0C, 0x07, // 221 - 0x06, 0x0F, 0x0C, 0x07, // 222 - 0x06, 0x1B, 0x0C, 0x07, // 223 - 0x06, 0x27, 0x0C, 0x07, // 224 - 0x06, 0x33, 0x0C, 0x07, // 225 - 0x06, 0x3F, 0x0C, 0x07, // 226 - 0x06, 0x4B, 0x0B, 0x07, // 227 - 0x06, 0x56, 0x0C, 0x07, // 228 - 0x06, 0x62, 0x0B, 0x07, // 229 - 0x06, 0x6D, 0x0C, 0x07, // 230 - 0x06, 0x79, 0x0C, 0x07, // 231 - 0x06, 0x85, 0x0C, 0x07, // 232 - 0x06, 0x91, 0x0C, 0x07, // 233 - 0x06, 0x9D, 0x0C, 0x07, // 234 - 0x06, 0xA9, 0x0C, 0x07, // 235 - 0x06, 0xB5, 0x0C, 0x07, // 236 - 0x06, 0xC1, 0x0C, 0x07, // 237 - 0x06, 0xCD, 0x0C, 0x07, // 238 - 0x06, 0xD9, 0x0C, 0x07, // 239 - 0x06, 0xE5, 0x0B, 0x07, // 240 - 0x06, 0xF0, 0x0C, 0x07, // 241 - 0x06, 0xFC, 0x0B, 0x07, // 242 - 0x07, 0x07, 0x0C, 0x07, // 243 - 0x07, 0x13, 0x0B, 0x07, // 244 - 0x07, 0x1E, 0x0C, 0x07, // 245 - 0x07, 0x2A, 0x0C, 0x07, // 246 - 0x07, 0x36, 0x0C, 0x07, // 247 - 0x07, 0x42, 0x0C, 0x07, // 248 - 0x07, 0x4E, 0x0E, 0x08, // 249 - 0x07, 0x5C, 0x0C, 0x07, // 250 - 0x07, 0x68, 0x0C, 0x07, // 251 - 0x07, 0x74, 0x0C, 0x07, // 252 - 0x07, 0x80, 0x0C, 0x07, // 253 - 0x07, 0x8C, 0x0C, 0x07, // 254 - 0x07, 0x98, 0x0C, 0x07, // 255 + 0x04, 0x9F, 0x06, 0x04, // 191 + 0x04, 0xA5, 0x0A, 0x06, // 192 + 0x04, 0xAF, 0x0A, 0x06, // 193 + 0x04, 0xB9, 0x0A, 0x06, // 194 + 0x04, 0xC3, 0x09, 0x06, // 195 + 0x04, 0xCC, 0x0A, 0x06, // 196 + 0x04, 0xD6, 0x0A, 0x06, // 197 + 0x04, 0xE0, 0x0A, 0x06, // 198 + 0x04, 0xEA, 0x08, 0x05, // 199 + 0x04, 0xF2, 0x0A, 0x06, // 200 + 0x04, 0xFC, 0x0A, 0x06, // 201 + 0x05, 0x06, 0x0A, 0x06, // 202 + 0x05, 0x10, 0x0A, 0x06, // 203 + 0x05, 0x1A, 0x0A, 0x06, // 204 + 0x05, 0x24, 0x0A, 0x06, // 205 + 0x05, 0x2E, 0x0A, 0x06, // 206 + 0x05, 0x38, 0x0A, 0x06, // 207 + 0x05, 0x42, 0x09, 0x06, // 208 + 0x05, 0x4B, 0x0A, 0x06, // 209 + 0x05, 0x55, 0x09, 0x06, // 210 + 0x05, 0x5E, 0x0A, 0x06, // 211 + 0x05, 0x68, 0x09, 0x06, // 212 + 0x05, 0x71, 0x0A, 0x06, // 213 + 0x05, 0x7B, 0x0A, 0x06, // 214 + 0x05, 0x85, 0x08, 0x05, // 215 + 0x05, 0x8D, 0x0A, 0x06, // 216 + 0x05, 0x97, 0x0C, 0x07, // 217 + 0x05, 0xA3, 0x0A, 0x06, // 218 + 0x05, 0xAD, 0x0A, 0x06, // 219 + 0x05, 0xB7, 0x08, 0x05, // 220 + 0x05, 0xBF, 0x0A, 0x06, // 221 + 0x05, 0xC9, 0x0A, 0x06, // 222 + 0x05, 0xD3, 0x0A, 0x06, // 223 + 0x05, 0xDD, 0x08, 0x05, // 224 + 0x05, 0xE5, 0x08, 0x05, // 225 + 0x05, 0xED, 0x08, 0x05, // 226 + 0x05, 0xF5, 0x07, 0x05, // 227 + 0x05, 0xFC, 0x0A, 0x06, // 228 + 0x06, 0x06, 0x09, 0x06, // 229 + 0x06, 0x0F, 0x0A, 0x06, // 230 + 0x06, 0x19, 0x08, 0x05, // 231 + 0x06, 0x21, 0x0A, 0x06, // 232 + 0x06, 0x2B, 0x0A, 0x06, // 233 + 0x06, 0x35, 0x06, 0x04, // 234 + 0x06, 0x3B, 0x08, 0x05, // 235 + 0x06, 0x43, 0x0A, 0x06, // 236 + 0x06, 0x4D, 0x08, 0x05, // 237 + 0x06, 0x55, 0x08, 0x05, // 238 + 0x06, 0x5D, 0x08, 0x05, // 239 + 0x06, 0x65, 0x05, 0x04, // 240 + 0x06, 0x6A, 0x08, 0x05, // 241 + 0x06, 0x72, 0x05, 0x04, // 242 + 0x06, 0x77, 0x08, 0x05, // 243 + 0x06, 0x7F, 0x09, 0x06, // 244 + 0x06, 0x88, 0x0A, 0x06, // 245 + 0x06, 0x92, 0x08, 0x05, // 246 + 0x06, 0x9A, 0x08, 0x05, // 247 + 0x06, 0xA2, 0x0A, 0x06, // 248 + 0x06, 0xAC, 0x0C, 0x07, // 249 + 0x06, 0xB8, 0x08, 0x05, // 250 + 0x06, 0xC0, 0x08, 0x05, // 251 + 0x06, 0xC8, 0x08, 0x05, // 252 + 0x06, 0xD0, 0x08, 0x05, // 253 + 0x06, 0xD8, 0x0A, 0x06, // 254 + 0x06, 0xE2, 0x08, 0x05, // 255 // Font Data: 0x00, 0x00, 0xF8, 0x02, // 33 0x38, 0x00, 0x00, 0x00, 0x38, // 34 @@ -356,69 +356,1568 @@ const uint8_t ArialMT_Plain_10_UA[] PROGMEM = { 0x00, 0x00, 0x10, 0x02, 0x78, 0x01, 0xC0, 0x00, 0x20, 0x01, 0x90, 0x01, 0xC8, 0x03, 0x00, 0x01, // 188 0x00, 0x00, 0x10, 0x02, 0x78, 0x01, 0x80, 0x00, 0x60, 0x00, 0x50, 0x02, 0x48, 0x03, 0xC0, 0x02, // 189 0x48, 0x00, 0x58, 0x00, 0x68, 0x03, 0x80, 0x00, 0x60, 0x01, 0x90, 0x01, 0xC8, 0x03, 0x00, 0x01, // 190 - 0x00, 0x00, 0x00, 0x00, 0x28, 0x02, 0xE0, 0x03, 0x28, 0x02, // 191 - 0x00, 0x00, 0xF0, 0x03, 0x88, 0x00, 0x88, 0x00, 0x88, 0x00, 0xF0, 0x03, // 192 - 0x00, 0x00, 0xF8, 0x03, 0x48, 0x02, 0x48, 0x02, 0x48, 0x02, 0x88, 0x01, // 193 - 0x00, 0x00, 0xF8, 0x03, 0x48, 0x02, 0x48, 0x02, 0x48, 0x02, 0xB0, 0x01, // 194 - 0x00, 0x00, 0xF8, 0x03, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x18, // 195 - 0x00, 0x00, 0x00, 0x02, 0xFC, 0x03, 0x04, 0x02, 0xFC, 0x03, 0x00, 0x02, // 196 - 0x00, 0x00, 0xF8, 0x03, 0x48, 0x02, 0x48, 0x02, 0x48, 0x02, 0x08, 0x02, // 197 - 0x00, 0x00, 0xB8, 0x03, 0x40, 0x00, 0xF8, 0x03, 0x40, 0x00, 0xB8, 0x03, // 198 - 0x00, 0x00, 0x08, 0x02, 0x48, 0x02, 0x48, 0x02, 0x48, 0x02, 0xB0, 0x01, // 199 - 0x00, 0x00, 0xF8, 0x03, 0x80, 0x00, 0x40, 0x00, 0x20, 0x00, 0xF8, 0x03, // 200 - 0x00, 0x00, 0xE0, 0x03, 0x08, 0x01, 0x90, 0x00, 0x48, 0x00, 0xE0, 0x03, // 201 - 0x00, 0x00, 0xF8, 0x03, 0x40, 0x00, 0xA0, 0x00, 0x10, 0x01, 0x08, 0x02, // 202 - 0x00, 0x00, 0x00, 0x02, 0xF0, 0x01, 0x08, 0x00, 0x08, 0x00, 0xF8, 0x03, // 203 - 0x00, 0x00, 0xF8, 0x03, 0x10, 0x00, 0x60, 0x00, 0x10, 0x00, 0xF8, 0x03, // 204 - 0x00, 0x00, 0xF8, 0x03, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0xF8, 0x03, // 205 - 0x00, 0x00, 0xF0, 0x01, 0x08, 0x02, 0x08, 0x02, 0x08, 0x02, 0xF0, 0x01, // 206 - 0x00, 0x00, 0xF8, 0x03, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0xF8, 0x03, // 207 - 0x00, 0x00, 0xF8, 0x03, 0x48, 0x00, 0x48, 0x00, 0x48, 0x00, 0x30, // 208 - 0x00, 0x00, 0xF0, 0x01, 0x08, 0x02, 0x08, 0x02, 0x08, 0x02, 0x10, 0x01, // 209 - 0x00, 0x00, 0x08, 0x00, 0x08, 0x00, 0xF8, 0x03, 0x08, 0x00, 0x08, // 210 - 0x00, 0x00, 0x38, 0x00, 0x40, 0x02, 0x40, 0x02, 0x40, 0x02, 0xF8, 0x01, // 211 - 0x00, 0x00, 0x70, 0x00, 0x88, 0x00, 0xF8, 0x03, 0x88, 0x00, 0x70, // 212 - 0x00, 0x00, 0x18, 0x03, 0xA0, 0x00, 0x40, 0x00, 0xA0, 0x00, 0x18, 0x03, // 213 - 0x00, 0x00, 0xF8, 0x03, 0x00, 0x02, 0x00, 0x02, 0xF8, 0x03, 0x00, 0x02, // 214 - 0x00, 0x00, 0x38, 0x00, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0xF8, 0x03, // 215 - 0x00, 0x00, 0xF8, 0x03, 0x00, 0x02, 0xF8, 0x03, 0x00, 0x02, 0xF8, 0x03, // 216 - 0x00, 0x00, 0xF8, 0x03, 0x00, 0x02, 0xF8, 0x03, 0x00, 0x02, 0xF8, 0x03, 0x00, 0x06, // 217 - 0x00, 0x00, 0x08, 0x00, 0xF8, 0x03, 0x40, 0x02, 0x40, 0x02, 0x80, 0x01, // 218 - 0x00, 0x00, 0xF8, 0x03, 0x40, 0x02, 0x40, 0x02, 0x80, 0x01, 0xF8, 0x03, // 219 - 0x00, 0x00, 0xF8, 0x03, 0x40, 0x02, 0x40, 0x02, 0x40, 0x02, 0x80, 0x01, // 220 - 0x00, 0x00, 0x10, 0x01, 0x08, 0x02, 0x48, 0x02, 0x48, 0x02, 0xF0, 0x01, // 221 - 0x00, 0x00, 0xF8, 0x03, 0x40, 0x00, 0xF0, 0x01, 0x08, 0x02, 0xF0, 0x01, // 222 - 0x00, 0x00, 0x30, 0x02, 0x48, 0x01, 0xC8, 0x00, 0x48, 0x00, 0xF8, 0x03, // 223 - 0x00, 0x00, 0x00, 0x01, 0xA0, 0x02, 0xA0, 0x02, 0xA0, 0x02, 0xC0, 0x03, // 224 - 0x00, 0x00, 0xE0, 0x01, 0x50, 0x02, 0x50, 0x02, 0x48, 0x02, 0x88, 0x01, // 225 - 0x00, 0x00, 0xE0, 0x03, 0xA0, 0x02, 0xA0, 0x02, 0xA0, 0x02, 0x40, 0x01, // 226 - 0x00, 0x00, 0xE0, 0x03, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0x60, // 227 - 0x00, 0x00, 0x00, 0x02, 0xC0, 0x03, 0x20, 0x02, 0xE0, 0x03, 0x00, 0x02, // 228 - 0x00, 0x00, 0xC0, 0x01, 0xA0, 0x02, 0xA0, 0x02, 0xA0, 0x02, 0xC0, // 229 - 0x00, 0x00, 0x60, 0x03, 0x80, 0x00, 0xE0, 0x03, 0x80, 0x00, 0x60, 0x03, // 230 - 0x00, 0x00, 0x20, 0x02, 0xA0, 0x02, 0xA0, 0x02, 0xA0, 0x02, 0x40, 0x01, // 231 - 0x00, 0x00, 0xE0, 0x03, 0x00, 0x01, 0x80, 0x00, 0x40, 0x00, 0xE0, 0x03, // 232 - 0x00, 0x00, 0xE0, 0x03, 0x00, 0x01, 0x98, 0x00, 0x40, 0x00, 0xE0, 0x03, // 233 - 0x00, 0x00, 0xE0, 0x03, 0x80, 0x00, 0x80, 0x00, 0x40, 0x01, 0x20, 0x02, // 234 - 0x00, 0x00, 0x00, 0x02, 0xC0, 0x01, 0x20, 0x00, 0x20, 0x00, 0xE0, 0x03, // 235 - 0x00, 0x00, 0xE0, 0x03, 0x40, 0x00, 0x80, 0x00, 0x40, 0x00, 0xE0, 0x03, // 236 - 0x00, 0x00, 0xE0, 0x03, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0xE0, 0x03, // 237 - 0x00, 0x00, 0xC0, 0x01, 0x20, 0x02, 0x20, 0x02, 0x20, 0x02, 0xC0, 0x01, // 238 - 0x00, 0x00, 0xE0, 0x03, 0x20, 0x00, 0x20, 0x00, 0x20, 0x00, 0xE0, 0x03, // 239 - 0x00, 0x00, 0xE0, 0x03, 0xA0, 0x00, 0xA0, 0x00, 0xA0, 0x00, 0x40, // 240 - 0x00, 0x00, 0xC0, 0x01, 0x20, 0x02, 0x20, 0x02, 0x20, 0x02, 0x40, 0x02, // 241 - 0x00, 0x00, 0x20, 0x00, 0x20, 0x00, 0xE0, 0x03, 0x20, 0x00, 0x20, // 242 - 0x00, 0x00, 0x60, 0x00, 0x80, 0x02, 0x80, 0x02, 0x80, 0x02, 0xE0, 0x01, // 243 - 0x00, 0x00, 0xC0, 0x00, 0x20, 0x01, 0xE0, 0x03, 0x20, 0x01, 0xC0, // 244 - 0x00, 0x00, 0x20, 0x02, 0x40, 0x01, 0x80, 0x00, 0x40, 0x01, 0x20, 0x02, // 245 - 0x00, 0x00, 0xE0, 0x03, 0x00, 0x02, 0x00, 0x02, 0xE0, 0x03, 0x00, 0x02, // 246 - 0x00, 0x00, 0x60, 0x00, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0xE0, 0x03, // 247 - 0x00, 0x00, 0xE0, 0x03, 0x00, 0x02, 0xE0, 0x03, 0x00, 0x02, 0xE0, 0x03, // 248 - 0x00, 0x00, 0xE0, 0x03, 0x00, 0x02, 0xE0, 0x03, 0x00, 0x02, 0xE0, 0x03, 0x00, 0x06, // 249 - 0x00, 0x00, 0x20, 0x00, 0xE0, 0x03, 0x80, 0x02, 0x80, 0x02, 0x00, 0x01, // 250 - 0x00, 0x00, 0xE0, 0x03, 0x80, 0x02, 0x80, 0x02, 0x00, 0x01, 0xE0, 0x03, // 251 - 0x00, 0x00, 0xE0, 0x03, 0x80, 0x02, 0x80, 0x02, 0x80, 0x02, 0x00, 0x01, // 252 - 0x00, 0x00, 0x40, 0x01, 0x20, 0x02, 0xA0, 0x02, 0xA0, 0x02, 0xC0, 0x01, // 253 - 0x00, 0x00, 0xE0, 0x03, 0x80, 0x00, 0xC0, 0x01, 0x20, 0x02, 0xC0, 0x01, // 254 - 0x00, 0x00, 0x40, 0x02, 0xA0, 0x01, 0xA0, 0x00, 0xA0, 0x00, 0xE0, 0x03, // 255 + 0x28, 0x02, 0xE0, 0x03, 0x28, 0x02, // 191 + 0xF0, 0x03, 0x88, 0x00, 0x88, 0x00, 0x88, 0x00, 0xF0, 0x03, // 192 + 0xF8, 0x03, 0x48, 0x02, 0x48, 0x02, 0x48, 0x02, 0x88, 0x01, // 193 + 0xF8, 0x03, 0x48, 0x02, 0x48, 0x02, 0x48, 0x02, 0xB0, 0x01, // 194 + 0xF8, 0x03, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0x18, // 195 + 0x00, 0x02, 0xFC, 0x03, 0x04, 0x02, 0xFC, 0x03, 0x00, 0x02, // 196 + 0xF8, 0x03, 0x48, 0x02, 0x48, 0x02, 0x48, 0x02, 0x08, 0x02, // 197 + 0xB8, 0x03, 0x40, 0x00, 0xF8, 0x03, 0x40, 0x00, 0xB8, 0x03, // 198 + 0x08, 0x02, 0x48, 0x02, 0x48, 0x02, 0xB0, 0x01, // 199 + 0xF8, 0x03, 0x80, 0x00, 0x40, 0x00, 0x20, 0x00, 0xF8, 0x03, // 200 + 0xE0, 0x03, 0x08, 0x01, 0x90, 0x00, 0x48, 0x00, 0xE0, 0x03, // 201 + 0xF8, 0x03, 0x40, 0x00, 0xA0, 0x00, 0x10, 0x01, 0x08, 0x02, // 202 + 0x00, 0x02, 0xF0, 0x01, 0x08, 0x00, 0x08, 0x00, 0xF8, 0x03, // 203 + 0xF8, 0x03, 0x10, 0x00, 0x60, 0x00, 0x10, 0x00, 0xF8, 0x03, // 204 + 0xF8, 0x03, 0x40, 0x00, 0x40, 0x00, 0x40, 0x00, 0xF8, 0x03, // 205 + 0xF0, 0x01, 0x08, 0x02, 0x08, 0x02, 0x08, 0x02, 0xF0, 0x01, // 206 + 0xF8, 0x03, 0x08, 0x00, 0x08, 0x00, 0x08, 0x00, 0xF8, 0x03, // 207 + 0xF8, 0x03, 0x48, 0x00, 0x48, 0x00, 0x48, 0x00, 0x30, // 208 + 0xF0, 0x01, 0x08, 0x02, 0x08, 0x02, 0x08, 0x02, 0x10, 0x01, // 209 + 0x08, 0x00, 0x08, 0x00, 0xF8, 0x03, 0x08, 0x00, 0x08, // 210 + 0x38, 0x00, 0x40, 0x02, 0x40, 0x02, 0x40, 0x02, 0xF8, 0x01, // 211 + 0x70, 0x00, 0x88, 0x00, 0xF8, 0x03, 0x88, 0x00, 0x70, // 212 + 0x18, 0x03, 0xA0, 0x00, 0x40, 0x00, 0xA0, 0x00, 0x18, 0x03, // 213 + 0xF8, 0x03, 0x00, 0x02, 0x00, 0x02, 0xF8, 0x03, 0x00, 0x02, // 214 + 0x38, 0x00, 0x40, 0x00, 0x40, 0x00, 0xF8, 0x03, // 215 + 0xF8, 0x03, 0x00, 0x02, 0xF8, 0x03, 0x00, 0x02, 0xF8, 0x03, // 216 + 0xF8, 0x03, 0x00, 0x02, 0xF8, 0x03, 0x00, 0x02, 0xF8, 0x03, 0x00, 0x06, // 217 + 0x08, 0x00, 0xF8, 0x03, 0x40, 0x02, 0x40, 0x02, 0x80, 0x01, // 218 + 0xF8, 0x03, 0x40, 0x02, 0x40, 0x02, 0x80, 0x01, 0xF8, 0x03, // 219 + 0xF8, 0x03, 0x40, 0x02, 0x40, 0x02, 0x80, 0x01, // 220 + 0x10, 0x01, 0x08, 0x02, 0x48, 0x02, 0x48, 0x02, 0xF0, 0x01, // 221 + 0xF8, 0x03, 0x40, 0x00, 0xF0, 0x01, 0x08, 0x02, 0xF0, 0x01, // 222 + 0x30, 0x02, 0x48, 0x01, 0xC8, 0x00, 0x48, 0x00, 0xF8, 0x03, // 223 + 0x00, 0x01, 0xA0, 0x02, 0xA0, 0x02, 0xE0, 0x01, // 224 + 0xE0, 0x01, 0x50, 0x02, 0x48, 0x02, 0x88, 0x01, // 225 + 0xE0, 0x03, 0xA0, 0x02, 0xA0, 0x02, 0x40, 0x01, // 226 + 0xE0, 0x03, 0x20, 0x00, 0x20, 0x00, 0x60, // 227 + 0x00, 0x02, 0xC0, 0x03, 0x20, 0x02, 0xE0, 0x03, 0x00, 0x02, // 228 + 0xC0, 0x01, 0xA0, 0x02, 0xA0, 0x02, 0xA0, 0x02, 0xC0, // 229 + 0x60, 0x03, 0x80, 0x00, 0xE0, 0x03, 0x80, 0x00, 0x60, 0x03, // 230 + 0x20, 0x02, 0xA0, 0x02, 0xA0, 0x02, 0x40, 0x01, // 231 + 0xE0, 0x03, 0x00, 0x01, 0x80, 0x00, 0x40, 0x00, 0xE0, 0x03, // 232 + 0xE0, 0x03, 0x08, 0x01, 0x88, 0x00, 0x48, 0x00, 0xE0, 0x03, // 233 + 0xE0, 0x03, 0x80, 0x00, 0x60, 0x03, // 234 + 0x00, 0x02, 0xC0, 0x01, 0x20, 0x00, 0xE0, 0x03, // 235 + 0xE0, 0x03, 0x40, 0x00, 0x80, 0x00, 0x40, 0x00, 0xE0, 0x03, // 236 + 0xE0, 0x03, 0x80, 0x00, 0x80, 0x00, 0xE0, 0x03, // 237 + 0xC0, 0x01, 0x20, 0x02, 0x20, 0x02, 0xC0, 0x01, // 238 + 0xE0, 0x03, 0x20, 0x00, 0x20, 0x00, 0xE0, 0x03, // 239 + 0xE0, 0x03, 0xA0, 0x00, 0x40, // 240 + 0xC0, 0x01, 0x20, 0x02, 0x20, 0x02, 0x40, 0x01, // 241 + 0x20, 0x00, 0xE0, 0x03, 0x20, // 242 + 0x60, 0x00, 0x80, 0x02, 0x80, 0x02, 0xE0, 0x01, // 243 + 0xC0, 0x00, 0x20, 0x01, 0xE0, 0x03, 0x20, 0x01, 0xC0, // 244 + 0x20, 0x02, 0x40, 0x01, 0x80, 0x00, 0x40, 0x01, 0x20, 0x02, // 245 + 0xE0, 0x03, 0x00, 0x02, 0xE0, 0x03, 0x00, 0x06, // 246 + 0x60, 0x00, 0x80, 0x00, 0x80, 0x00, 0xE0, 0x03, // 247 + 0xE0, 0x03, 0x00, 0x02, 0xE0, 0x03, 0x00, 0x02, 0xE0, 0x03, // 248 + 0xE0, 0x03, 0x00, 0x02, 0xE0, 0x03, 0x00, 0x02, 0xE0, 0x03, 0x00, 0x06, // 249 + 0x20, 0x00, 0xE0, 0x03, 0x80, 0x02, 0x00, 0x01, // 250 + 0xE0, 0x03, 0x80, 0x02, 0x00, 0x01, 0xE0, 0x03, // 251 + 0xE0, 0x03, 0x80, 0x02, 0x80, 0x02, 0x00, 0x01, // 252 + 0x40, 0x01, 0x20, 0x02, 0xA0, 0x02, 0xC0, 0x01, // 253 + 0xE0, 0x03, 0x80, 0x00, 0xC0, 0x01, 0x20, 0x02, 0xC0, 0x01, // 254 + 0x40, 0x02, 0xA0, 0x01, 0xA0, 0x00, 0xE0, 0x03, // 255 +}; + +const uint8_t ArialMT_Plain_16_UA[] PROGMEM = { + 0x10, // Width: 16 + 0x13, // Height: 19 + 0x20, // First Char: 32 + 0xE0, // Numbers of Chars: 224 + // Jump Table: + 0xFF, 0xFF, 0x00, 0x04, // 32= :65535 + 0x00, 0x00, 0x08, 0x05, // 33=!:0 + 0x00, 0x08, 0x0D, 0x06, // 34=":8 + 0x00, 0x15, 0x1A, 0x09, // 35=#:21 + 0x00, 0x2F, 0x17, 0x09, // 36=$:47 + 0x00, 0x46, 0x26, 0x0E, // 37=%:70 + 0x00, 0x6C, 0x1D, 0x0B, // 38=&:108 + 0x00, 0x89, 0x04, 0x03, // 39=':137 + 0x00, 0x8D, 0x0C, 0x05, // 40=(:141 + 0x00, 0x99, 0x0B, 0x05, // 41=):153 + 0x00, 0xA4, 0x0D, 0x06, // 42=*:164 + 0x00, 0xB1, 0x17, 0x09, // 43=+:177 + 0x00, 0xC8, 0x09, 0x04, // 44=,:200 + 0x00, 0xD1, 0x0B, 0x05, // 45=-:209 + 0x00, 0xDC, 0x08, 0x04, // 46=.:220 + 0x00, 0xE4, 0x0A, 0x04, // 47=/:228 + 0x00, 0xEE, 0x17, 0x09, // 48=0:238 + 0x01, 0x05, 0x11, 0x09, // 49=1:261 + 0x01, 0x16, 0x17, 0x09, // 50=2:278 + 0x01, 0x2D, 0x17, 0x09, // 51=3:301 + 0x01, 0x44, 0x17, 0x09, // 52=4:324 + 0x01, 0x5B, 0x17, 0x09, // 53=5:347 + 0x01, 0x72, 0x17, 0x09, // 54=6:370 + 0x01, 0x89, 0x16, 0x09, // 55=7:393 + 0x01, 0x9F, 0x17, 0x09, // 56=8:415 + 0x01, 0xB6, 0x17, 0x09, // 57=9:438 + 0x01, 0xCD, 0x05, 0x04, // 58=::461 + 0x01, 0xD2, 0x06, 0x04, // 59=;:466 + 0x01, 0xD8, 0x17, 0x09, // 60=<:472 + 0x01, 0xEF, 0x17, 0x09, // 61==:495 + 0x02, 0x06, 0x17, 0x09, // 62=>:518 + 0x02, 0x1D, 0x16, 0x09, // 63=?:541 + 0x02, 0x33, 0x2F, 0x10, // 64=@:563 + 0x02, 0x62, 0x1D, 0x0B, // 65=A:610 + 0x02, 0x7F, 0x1D, 0x0B, // 66=B:639 + 0x02, 0x9C, 0x20, 0x0C, // 67=C:668 + 0x02, 0xBC, 0x20, 0x0C, // 68=D:700 + 0x02, 0xDC, 0x1D, 0x0B, // 69=E:732 + 0x02, 0xF9, 0x19, 0x0A, // 70=F:761 + 0x03, 0x12, 0x20, 0x0C, // 71=G:786 + 0x03, 0x32, 0x1D, 0x0B, // 72=H:818 + 0x03, 0x4F, 0x05, 0x03, // 73=I:847 + 0x03, 0x54, 0x14, 0x08, // 74=J:852 + 0x03, 0x68, 0x1D, 0x0B, // 75=K:872 + 0x03, 0x85, 0x17, 0x09, // 76=L:901 + 0x03, 0x9C, 0x23, 0x0D, // 77=M:924 + 0x03, 0xBF, 0x1D, 0x0B, // 78=N:959 + 0x03, 0xDC, 0x20, 0x0C, // 79=O:988 + 0x03, 0xFC, 0x1C, 0x0B, // 80=P:1020 + 0x04, 0x18, 0x20, 0x0C, // 81=Q:1048 + 0x04, 0x38, 0x1D, 0x0B, // 82=R:1080 + 0x04, 0x55, 0x1D, 0x0B, // 83=S:1109 + 0x04, 0x72, 0x19, 0x09, // 84=T:1138 + 0x04, 0x8B, 0x1D, 0x0B, // 85=U:1163 + 0x04, 0xA8, 0x1C, 0x0B, // 86=V:1192 + 0x04, 0xC4, 0x2B, 0x0F, // 87=W:1220 + 0x04, 0xEF, 0x20, 0x0B, // 88=X:1263 + 0x05, 0x0F, 0x19, 0x09, // 89=Y:1295 + 0x05, 0x28, 0x1A, 0x09, // 90=Z:1320 + 0x05, 0x42, 0x0C, 0x04, // 91=[:1346 + 0x05, 0x4E, 0x0B, 0x04, // 92=\:1358 + 0x05, 0x59, 0x09, 0x04, // 93=]:1369 + 0x05, 0x62, 0x14, 0x07, // 94=^:1378 + 0x05, 0x76, 0x1B, 0x09, // 95=_:1398 + 0x05, 0x91, 0x07, 0x05, // 96=`:1425 + 0x05, 0x98, 0x17, 0x09, // 97=a:1432 + 0x05, 0xAF, 0x17, 0x09, // 98=b:1455 + 0x05, 0xC6, 0x14, 0x08, // 99=c:1478 + 0x05, 0xDA, 0x17, 0x09, // 100=d:1498 + 0x05, 0xF1, 0x17, 0x09, // 101=e:1521 + 0x06, 0x08, 0x0A, 0x04, // 102=f:1544 + 0x06, 0x12, 0x17, 0x09, // 103=g:1554 + 0x06, 0x29, 0x14, 0x08, // 104=h:1577 + 0x06, 0x3D, 0x05, 0x04, // 105=i:1597 + 0x06, 0x42, 0x06, 0x03, // 106=j:1602 + 0x06, 0x48, 0x17, 0x08, // 107=k:1608 + 0x06, 0x5F, 0x05, 0x03, // 108=l:1631 + 0x06, 0x64, 0x23, 0x0D, // 109=m:1636 + 0x06, 0x87, 0x14, 0x08, // 110=n:1671 + 0x06, 0x9B, 0x17, 0x09, // 111=o:1691 + 0x06, 0xB2, 0x17, 0x09, // 112=p:1714 + 0x06, 0xC9, 0x18, 0x09, // 113=q:1737 + 0x06, 0xE1, 0x0D, 0x05, // 114=r:1761 + 0x06, 0xEE, 0x14, 0x08, // 115=s:1774 + 0x07, 0x02, 0x0B, 0x04, // 116=t:1794 + 0x07, 0x0D, 0x14, 0x08, // 117=u:1805 + 0x07, 0x21, 0x13, 0x07, // 118=v:1825 + 0x07, 0x34, 0x1F, 0x0B, // 119=w:1844 + 0x07, 0x53, 0x14, 0x07, // 120=x:1875 + 0x07, 0x67, 0x13, 0x07, // 121=y:1895 + 0x07, 0x7A, 0x14, 0x07, // 122=z:1914 + 0x07, 0x8E, 0x0F, 0x05, // 123={:1934 + 0x07, 0x9D, 0x06, 0x03, // 124=|:1949 + 0x07, 0xA3, 0x0E, 0x05, // 125=}:1955 + 0x07, 0xB1, 0x17, 0x09, // 126=~:1969 + 0x07, 0xC8, 0x1D, 0x0C, // 127=:1992 + 0x07, 0xE5, 0x26, 0x0E, // 1026=Ђ:2021 + 0x08, 0x0B, 0x19, 0x09, // 1027=Ѓ:2059 + 0x08, 0x24, 0x06, 0x04, // 8218=‚:2084 + 0x08, 0x2A, 0x10, 0x06, // 1107=ѓ:2090 + 0x08, 0x3A, 0x09, 0x05, // 8222=„:2106 + 0x08, 0x43, 0x26, 0x10, // 8230=…:2115 + 0x08, 0x69, 0x16, 0x09, // 8224=†:2153 + 0x08, 0x7F, 0x17, 0x09, // 8225=‡:2175 + 0x08, 0x96, 0x17, 0x09, // 8364=€:2198 + 0x08, 0xAD, 0x32, 0x11, // 8240=‰:2221 + 0x08, 0xDF, 0x2F, 0x11, // 1033=Љ:2271 + 0x09, 0x0E, 0x0B, 0x05, // 8249=‹:2318 + 0x09, 0x19, 0x2C, 0x10, // 1034=Њ:2329 + 0x09, 0x45, 0x1A, 0x09, // 1036=Ќ:2373 + 0x09, 0x5F, 0x23, 0x0D, // 1035=Ћ:2399 + 0x09, 0x82, 0x1D, 0x0C, // 1039=Џ:2434 + 0x09, 0x9F, 0x15, 0x08, // 1106=ђ:2463 + 0x09, 0xB4, 0x04, 0x04, // 8216=‘:2484 + 0x09, 0xB8, 0x04, 0x04, // 8217=’:2488 + 0x09, 0xBC, 0x07, 0x05, // 8220=“:2492 + 0x09, 0xC3, 0x0A, 0x05, // 8221=”:2499 + 0x09, 0xCD, 0x0E, 0x06, // 8226=•:2509 + 0x09, 0xDB, 0x1A, 0x09, // 8211=–:2523 + 0x09, 0xF5, 0x2F, 0x10, // 8212=—:2549 + 0x0A, 0x24, 0x1D, 0x0C, // 65533=�:2596 + 0x0A, 0x41, 0x2C, 0x10, // 8482=™:2625 + 0x0A, 0x6D, 0x29, 0x0F, // 1113=љ:2669 + 0x0A, 0x96, 0x0B, 0x05, // 8250=›:2710 + 0x0A, 0xA1, 0x23, 0x0D, // 1114=њ:2721 + 0x0A, 0xC4, 0x14, 0x07, // 1116=ќ:2756 + 0x0A, 0xD8, 0x14, 0x08, // 1115=ћ:2776 + 0x0A, 0xEC, 0x14, 0x08, // 1119=џ:2796 + 0xFF, 0xFF, 0x00, 0x04, // 160= :65535 + 0x0B, 0x00, 0x1C, 0x0A, // 1038=Ў:2816 + 0x0B, 0x1C, 0x13, 0x07, // 1118=ў:2844 + 0x0B, 0x2F, 0x14, 0x08, // 1032=Ј:2863 + 0x0B, 0x43, 0x14, 0x09, // 164=¤:2883 + 0x0B, 0x57, 0x16, 0x08, // 1168=Ґ:2903 + 0x0B, 0x6D, 0x06, 0x03, // 166=¦:2925 + 0x0B, 0x73, 0x17, 0x09, // 167=§:2931 + 0x0B, 0x8A, 0x1D, 0x0B, // 1025=Ё:2954 + 0x0B, 0xA7, 0x23, 0x0C, // 169=©:2983 + 0x0B, 0xCA, 0x20, 0x0C, // 1028=Є:3018 + 0x0B, 0xEA, 0x14, 0x09, // 171=«:3050 + 0x0B, 0xFE, 0x17, 0x09, // 172=¬:3070 + 0x0C, 0x15, 0x0B, 0x05, // 173=­:3093 + 0x0C, 0x20, 0x23, 0x0C, // 174=®:3104 + 0x0C, 0x43, 0x07, 0x03, // 1031=Ї:3139 + 0x0C, 0x4A, 0x0D, 0x06, // 176=°:3146 + 0x0C, 0x57, 0x17, 0x09, // 177=±:3159 + 0x0C, 0x6E, 0x05, 0x03, // 1030=І:3182 + 0x0C, 0x73, 0x05, 0x04, // 1110=і:3187 + 0x0C, 0x78, 0x10, 0x07, // 1169=ґ:3192 + 0x0C, 0x88, 0x17, 0x09, // 181=µ:3208 + 0x0C, 0x9F, 0x19, 0x09, // 182=¶:3231 + 0x0C, 0xB8, 0x08, 0x05, // 183=·:3256 + 0x0C, 0xC0, 0x17, 0x09, // 1105=ё:3264 + 0x0C, 0xD7, 0x2F, 0x11, // 8470=№:3287 + 0x0D, 0x06, 0x14, 0x08, // 1108=є:3334 + 0x0D, 0x1A, 0x17, 0x09, // 187=»:3354 + 0x0D, 0x31, 0x06, 0x03, // 1112=ј:3377 + 0x0D, 0x37, 0x1D, 0x0B, // 1029=Ѕ:3383 + 0x0D, 0x54, 0x14, 0x08, // 1109=ѕ:3412 + 0x0D, 0x68, 0x07, 0x03, // 1111=ї:3432 + 0x0D, 0x6F, 0x1D, 0x0B, // 1040=А:3439 + 0x0D, 0x8C, 0x1D, 0x0B, // 1041=Б:3468 + 0x0D, 0xA9, 0x1D, 0x0B, // 1042=В:3497 + 0x0D, 0xC6, 0x19, 0x09, // 1043=Г:3526 + 0x0D, 0xDF, 0x1E, 0x0B, // 1044=Д:3551 + 0x0D, 0xFD, 0x1D, 0x0B, // 1045=Е:3581 + 0x0E, 0x1A, 0x29, 0x0E, // 1046=Ж:3610 + 0x0E, 0x43, 0x1A, 0x0A, // 1047=З:3651 + 0x0E, 0x5D, 0x20, 0x0C, // 1048=И:3677 + 0x0E, 0x7D, 0x20, 0x0C, // 1049=Й:3709 + 0x0E, 0x9D, 0x1A, 0x09, // 1050=К:3741 + 0x0E, 0xB7, 0x1D, 0x0B, // 1051=Л:3767 + 0x0E, 0xD4, 0x23, 0x0D, // 1052=М:3796 + 0x0E, 0xF7, 0x1D, 0x0B, // 1053=Н:3831 + 0x0F, 0x14, 0x20, 0x0C, // 1054=О:3860 + 0x0F, 0x34, 0x1D, 0x0B, // 1055=П:3892 + 0x0F, 0x51, 0x1C, 0x0B, // 1056=Р:3921 + 0x0F, 0x6D, 0x20, 0x0C, // 1057=С:3949 + 0x0F, 0x8D, 0x19, 0x09, // 1058=Т:3981 + 0x0F, 0xA6, 0x1C, 0x0A, // 1059=У:4006 + 0x0F, 0xC2, 0x1D, 0x0B, // 1060=Ф:4034 + 0x0F, 0xDF, 0x20, 0x0B, // 1061=Х:4063 + 0x0F, 0xFF, 0x21, 0x0C, // 1062=Ц:4095 + 0x10, 0x20, 0x1A, 0x0A, // 1063=Ч:4128 + 0x10, 0x3A, 0x23, 0x0D, // 1064=Ш:4154 + 0x10, 0x5D, 0x27, 0x0E, // 1065=Щ:4189 + 0x10, 0x84, 0x23, 0x0D, // 1066=Ъ:4228 + 0x10, 0xA7, 0x26, 0x0E, // 1067=Ы:4263 + 0x10, 0xCD, 0x1D, 0x0B, // 1068=Ь:4301 + 0x10, 0xEA, 0x20, 0x0C, // 1069=Э:4330 + 0x11, 0x0A, 0x2C, 0x10, // 1070=Ю:4362 + 0x11, 0x36, 0x20, 0x0C, // 1071=Я:4406 + 0x11, 0x56, 0x17, 0x09, // 1072=а:4438 + 0x11, 0x6D, 0x17, 0x09, // 1073=б:4461 + 0x11, 0x84, 0x17, 0x09, // 1074=в:4484 + 0x11, 0x9B, 0x10, 0x06, // 1075=г:4507 + 0x11, 0xAB, 0x18, 0x09, // 1076=д:4523 + 0x11, 0xC3, 0x17, 0x09, // 1077=е:4547 + 0x11, 0xDA, 0x1D, 0x0A, // 1078=ж:4570 + 0x11, 0xF7, 0x11, 0x07, // 1079=з:4599 + 0x12, 0x08, 0x14, 0x08, // 1080=и:4616 + 0x12, 0x1C, 0x14, 0x08, // 1081=й:4636 + 0x12, 0x30, 0x14, 0x07, // 1082=к:4656 + 0x12, 0x44, 0x14, 0x08, // 1083=л:4676 + 0x12, 0x58, 0x1D, 0x0B, // 1084=м:4696 + 0x12, 0x75, 0x14, 0x08, // 1085=н:4725 + 0x12, 0x89, 0x17, 0x09, // 1086=о:4745 + 0x12, 0xA0, 0x14, 0x08, // 1087=п:4768 + 0x12, 0xB4, 0x17, 0x09, // 1088=р:4788 + 0x12, 0xCB, 0x14, 0x08, // 1089=с:4811 + 0x12, 0xDF, 0x13, 0x07, // 1090=т:4831 + 0x12, 0xF2, 0x13, 0x07, // 1091=у:4850 + 0x13, 0x05, 0x23, 0x0D, // 1092=ф:4869 + 0x13, 0x28, 0x14, 0x07, // 1093=х:4904 + 0x13, 0x3C, 0x1B, 0x09, // 1094=ц:4924 + 0x13, 0x57, 0x14, 0x08, // 1095=ч:4951 + 0x13, 0x6B, 0x1D, 0x0B, // 1096=ш:4971 + 0x13, 0x88, 0x21, 0x0B, // 1097=щ:5000 + 0x13, 0xA9, 0x1A, 0x0A, // 1098=ъ:5033 + 0x13, 0xC3, 0x20, 0x0C, // 1099=ы:5059 + 0x13, 0xE3, 0x17, 0x09, // 1100=ь:5091 + 0x13, 0xFA, 0x14, 0x08, // 1101=э:5114 + 0x14, 0x0E, 0x20, 0x0C, // 1102=ю:5134 + 0x14, 0x2E, 0x17, 0x09, // 1103=я:5166 + // Font Data: + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x5F, // 33 + 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, // 34 + 0x80, 0x08, 0x00, 0x80, 0x78, 0x00, 0xC0, 0x0F, 0x00, 0xB8, 0x08, 0x00, 0x80, 0x08, 0x00, 0x80, 0x78, 0x00, 0xC0, 0x0F, 0x00, + 0xB8, 0x08, 0x00, 0x80, 0x08, // 35 + 0x00, 0x00, 0x00, 0xE0, 0x10, 0x00, 0x10, 0x21, 0x00, 0x08, 0x43, 0x00, 0xFC, 0xFF, 0x00, 0x08, 0x42, 0x00, 0x18, 0x22, 0x00, + 0x20, 0x1C, // 36 + 0x00, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x08, 0x01, 0x00, 0x08, 0x01, 0x00, 0x08, 0x61, 0x00, 0xF0, 0x18, 0x00, 0x00, 0x06, 0x00, + 0xC0, 0x01, 0x00, 0x30, 0x3C, 0x00, 0x08, 0x42, 0x00, 0x00, 0x42, 0x00, 0x00, 0x42, 0x00, 0x00, 0x3C, // 37 + 0x00, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x70, 0x22, 0x00, 0x88, 0x41, 0x00, 0x08, 0x43, 0x00, 0x88, 0x44, 0x00, 0x70, 0x28, 0x00, + 0x00, 0x10, 0x00, 0x00, 0x28, 0x00, 0x00, 0x44, // 38 + 0x00, 0x00, 0x00, 0x78, // 39 + 0x00, 0x00, 0x00, 0x80, 0x3F, 0x00, 0x70, 0xC0, 0x01, 0x08, 0x00, 0x02, // 40 + 0x00, 0x00, 0x00, 0x08, 0x00, 0x02, 0x70, 0xC0, 0x01, 0x80, 0x3F, // 41 + 0x10, 0x00, 0x00, 0xD0, 0x00, 0x00, 0x38, 0x00, 0x00, 0xD0, 0x00, 0x00, 0x10, // 42 + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x00, 0xC0, 0x1F, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x00, + 0x00, 0x02, // 43 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x01, // 44 + 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, // 45 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, // 46 + 0x00, 0x60, 0x00, 0x00, 0x1E, 0x00, 0xE0, 0x01, 0x00, 0x18, // 47 + 0x00, 0x00, 0x00, 0xE0, 0x1F, 0x00, 0x10, 0x20, 0x00, 0x08, 0x40, 0x00, 0x08, 0x40, 0x00, 0x08, 0x40, 0x00, 0x10, 0x20, 0x00, + 0xE0, 0x1F, // 48 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x20, 0x00, 0x00, 0x10, 0x00, 0x00, 0xF8, 0x7F, // 49 + 0x00, 0x00, 0x00, 0x20, 0x40, 0x00, 0x10, 0x60, 0x00, 0x08, 0x50, 0x00, 0x08, 0x48, 0x00, 0x08, 0x44, 0x00, 0x10, 0x43, 0x00, + 0xE0, 0x40, // 50 + 0x00, 0x00, 0x00, 0x20, 0x10, 0x00, 0x10, 0x20, 0x00, 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, 0x88, 0x41, 0x00, 0xF0, 0x22, 0x00, + 0x00, 0x1C, // 51 + 0x00, 0x0C, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x09, 0x00, 0xC0, 0x08, 0x00, 0x20, 0x08, 0x00, 0x10, 0x08, 0x00, 0xF8, 0x7F, 0x00, + 0x00, 0x08, // 52 + 0x00, 0x00, 0x00, 0xC0, 0x11, 0x00, 0xB8, 0x20, 0x00, 0x88, 0x40, 0x00, 0x88, 0x40, 0x00, 0x88, 0x40, 0x00, 0x08, 0x21, 0x00, + 0x08, 0x1E, // 53 + 0x00, 0x00, 0x00, 0xE0, 0x1F, 0x00, 0x10, 0x21, 0x00, 0x88, 0x40, 0x00, 0x88, 0x40, 0x00, 0x88, 0x40, 0x00, 0x10, 0x21, 0x00, + 0x20, 0x1E, // 54 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x78, 0x00, 0x88, 0x07, 0x00, 0x68, 0x00, 0x00, + 0x18, // 55 + 0x00, 0x00, 0x00, 0x60, 0x1C, 0x00, 0x90, 0x22, 0x00, 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, 0x90, 0x22, 0x00, + 0x60, 0x1C, // 56 + 0x00, 0x00, 0x00, 0xE0, 0x11, 0x00, 0x10, 0x22, 0x00, 0x08, 0x44, 0x00, 0x08, 0x44, 0x00, 0x08, 0x44, 0x00, 0x10, 0x22, 0x00, + 0xE0, 0x1F, // 57 + 0x00, 0x00, 0x00, 0x40, 0x40, // 58 + 0x00, 0x00, 0x00, 0x40, 0xC0, 0x01, // 59 + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x05, 0x00, 0x00, 0x05, 0x00, 0x80, 0x08, 0x00, 0x80, 0x08, 0x00, 0x80, 0x08, 0x00, + 0x40, 0x10, // 60 + 0x00, 0x00, 0x00, 0x80, 0x08, 0x00, 0x80, 0x08, 0x00, 0x80, 0x08, 0x00, 0x80, 0x08, 0x00, 0x80, 0x08, 0x00, 0x80, 0x08, 0x00, + 0x80, 0x08, // 61 + 0x00, 0x00, 0x00, 0x40, 0x10, 0x00, 0x80, 0x08, 0x00, 0x80, 0x08, 0x00, 0x80, 0x08, 0x00, 0x00, 0x05, 0x00, 0x00, 0x05, 0x00, + 0x00, 0x02, // 62 + 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x10, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x5C, 0x00, 0x08, 0x02, 0x00, 0x10, 0x01, 0x00, + 0xE0, // 63 + 0x00, 0x00, 0x00, 0x00, 0x3F, 0x00, 0xC0, 0x40, 0x00, 0x20, 0x80, 0x00, 0x10, 0x1E, 0x01, 0x10, 0x21, 0x01, 0x88, 0x40, 0x02, + 0x48, 0x40, 0x02, 0x48, 0x40, 0x02, 0x48, 0x20, 0x02, 0x88, 0x7C, 0x02, 0xC8, 0x43, 0x02, 0x10, 0x40, 0x02, 0x10, 0x20, 0x01, + 0x60, 0x10, 0x01, 0x80, 0x8F, // 64 + 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x1C, 0x00, 0x80, 0x07, 0x00, 0x70, 0x04, 0x00, 0x08, 0x04, 0x00, 0x70, 0x04, 0x00, + 0x80, 0x07, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x60, // 65 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, + 0x08, 0x41, 0x00, 0x90, 0x22, 0x00, 0x60, 0x1C, // 66 + 0x00, 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x20, 0x10, 0x00, 0x10, 0x20, 0x00, 0x08, 0x40, 0x00, 0x08, 0x40, 0x00, 0x08, 0x40, 0x00, + 0x08, 0x40, 0x00, 0x08, 0x40, 0x00, 0x10, 0x20, 0x00, 0x20, 0x10, // 67 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x08, 0x40, 0x00, 0x08, 0x40, 0x00, 0x08, 0x40, 0x00, 0x08, 0x40, 0x00, 0x08, 0x40, 0x00, + 0x08, 0x40, 0x00, 0x10, 0x20, 0x00, 0x20, 0x10, 0x00, 0xC0, 0x0F, // 68 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, + 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, 0x08, 0x40, // 69 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x08, 0x02, 0x00, 0x08, 0x02, 0x00, 0x08, 0x02, 0x00, 0x08, 0x02, 0x00, 0x08, 0x02, 0x00, + 0x08, 0x02, 0x00, 0x08, // 70 + 0x00, 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x20, 0x10, 0x00, 0x10, 0x20, 0x00, 0x08, 0x40, 0x00, 0x08, 0x40, 0x00, 0x08, 0x42, 0x00, + 0x08, 0x42, 0x00, 0x10, 0x22, 0x00, 0x20, 0x12, 0x00, 0x00, 0x0E, // 71 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0xF8, 0x7F, // 72 + 0x00, 0x00, 0x00, 0xF8, 0x7F, // 73 + 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0xF8, 0x3F, // 74 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x00, 0x04, 0x00, 0x00, 0x02, 0x00, 0x00, 0x01, 0x00, 0x80, 0x03, 0x00, 0x40, 0x04, 0x00, + 0x20, 0x18, 0x00, 0x10, 0x20, 0x00, 0x08, 0x40, // 75 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, + 0x00, 0x40, // 76 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x30, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x60, 0x00, + 0x00, 0x1C, 0x00, 0x00, 0x03, 0x00, 0xC0, 0x00, 0x00, 0x30, 0x00, 0x00, 0xF8, 0x7F, // 77 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x10, 0x00, 0x00, 0x60, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x04, 0x00, + 0x00, 0x18, 0x00, 0x00, 0x20, 0x00, 0xF8, 0x7F, // 78 + 0x00, 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x20, 0x10, 0x00, 0x10, 0x20, 0x00, 0x08, 0x40, 0x00, 0x08, 0x40, 0x00, 0x08, 0x40, 0x00, + 0x08, 0x40, 0x00, 0x10, 0x20, 0x00, 0x20, 0x10, 0x00, 0xC0, 0x0F, // 79 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x08, 0x02, 0x00, 0x08, 0x02, 0x00, 0x08, 0x02, 0x00, 0x08, 0x02, 0x00, 0x08, 0x02, 0x00, + 0x08, 0x02, 0x00, 0x10, 0x01, 0x00, 0xE0, // 80 + 0x00, 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x20, 0x10, 0x00, 0x10, 0x20, 0x00, 0x08, 0x40, 0x00, 0x08, 0x40, 0x00, 0x08, 0x50, 0x00, + 0x08, 0x50, 0x00, 0x10, 0x20, 0x00, 0x20, 0x70, 0x00, 0xC0, 0x4F, // 81 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x08, 0x02, 0x00, 0x08, 0x02, 0x00, 0x08, 0x02, 0x00, 0x08, 0x02, 0x00, 0x08, 0x0E, 0x00, + 0x08, 0x1A, 0x00, 0x10, 0x21, 0x00, 0xE0, 0x40, // 82 + 0x00, 0x00, 0x00, 0x60, 0x10, 0x00, 0x90, 0x20, 0x00, 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, 0x08, 0x42, 0x00, + 0x08, 0x42, 0x00, 0x10, 0x22, 0x00, 0x20, 0x1C, // 83 + 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x08, // 84 + 0x00, 0x00, 0x00, 0xF8, 0x1F, 0x00, 0x00, 0x20, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, + 0x00, 0x40, 0x00, 0x00, 0x20, 0x00, 0xF8, 0x1F, // 85 + 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x18, 0x00, 0x00, 0x60, 0x00, 0x00, 0x18, 0x00, + 0x00, 0x07, 0x00, 0xE0, 0x00, 0x00, 0x18, // 86 + 0x18, 0x00, 0x00, 0xE0, 0x01, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x60, 0x00, 0x00, 0x1C, 0x00, 0x80, 0x03, 0x00, 0x70, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x70, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x60, 0x00, 0x00, 0x1E, 0x00, 0xE0, 0x01, 0x00, + 0x18, // 87 + 0x00, 0x40, 0x00, 0x08, 0x20, 0x00, 0x10, 0x18, 0x00, 0x60, 0x04, 0x00, 0x80, 0x02, 0x00, 0x00, 0x01, 0x00, 0x80, 0x02, 0x00, + 0x60, 0x0C, 0x00, 0x10, 0x10, 0x00, 0x08, 0x20, 0x00, 0x00, 0x40, // 88 + 0x08, 0x00, 0x00, 0x30, 0x00, 0x00, 0x40, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x7E, 0x00, 0x80, 0x01, 0x00, 0x40, 0x00, 0x00, + 0x30, 0x00, 0x00, 0x08, // 89 + 0x00, 0x40, 0x00, 0x08, 0x60, 0x00, 0x08, 0x58, 0x00, 0x08, 0x44, 0x00, 0x08, 0x43, 0x00, 0x88, 0x40, 0x00, 0x68, 0x40, 0x00, + 0x18, 0x40, 0x00, 0x08, 0x40, // 90 + 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x03, 0x08, 0x00, 0x02, 0x08, 0x00, 0x02, // 91 + 0x18, 0x00, 0x00, 0xE0, 0x01, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x60, // 92 + 0x08, 0x00, 0x02, 0x08, 0x00, 0x02, 0xF8, 0xFF, 0x03, // 93 + 0x00, 0x01, 0x00, 0xC0, 0x00, 0x00, 0x30, 0x00, 0x00, 0x08, 0x00, 0x00, 0x30, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x01, // 94 + 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, // 95 + 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x10, // 96 + 0x00, 0x00, 0x00, 0x00, 0x39, 0x00, 0x80, 0x44, 0x00, 0x40, 0x44, 0x00, 0x40, 0x44, 0x00, 0x40, 0x42, 0x00, 0x40, 0x22, 0x00, + 0x80, 0x7F, // 97 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x80, 0x20, 0x00, 0x40, 0x40, 0x00, 0x40, 0x40, 0x00, 0x40, 0x40, 0x00, 0x80, 0x20, 0x00, + 0x00, 0x1F, // 98 + 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x80, 0x20, 0x00, 0x40, 0x40, 0x00, 0x40, 0x40, 0x00, 0x40, 0x40, 0x00, 0x80, 0x20, // 99 + 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x80, 0x20, 0x00, 0x40, 0x40, 0x00, 0x40, 0x40, 0x00, 0x40, 0x40, 0x00, 0x80, 0x20, 0x00, + 0xF8, 0x7F, // 100 + 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x80, 0x24, 0x00, 0x40, 0x44, 0x00, 0x40, 0x44, 0x00, 0x40, 0x44, 0x00, 0x80, 0x24, 0x00, + 0x00, 0x17, // 101 + 0x40, 0x00, 0x00, 0xF0, 0x7F, 0x00, 0x48, 0x00, 0x00, 0x48, // 102 + 0x00, 0x00, 0x00, 0x00, 0x1F, 0x01, 0x80, 0x20, 0x02, 0x40, 0x40, 0x02, 0x40, 0x40, 0x02, 0x40, 0x40, 0x02, 0x80, 0x20, 0x01, + 0xC0, 0xFF, // 103 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x80, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x80, 0x7F, // 104 + 0x00, 0x00, 0x00, 0xC8, 0x7F, // 105 + 0x00, 0x00, 0x02, 0xC8, 0xFF, 0x01, // 106 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x00, 0x08, 0x00, 0x00, 0x04, 0x00, 0x00, 0x06, 0x00, 0x00, 0x19, 0x00, 0x80, 0x20, 0x00, + 0x40, 0x40, // 107 + 0x00, 0x00, 0x00, 0xF8, 0x7F, // 108 + 0x00, 0x00, 0x00, 0xC0, 0x7F, 0x00, 0x80, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x80, 0x7F, 0x00, + 0x80, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x80, 0x7F, // 109 + 0x00, 0x00, 0x00, 0xC0, 0x7F, 0x00, 0x80, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x80, 0x7F, // 110 + 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x80, 0x20, 0x00, 0x40, 0x40, 0x00, 0x40, 0x40, 0x00, 0x40, 0x40, 0x00, 0x80, 0x20, 0x00, + 0x00, 0x1F, // 111 + 0x00, 0x00, 0x00, 0xC0, 0xFF, 0x03, 0x80, 0x20, 0x00, 0x40, 0x40, 0x00, 0x40, 0x40, 0x00, 0x40, 0x40, 0x00, 0x80, 0x20, 0x00, + 0x00, 0x1F, // 112 + 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x80, 0x20, 0x00, 0x40, 0x40, 0x00, 0x40, 0x40, 0x00, 0x40, 0x40, 0x00, 0x80, 0x20, 0x00, + 0xC0, 0xFF, 0x03, // 113 + 0x00, 0x00, 0x00, 0xC0, 0x7F, 0x00, 0x80, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, // 114 + 0x00, 0x00, 0x00, 0x80, 0x23, 0x00, 0x40, 0x44, 0x00, 0x40, 0x44, 0x00, 0x40, 0x44, 0x00, 0x40, 0x44, 0x00, 0x80, 0x38, // 115 + 0x40, 0x00, 0x00, 0xF0, 0x7F, 0x00, 0x40, 0x40, 0x00, 0x40, 0x40, // 116 + 0x00, 0x00, 0x00, 0xC0, 0x3F, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x20, 0x00, 0xC0, 0x7F, // 117 + 0xC0, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x60, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x03, 0x00, 0xC0, // 118 + 0xC0, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x60, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x03, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x03, 0x00, + 0x00, 0x1C, 0x00, 0x00, 0x60, 0x00, 0x00, 0x1F, 0x00, 0xC0, // 119 + 0x40, 0x40, 0x00, 0x80, 0x20, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x04, 0x00, 0x00, 0x1B, 0x00, 0x80, 0x20, 0x00, 0x40, 0x40, // 120 + 0xC0, 0x01, 0x00, 0x00, 0x06, 0x02, 0x00, 0x38, 0x02, 0x00, 0xC0, 0x01, 0x00, 0x38, 0x00, 0x00, 0x07, 0x00, 0xC0, // 121 + 0x40, 0x40, 0x00, 0x40, 0x60, 0x00, 0x40, 0x58, 0x00, 0x40, 0x44, 0x00, 0x40, 0x43, 0x00, 0xC0, 0x40, 0x00, 0x40, 0x40, // 122 + 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0xF0, 0xFB, 0x01, 0x08, 0x00, 0x02, 0x08, 0x00, 0x02, // 123 + 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x03, // 124 + 0x08, 0x00, 0x02, 0x08, 0x00, 0x02, 0xF0, 0xFB, 0x01, 0x00, 0x04, 0x00, 0x00, 0x04, // 125 + 0x00, 0x02, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x00, + 0x00, 0x01, // 126 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x7F, 0x00, 0x20, 0x40, 0x00, 0x20, 0x40, 0x00, 0x20, 0x40, 0x00, 0x20, 0x40, 0x00, + 0x20, 0x40, 0x00, 0x20, 0x40, 0x00, 0xE0, 0x7F, // 127 + 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x08, 0x02, 0x00, 0x08, 0x01, 0x00, + 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, 0x00, 0x41, 0x00, 0x00, 0x41, 0x00, 0x00, 0x41, 0x00, 0x00, 0x3E, // 1026 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x08, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x09, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x08, // 1027 + 0x00, 0x00, 0x00, 0x00, 0xC0, 0x01, // 8218 + 0x00, 0x00, 0x00, 0xC0, 0x7F, 0x00, 0x40, 0x00, 0x00, 0x50, 0x00, 0x00, 0x48, 0x00, 0x00, 0x40, // 1107 + 0x00, 0xC0, 0x01, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x01, // 8222 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, // 8230 + 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0xF8, 0xFF, 0x03, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, + 0x40, // 8224 + 0x00, 0x00, 0x00, 0x40, 0x40, 0x00, 0x40, 0x40, 0x00, 0x40, 0x40, 0x00, 0xF8, 0xFF, 0x03, 0x40, 0x40, 0x00, 0x40, 0x40, 0x00, + 0x40, 0x40, // 8225 + 0x00, 0x05, 0x00, 0xC0, 0x1F, 0x00, 0x20, 0x25, 0x00, 0x10, 0x45, 0x00, 0x08, 0x45, 0x00, 0x08, 0x45, 0x00, 0x08, 0x45, 0x00, + 0x10, 0x20, // 8364 + 0xF0, 0x00, 0x00, 0x08, 0x01, 0x00, 0x08, 0x01, 0x00, 0x08, 0x71, 0x00, 0xF0, 0x0C, 0x00, 0x00, 0x03, 0x00, 0xE0, 0x3C, 0x00, + 0x18, 0x42, 0x00, 0x00, 0x42, 0x00, 0x00, 0x42, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x42, 0x00, + 0x00, 0x42, 0x00, 0x00, 0x42, 0x00, 0x00, 0x3C, // 8240 + 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0xF8, 0x3F, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, + 0x08, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x00, 0x41, 0x00, 0x00, 0x41, 0x00, 0x00, 0x41, 0x00, 0x00, 0x41, 0x00, 0x00, 0x41, 0x00, + 0x00, 0x41, 0x00, 0x00, 0x3E, // 1033 + 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x1B, 0x00, 0x80, 0x20, // 8249 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, + 0xF8, 0x7F, 0x00, 0x00, 0x41, 0x00, 0x00, 0x41, 0x00, 0x00, 0x41, 0x00, 0x00, 0x41, 0x00, 0x00, 0x41, 0x00, 0x00, 0x41, 0x00, + 0x00, 0x3E, // 1034 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x82, 0x02, 0x00, 0x61, 0x04, 0x00, 0x10, 0x08, 0x00, + 0x08, 0x30, 0x00, 0x08, 0x40, // 1036 + 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x08, 0x02, 0x00, 0x08, 0x01, 0x00, + 0x08, 0x01, 0x00, 0x08, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x7E, // 1035 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0xC0, 0x03, 0x00, 0x40, 0x00, + 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0xF8, 0x7F, // 1039 + 0x10, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x90, 0x00, 0x00, 0x50, 0x00, 0x00, 0x50, 0x00, 0x00, 0x40, 0x00, 0x02, 0x80, 0xFF, + 0x03, // 1106 + 0x00, 0x00, 0x00, 0x38, // 8216 + 0x00, 0x00, 0x00, 0x38, // 8217 + 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, // 8220 + 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, // 8221 + 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x80, 0x07, 0x00, 0x80, 0x07, 0x00, 0x00, 0x03, // 8226 + 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, + 0x00, 0x04, 0x00, 0x00, 0x04, // 8211 + 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, + 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, + 0x00, 0x04, 0x00, 0x00, 0x04, // 8212 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x7F, 0x00, 0x20, 0x40, 0x00, 0x20, 0x40, 0x00, 0x20, 0x40, 0x00, 0x20, 0x40, 0x00, + 0x20, 0x40, 0x00, 0x20, 0x40, 0x00, 0xE0, 0x7F, // 65533 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0xF8, 0x01, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, + 0x00, 0x00, 0x00, 0xF8, 0x01, 0x00, 0x18, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0x01, 0x00, 0xE0, 0x00, 0x00, 0x18, 0x00, 0x00, + 0xF8, 0x01, // 8482 + 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0xC0, 0x3F, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, + 0xC0, 0x7F, 0x00, 0x00, 0x44, 0x00, 0x00, 0x44, 0x00, 0x00, 0x44, 0x00, 0x00, 0x44, 0x00, 0x00, 0x64, 0x00, 0x00, + 0x38, // 1113 + 0x00, 0x00, 0x00, 0x80, 0x20, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x04, // 8250 + 0x00, 0x00, 0x00, 0xC0, 0x7F, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0xC0, 0x7F, 0x00, + 0x00, 0x44, 0x00, 0x00, 0x44, 0x00, 0x00, 0x44, 0x00, 0x00, 0x44, 0x00, 0x00, 0x38, // 1114 + 0x00, 0x00, 0x00, 0xC0, 0x7F, 0x00, 0x00, 0x04, 0x00, 0x10, 0x04, 0x00, 0x08, 0x1B, 0x00, 0xC0, 0x20, 0x00, 0x40, + 0x40, // 1116 + 0x10, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x90, 0x00, 0x00, 0x50, 0x00, 0x00, 0x50, 0x00, 0x00, 0x40, 0x00, 0x00, 0x80, + 0x7F, // 1115 + 0x00, 0x00, 0x00, 0xC0, 0x7F, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0xC0, 0x03, 0x00, 0x40, 0x00, 0xC0, + 0x7F, // 1119 + 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x60, 0x40, 0x00, 0x81, 0x41, 0x00, 0x02, 0x66, 0x00, 0x02, 0x18, 0x00, 0x02, 0x06, 0x00, + 0x81, 0x01, 0x00, 0x60, 0x00, 0x00, 0x18, // 1038 + 0xC0, 0x01, 0x00, 0x08, 0x06, 0x02, 0x10, 0x38, 0x02, 0x10, 0xC0, 0x01, 0x10, 0x38, 0x00, 0x08, 0x07, 0x00, 0xC0, // 1118 + 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0xF8, + 0x3F, // 1032 + 0x00, 0x00, 0x00, 0x40, 0x0B, 0x00, 0x80, 0x04, 0x00, 0x40, 0x08, 0x00, 0x40, 0x08, 0x00, 0x80, 0x04, 0x00, 0x40, 0x0B, // 164 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, + 0x0F, // 1168 + 0x00, 0x00, 0x00, 0xF8, 0xF1, 0x03, // 166 + 0x00, 0x86, 0x00, 0x70, 0x09, 0x01, 0xC8, 0x10, 0x02, 0x88, 0x10, 0x02, 0x08, 0x21, 0x02, 0x08, 0x61, 0x02, 0x30, 0xD2, 0x01, + 0x00, 0x0C, // 167 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x08, 0x41, 0x00, 0x0A, 0x41, 0x00, 0x08, 0x41, 0x00, 0x0A, 0x41, 0x00, 0x08, 0x41, 0x00, + 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, 0x08, 0x40, // 1025 + 0xC0, 0x0F, 0x00, 0x20, 0x10, 0x00, 0x10, 0x20, 0x00, 0xC8, 0x47, 0x00, 0x28, 0x48, 0x00, 0x28, 0x48, 0x00, 0x28, 0x48, 0x00, + 0x28, 0x48, 0x00, 0x48, 0x44, 0x00, 0x10, 0x20, 0x00, 0x20, 0x10, 0x00, 0xC0, 0x0F, // 169 + 0x00, 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x20, 0x11, 0x00, 0x10, 0x21, 0x00, 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, + 0x08, 0x40, 0x00, 0x08, 0x40, 0x00, 0x10, 0x20, 0x00, 0x20, 0x10, // 1028 + 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x1B, 0x00, 0x80, 0x20, 0x00, 0x00, 0x04, 0x00, 0x00, 0x1B, 0x00, 0x80, 0x20, // 171 + 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, 0x00, 0x00, + 0x80, 0x0F, // 172 + 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, // 173 + 0xC0, 0x0F, 0x00, 0x20, 0x10, 0x00, 0x10, 0x20, 0x00, 0xE8, 0x4F, 0x00, 0x28, 0x41, 0x00, 0x28, 0x41, 0x00, 0x28, 0x43, 0x00, + 0x28, 0x45, 0x00, 0xC8, 0x48, 0x00, 0x10, 0x20, 0x00, 0x20, 0x10, 0x00, 0xC0, 0x0F, // 174 + 0x02, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x02, // 1031 + 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x48, 0x00, 0x00, 0x48, 0x00, 0x00, 0x30, // 176 + 0x00, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x41, 0x00, 0x00, 0x41, 0x00, 0xE0, 0x4F, 0x00, 0x00, 0x41, 0x00, 0x00, 0x41, 0x00, + 0x00, 0x41, // 177 + 0x00, 0x00, 0x00, 0xF8, 0x7F, // 1030 + 0x00, 0x00, 0x00, 0xC8, 0x7F, // 1110 + 0x00, 0x00, 0x00, 0xC0, 0x7F, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x78, // 1169 + 0x00, 0x00, 0x00, 0xC0, 0xFF, 0x03, 0x00, 0x20, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x20, 0x00, + 0xC0, 0x7F, // 181 + 0xF0, 0x00, 0x00, 0xF8, 0x00, 0x00, 0xF8, 0x01, 0x00, 0xF8, 0x01, 0x00, 0xF8, 0xFF, 0x03, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, + 0xF8, 0xFF, 0x03, 0x08, // 182 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, // 183 + 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x80, 0x24, 0x00, 0x50, 0x44, 0x00, 0x40, 0x44, 0x00, 0x50, 0x44, 0x00, 0x80, 0x24, 0x00, + 0x00, 0x17, // 1105 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x20, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x06, 0x00, 0x00, 0x08, 0x00, + 0x00, 0x10, 0x00, 0xF8, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x80, 0x27, 0x00, 0x40, 0x28, 0x00, 0x40, 0x28, 0x00, 0x40, 0x28, 0x00, + 0x40, 0x28, 0x00, 0x80, 0x27, // 8470 + 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x80, 0x24, 0x00, 0x40, 0x44, 0x00, 0x40, 0x44, 0x00, 0x80, 0x20, 0x00, 0x00, + 0x11, // 1108 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x20, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x04, 0x00, 0x80, 0x20, 0x00, 0x00, 0x1B, 0x00, + 0x00, 0x04, // 187 + 0x00, 0x00, 0x02, 0xC8, 0xFF, 0x01, // 1112 + 0x00, 0x00, 0x00, 0x60, 0x10, 0x00, 0x90, 0x20, 0x00, 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, 0x08, 0x42, 0x00, + 0x08, 0x42, 0x00, 0x10, 0x22, 0x00, 0x20, 0x1C, // 1029 + 0x00, 0x00, 0x00, 0x80, 0x23, 0x00, 0x40, 0x44, 0x00, 0x40, 0x44, 0x00, 0x40, 0x44, 0x00, 0x40, 0x44, 0x00, 0x80, + 0x38, // 1109 + 0x10, 0x00, 0x00, 0xC0, 0x7F, 0x00, 0x10, // 1111 + 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x1C, 0x00, 0x80, 0x07, 0x00, 0x70, 0x04, 0x00, 0x08, 0x04, 0x00, 0x70, 0x04, 0x00, + 0x80, 0x07, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x60, // 1040 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, + 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, 0x00, 0x3E, // 1041 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, + 0x08, 0x41, 0x00, 0x90, 0x22, 0x00, 0x60, 0x1C, // 1042 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x08, // 1043 + 0x00, 0xC0, 0x03, 0x00, 0x60, 0x00, 0x00, 0x5C, 0x00, 0xF8, 0x43, 0x00, 0x08, 0x40, 0x00, 0x08, 0x40, 0x00, 0x08, 0x40, 0x00, + 0x08, 0x40, 0x00, 0xF8, 0x7F, 0x00, 0x00, 0xC0, 0x03, // 1044 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, + 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, 0x08, 0x40, // 1045 + 0x08, 0x30, 0x00, 0x10, 0x08, 0x00, 0x60, 0x04, 0x00, 0x80, 0x02, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0xF8, 0x7F, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x80, 0x02, 0x00, 0x60, 0x04, 0x00, 0x10, 0x08, 0x00, 0x08, 0x30, 0x00, 0x08, + 0x40, // 1046 + 0x00, 0x00, 0x00, 0x20, 0x10, 0x00, 0x10, 0x20, 0x00, 0x08, 0x40, 0x00, 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, 0x88, 0x42, 0x00, + 0x70, 0x42, 0x00, 0x00, 0x3C, // 1047 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x00, 0x30, 0x00, 0x00, 0x08, 0x00, 0x00, 0x04, 0x00, 0x00, 0x02, 0x00, 0x00, 0x01, 0x00, + 0x80, 0x00, 0x00, 0x40, 0x00, 0x00, 0x30, 0x00, 0x00, 0xF8, 0x7F, // 1048 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x00, 0x30, 0x00, 0x00, 0x08, 0x00, 0x01, 0x04, 0x00, 0x02, 0x02, 0x00, 0x02, 0x01, 0x00, + 0x82, 0x00, 0x00, 0x41, 0x00, 0x00, 0x30, 0x00, 0x00, 0xF8, 0x7F, // 1049 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x80, 0x02, 0x00, 0x60, 0x04, 0x00, 0x10, 0x08, 0x00, + 0x08, 0x30, 0x00, 0x08, 0x40, // 1050 + 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0xF8, 0x3F, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0xF8, 0x7F, // 1051 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x30, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x60, 0x00, + 0x00, 0x1C, 0x00, 0x00, 0x03, 0x00, 0xC0, 0x00, 0x00, 0x30, 0x00, 0x00, 0xF8, 0x7F, // 1052 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0xF8, 0x7F, // 1053 + 0x00, 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x20, 0x10, 0x00, 0x10, 0x20, 0x00, 0x08, 0x40, 0x00, 0x08, 0x40, 0x00, 0x08, 0x40, 0x00, + 0x08, 0x40, 0x00, 0x10, 0x20, 0x00, 0x20, 0x10, 0x00, 0xC0, 0x0F, // 1054 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0xF8, 0x7F, // 1055 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x08, 0x02, 0x00, 0x08, 0x02, 0x00, 0x08, 0x02, 0x00, 0x08, 0x02, 0x00, 0x08, 0x02, 0x00, + 0x08, 0x02, 0x00, 0x10, 0x01, 0x00, 0xE0, // 1056 + 0x00, 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x20, 0x10, 0x00, 0x10, 0x20, 0x00, 0x08, 0x40, 0x00, 0x08, 0x40, 0x00, 0x08, 0x40, 0x00, + 0x08, 0x40, 0x00, 0x08, 0x40, 0x00, 0x10, 0x20, 0x00, 0x20, 0x10, // 1057 + 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x08, // 1058 + 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x60, 0x40, 0x00, 0x80, 0x41, 0x00, 0x00, 0x66, 0x00, 0x00, 0x18, 0x00, 0x00, 0x06, 0x00, + 0x80, 0x01, 0x00, 0x60, 0x00, 0x00, 0x18, // 1059 + 0x00, 0x00, 0x00, 0x80, 0x07, 0x00, 0x40, 0x08, 0x00, 0x20, 0x10, 0x00, 0x20, 0x10, 0x00, 0xF8, 0x7F, 0x00, 0x20, 0x10, 0x00, + 0x20, 0x10, 0x00, 0x40, 0x08, 0x00, 0x80, 0x07, // 1060 + 0x00, 0x40, 0x00, 0x08, 0x20, 0x00, 0x10, 0x18, 0x00, 0x60, 0x04, 0x00, 0x80, 0x02, 0x00, 0x00, 0x01, 0x00, 0x80, 0x02, 0x00, + 0x60, 0x0C, 0x00, 0x10, 0x10, 0x00, 0x08, 0x20, 0x00, 0x00, 0x40, // 1061 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, + 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0xF8, 0x7F, 0x00, 0x00, 0xC0, 0x03, // 1062 + 0x00, 0x00, 0x00, 0xF8, 0x03, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, + 0x00, 0x02, 0x00, 0xF8, 0x7F, // 1063 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0xF8, 0x7F, 0x00, + 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0xF8, 0x7F, // 1064 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0xF8, 0x7F, 0x00, + 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0xF8, 0x7F, 0x00, 0x00, 0xC0, 0x03, // 1065 + 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x00, 0x41, 0x00, 0x00, 0x41, 0x00, 0x00, 0x41, 0x00, + 0x00, 0x41, 0x00, 0x00, 0x41, 0x00, 0x00, 0x41, 0x00, 0x00, 0x41, 0x00, 0x00, 0x3E, // 1066 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x00, 0x41, 0x00, 0x00, 0x41, 0x00, 0x00, 0x41, 0x00, 0x00, 0x41, 0x00, 0x00, 0x41, 0x00, + 0x00, 0x41, 0x00, 0x00, 0x41, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x7F, // 1067 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x00, 0x41, 0x00, 0x00, 0x41, 0x00, 0x00, 0x41, 0x00, 0x00, 0x41, 0x00, 0x00, 0x41, 0x00, + 0x00, 0x41, 0x00, 0x00, 0x41, 0x00, 0x00, 0x3E, // 1068 + 0x00, 0x00, 0x00, 0x20, 0x10, 0x00, 0x10, 0x20, 0x00, 0x08, 0x40, 0x00, 0x08, 0x40, 0x00, 0x08, 0x41, 0x00, 0x08, 0x41, 0x00, + 0x08, 0x41, 0x00, 0x10, 0x21, 0x00, 0x20, 0x11, 0x00, 0xC0, 0x0F, // 1069 + 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x00, 0xC0, 0x0F, 0x00, 0x20, 0x10, 0x00, + 0x10, 0x20, 0x00, 0x08, 0x40, 0x00, 0x08, 0x40, 0x00, 0x08, 0x40, 0x00, 0x08, 0x40, 0x00, 0x10, 0x20, 0x00, 0x20, 0x10, 0x00, + 0xC0, 0x0F, // 1070 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x40, 0x00, 0x10, 0x21, 0x00, 0x08, 0x1A, 0x00, 0x08, 0x0E, 0x00, 0x08, 0x02, 0x00, + 0x08, 0x02, 0x00, 0x08, 0x02, 0x00, 0x08, 0x02, 0x00, 0xF8, 0x7F, // 1071 + 0x00, 0x00, 0x00, 0x00, 0x39, 0x00, 0x80, 0x44, 0x00, 0x40, 0x44, 0x00, 0x40, 0x44, 0x00, 0x40, 0x42, 0x00, 0x40, 0x22, 0x00, + 0x80, 0x7F, // 1072 + 0x00, 0x00, 0x00, 0xE0, 0x1F, 0x00, 0x90, 0x20, 0x00, 0x48, 0x40, 0x00, 0x48, 0x40, 0x00, 0x48, 0x40, 0x00, 0x88, 0x20, 0x00, + 0x08, 0x1F, // 1073 + 0x00, 0x00, 0x00, 0xC0, 0x7F, 0x00, 0x40, 0x44, 0x00, 0x40, 0x44, 0x00, 0x40, 0x44, 0x00, 0x40, 0x44, 0x00, 0x40, 0x44, 0x00, + 0x80, 0x3B, // 1074 + 0x00, 0x00, 0x00, 0xC0, 0x7F, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, // 1075 + 0x00, 0xC0, 0x01, 0x00, 0x70, 0x00, 0xC0, 0x4F, 0x00, 0x40, 0x40, 0x00, 0x40, 0x40, 0x00, 0x40, 0x40, 0x00, 0xC0, 0x7F, 0x00, + 0x00, 0xC0, 0x01, // 1076 + 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x80, 0x24, 0x00, 0x40, 0x44, 0x00, 0x40, 0x44, 0x00, 0x40, 0x44, 0x00, 0x80, 0x24, 0x00, + 0x00, 0x17, // 1077 + 0xC0, 0x20, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0xC0, 0x7F, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, + 0x00, 0x1B, 0x00, 0xC0, 0x20, 0x00, 0x40, 0x40, // 1078 + 0x80, 0x20, 0x00, 0x40, 0x40, 0x00, 0x40, 0x44, 0x00, 0x40, 0x44, 0x00, 0x40, 0x44, 0x00, 0x80, 0x3B, // 1079 + 0x00, 0x00, 0x00, 0xC0, 0x7F, 0x00, 0x00, 0x30, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x02, 0x00, 0x80, 0x01, 0x00, 0xC0, + 0x7F, // 1080 + 0x00, 0x00, 0x00, 0xC0, 0x7F, 0x00, 0x08, 0x30, 0x00, 0x10, 0x0C, 0x00, 0x10, 0x02, 0x00, 0x90, 0x01, 0x00, 0xC8, + 0x7F, // 1081 + 0x00, 0x00, 0x00, 0xC0, 0x7F, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x1B, 0x00, 0xC0, 0x20, 0x00, 0x40, + 0x40, // 1082 + 0x00, 0x40, 0x00, 0xC0, 0x3F, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0xC0, + 0x7F, // 1083 + 0x00, 0x00, 0x00, 0xC0, 0x7F, 0x00, 0xC0, 0x01, 0x00, 0x00, 0x06, 0x00, 0x00, 0x18, 0x00, 0x00, 0x60, 0x00, 0x00, 0x18, 0x00, + 0x00, 0x06, 0x00, 0xC0, 0x01, 0x00, 0xC0, 0x7F, // 1084 + 0x00, 0x00, 0x00, 0xC0, 0x7F, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0xC0, + 0x7F, // 1085 + 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x80, 0x20, 0x00, 0x40, 0x40, 0x00, 0x40, 0x40, 0x00, 0x40, 0x40, 0x00, 0x80, 0x20, 0x00, + 0x00, 0x1F, // 1086 + 0x00, 0x00, 0x00, 0xC0, 0x7F, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0xC0, + 0x7F, // 1087 + 0x00, 0x00, 0x00, 0xC0, 0xFF, 0x03, 0x80, 0x20, 0x00, 0x40, 0x40, 0x00, 0x40, 0x40, 0x00, 0x40, 0x40, 0x00, 0x80, 0x20, 0x00, + 0x00, 0x1F, // 1088 + 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x80, 0x20, 0x00, 0x40, 0x40, 0x00, 0x40, 0x40, 0x00, 0x40, 0x40, 0x00, 0x80, + 0x20, // 1089 + 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0xC0, 0x7F, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, // 1090 + 0xC0, 0x01, 0x00, 0x00, 0x06, 0x02, 0x00, 0x38, 0x02, 0x00, 0xC0, 0x01, 0x00, 0x38, 0x00, 0x00, 0x07, 0x00, 0xC0, // 1091 + 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x80, 0x20, 0x00, 0x40, 0x40, 0x00, 0x40, 0x40, 0x00, 0x80, 0x20, 0x00, 0xF8, 0xFF, 0x03, + 0x80, 0x20, 0x00, 0x40, 0x40, 0x00, 0x40, 0x40, 0x00, 0x80, 0x20, 0x00, 0x00, 0x1F, // 1092 + 0x40, 0x40, 0x00, 0x80, 0x20, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x04, 0x00, 0x00, 0x1B, 0x00, 0x80, 0x20, 0x00, 0x40, + 0x40, // 1093 + 0x00, 0x00, 0x00, 0xC0, 0x7F, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, + 0xC0, 0x7F, 0x00, 0x00, 0xC0, 0x03, // 1094 + 0x00, 0x00, 0x00, 0xC0, 0x03, 0x00, 0x00, 0x04, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0x00, 0x08, 0x00, 0xC0, + 0x7F, // 1095 + 0x00, 0x00, 0x00, 0xC0, 0x7F, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0xC0, 0x7F, 0x00, 0x00, 0x40, 0x00, + 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0xC0, 0x7F, // 1096 + 0x00, 0x00, 0x00, 0xC0, 0x7F, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0xC0, 0x7F, 0x00, 0x00, 0x40, 0x00, + 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0xC0, 0x7F, 0x00, 0x00, 0xC0, 0x03, // 1097 + 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x00, 0xC0, 0x7F, 0x00, 0x00, 0x44, 0x00, 0x00, 0x44, 0x00, 0x00, 0x44, 0x00, + 0x00, 0x44, 0x00, 0x00, 0x38, // 1098 + 0x00, 0x00, 0x00, 0xC0, 0x7F, 0x00, 0x00, 0x44, 0x00, 0x00, 0x44, 0x00, 0x00, 0x44, 0x00, 0x00, 0x44, 0x00, 0x00, 0x44, 0x00, + 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x7F, // 1099 + 0x00, 0x00, 0x00, 0xC0, 0x7F, 0x00, 0x00, 0x44, 0x00, 0x00, 0x44, 0x00, 0x00, 0x44, 0x00, 0x00, 0x44, 0x00, 0x00, 0x44, 0x00, + 0x00, 0x38, // 1100 + 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x80, 0x20, 0x00, 0x40, 0x44, 0x00, 0x40, 0x44, 0x00, 0x80, 0x24, 0x00, 0x00, + 0x1F, // 1101 + 0x00, 0x00, 0x00, 0xC0, 0x7F, 0x00, 0x00, 0x04, 0x00, 0x00, 0x04, 0x00, 0x00, 0x1F, 0x00, 0x80, 0x20, 0x00, 0x40, 0x40, 0x00, + 0x40, 0x40, 0x00, 0x40, 0x40, 0x00, 0x80, 0x20, 0x00, 0x00, 0x1F, // 1102 + 0x00, 0x00, 0x00, 0x80, 0x63, 0x00, 0x40, 0x14, 0x00, 0x40, 0x0C, 0x00, 0x40, 0x04, 0x00, 0x40, 0x04, 0x00, 0x40, 0x04, 0x00, + 0xC0, 0x7F, // 1103 +}; + +const uint8_t ArialMT_Plain_24_UA[] PROGMEM = { + 0x18, // Width: 24 + 0x1C, // Height: 28 + 0x20, // First Char: 32 + 0xE0, // Numbers of Chars: 224 + // Jump Table: + 0xFF, 0xFF, 0x00, 0x07, // 32= :65535 + 0x00, 0x00, 0x13, 0x08, // 33=!:0 + 0x00, 0x13, 0x1A, 0x09, // 34=":19 + 0x00, 0x2D, 0x33, 0x0D, // 35=#:45 + 0x00, 0x60, 0x2F, 0x0D, // 36=$:96 + 0x00, 0x8F, 0x4F, 0x15, // 37=%:143 + 0x00, 0xDE, 0x3B, 0x10, // 38=&:222 + 0x01, 0x19, 0x0A, 0x05, // 39=':281 + 0x01, 0x23, 0x1C, 0x08, // 40=(:291 + 0x01, 0x3F, 0x1B, 0x08, // 41=):319 + 0x01, 0x5A, 0x22, 0x09, // 42=*:346 + 0x01, 0x7C, 0x33, 0x0E, // 43=+:380 + 0x01, 0xAF, 0x10, 0x07, // 44=,:431 + 0x01, 0xBF, 0x1B, 0x08, // 45=-:447 + 0x01, 0xDA, 0x0F, 0x07, // 46=.:474 + 0x01, 0xE9, 0x1A, 0x07, // 47=/:489 + 0x02, 0x03, 0x2F, 0x0D, // 48=0:515 + 0x02, 0x32, 0x23, 0x0D, // 49=1:562 + 0x02, 0x55, 0x2F, 0x0D, // 50=2:597 + 0x02, 0x84, 0x2F, 0x0D, // 51=3:644 + 0x02, 0xB3, 0x2F, 0x0D, // 52=4:691 + 0x02, 0xE2, 0x2F, 0x0D, // 53=5:738 + 0x03, 0x11, 0x2F, 0x0D, // 54=6:785 + 0x03, 0x40, 0x2E, 0x0D, // 55=7:832 + 0x03, 0x6E, 0x2F, 0x0D, // 56=8:878 + 0x03, 0x9D, 0x2F, 0x0D, // 57=9:925 + 0x03, 0xCC, 0x0F, 0x07, // 58=::972 + 0x03, 0xDB, 0x10, 0x07, // 59=;:987 + 0x03, 0xEB, 0x2F, 0x0E, // 60=<:1003 + 0x04, 0x1A, 0x2F, 0x0E, // 61==:1050 + 0x04, 0x49, 0x2E, 0x0E, // 62=>:1097 + 0x04, 0x77, 0x2E, 0x0D, // 63=?:1143 + 0x04, 0xA5, 0x5C, 0x18, // 64=@:1189 + 0x05, 0x01, 0x3B, 0x0F, // 65=A:1281 + 0x05, 0x3C, 0x3B, 0x10, // 66=B:1340 + 0x05, 0x77, 0x3F, 0x11, // 67=C:1399 + 0x05, 0xB6, 0x3F, 0x11, // 68=D:1462 + 0x05, 0xF5, 0x3B, 0x10, // 69=E:1525 + 0x06, 0x30, 0x36, 0x0F, // 70=F:1584 + 0x06, 0x66, 0x43, 0x13, // 71=G:1638 + 0x06, 0xA9, 0x3B, 0x11, // 72=H:1705 + 0x06, 0xE4, 0x0F, 0x06, // 73=I:1764 + 0x06, 0xF3, 0x27, 0x0C, // 74=J:1779 + 0x07, 0x1A, 0x3F, 0x10, // 75=K:1818 + 0x07, 0x59, 0x2F, 0x0D, // 76=L:1881 + 0x07, 0x88, 0x43, 0x13, // 77=M:1928 + 0x07, 0xCB, 0x3B, 0x11, // 78=N:1995 + 0x08, 0x06, 0x47, 0x13, // 79=O:2054 + 0x08, 0x4D, 0x3A, 0x10, // 80=P:2125 + 0x08, 0x87, 0x48, 0x13, // 81=Q:2183 + 0x08, 0xCF, 0x3F, 0x11, // 82=R:2255 + 0x09, 0x0E, 0x3B, 0x10, // 83=S:2318 + 0x09, 0x49, 0x36, 0x0E, // 84=T:2377 + 0x09, 0x7F, 0x3B, 0x11, // 85=U:2431 + 0x09, 0xBA, 0x39, 0x0F, // 86=V:2490 + 0x09, 0xF3, 0x5A, 0x17, // 87=W:2547 + 0x0A, 0x4D, 0x3B, 0x0F, // 88=X:2637 + 0x0A, 0x88, 0x3D, 0x10, // 89=Y:2696 + 0x0A, 0xC5, 0x37, 0x0F, // 90=Z:2757 + 0x0A, 0xFC, 0x14, 0x07, // 91=[:2812 + 0x0B, 0x10, 0x1B, 0x07, // 92=\:2832 + 0x0B, 0x2B, 0x18, 0x07, // 93=]:2859 + 0x0B, 0x43, 0x2A, 0x0C, // 94=^:2883 + 0x0B, 0x6D, 0x34, 0x0D, // 95=_:2925 + 0x0B, 0xA1, 0x12, 0x08, // 96=`:2977 + 0x0B, 0xB3, 0x2F, 0x0D, // 97=a:2995 + 0x0B, 0xE2, 0x33, 0x0E, // 98=b:3042 + 0x0C, 0x15, 0x2B, 0x0C, // 99=c:3093 + 0x0C, 0x40, 0x2F, 0x0E, // 100=d:3136 + 0x0C, 0x6F, 0x2F, 0x0D, // 101=e:3183 + 0x0C, 0x9E, 0x1A, 0x07, // 102=f:3230 + 0x0C, 0xB8, 0x30, 0x0E, // 103=g:3256 + 0x0C, 0xE8, 0x2F, 0x0E, // 104=h:3304 + 0x0D, 0x17, 0x0F, 0x05, // 105=i:3351 + 0x0D, 0x26, 0x10, 0x06, // 106=j:3366 + 0x0D, 0x36, 0x2F, 0x0C, // 107=k:3382 + 0x0D, 0x65, 0x0F, 0x06, // 108=l:3429 + 0x0D, 0x74, 0x47, 0x14, // 109=m:3444 + 0x0D, 0xBB, 0x2F, 0x0E, // 110=n:3515 + 0x0D, 0xEA, 0x2F, 0x0D, // 111=o:3562 + 0x0E, 0x19, 0x33, 0x0E, // 112=p:3609 + 0x0E, 0x4C, 0x30, 0x0E, // 113=q:3660 + 0x0E, 0x7C, 0x1E, 0x08, // 114=r:3708 + 0x0E, 0x9A, 0x2B, 0x0C, // 115=s:3738 + 0x0E, 0xC5, 0x1B, 0x07, // 116=t:3781 + 0x0E, 0xE0, 0x2F, 0x0E, // 117=u:3808 + 0x0F, 0x0F, 0x2A, 0x0B, // 118=v:3855 + 0x0F, 0x39, 0x42, 0x11, // 119=w:3897 + 0x0F, 0x7B, 0x2B, 0x0B, // 120=x:3963 + 0x0F, 0xA6, 0x2A, 0x0C, // 121=y:4006 + 0x0F, 0xD0, 0x2B, 0x0C, // 122=z:4048 + 0x0F, 0xFB, 0x1C, 0x08, // 123={:4091 + 0x10, 0x17, 0x10, 0x06, // 124=|:4119 + 0x10, 0x27, 0x1B, 0x08, // 125=}:4135 + 0x10, 0x42, 0x33, 0x0E, // 126=~:4162 + 0xFF, 0xFF, 0x00, 0x12, // 127:65535 + 0x10, 0x75, 0x4F, 0x15, // 1026=� �..:4213 + 0x10, 0xC4, 0x32, 0x0D, // 1027=� �.:4292 + 0x10, 0xF6, 0x0C, 0x05, // 8218=��.�.:4342 + 0x11, 0x02, 0x22, 0x09, // 1107=�.�..:4354 + 0x11, 0x24, 0x1C, 0x08, // 8222=��.�.:4388 + 0x11, 0x40, 0x4B, 0x18, // 8230=��.�.:4416 + 0x11, 0x8B, 0x32, 0x0D, // 8224=��.� :4491 + 0x11, 0xBD, 0x33, 0x0D, // 8225=��.�.:4541 + 0x11, 0xF0, 0x2F, 0x0D, // 8364=��..�.:4592 + 0x12, 0x1F, 0x63, 0x1A, // 8240=��.��:4639 + 0x12, 0x82, 0x5F, 0x19, // 1033=� �.�:4738 + 0x12, 0xE1, 0x17, 0x08, // 8249=��.�..:4833 + 0x12, 0xF8, 0x5B, 0x18, // 1034=� �.:4856 + 0x13, 0x53, 0x37, 0x0E, // 1036=� �.:4947 + 0x13, 0x8A, 0x4F, 0x16, // 1035=� �..:5002 + 0x13, 0xD9, 0x3B, 0x11, // 1039=� �.:5081 + 0x14, 0x14, 0x30, 0x0E, // 1106=�.�..:5140 + 0x14, 0x44, 0x0A, 0x05, // 8216=��.Ч.:5188 + 0x14, 0x4E, 0x0A, 0x05, // 8217=��.�..:5198 + 0x14, 0x58, 0x1A, 0x08, // 8220=��.�.:5208 + 0x14, 0x72, 0x1A, 0x08, // 8221=��.�.:5234 + 0x14, 0x8C, 0x1B, 0x08, // 8226=��.�.:5260 + 0x14, 0xA7, 0x33, 0x0D, // 8211=��.�..:5287 + 0x14, 0xDA, 0x5F, 0x18, // 8212=��.�..:5338 + 0xFF, 0xFF, 0x00, 0x12, // 65533=��.�.:65535 + 0x15, 0x39, 0x5B, 0x18, // 8482=��..�.:5433 + 0x15, 0x94, 0x53, 0x16, // 1113=�.�..:5524 + 0x15, 0xE7, 0x1B, 0x08, // 8250=��.�.:5607 + 0x16, 0x02, 0x4B, 0x14, // 1114=�.�.:5634 + 0x16, 0x4D, 0x2B, 0x0B, // 1116=�.�.:5709 + 0x16, 0x78, 0x2F, 0x0E, // 1115=�.�.�:5752 + 0x16, 0xA7, 0x2F, 0x0D, // 1119=�.�.:5799 + 0xFF, 0xFF, 0x00, 0x07, // 160=�.� :65535 + 0x16, 0xD6, 0x36, 0x0F, // 1038=� �.:5846 + 0x17, 0x0C, 0x2A, 0x0C, // 1118=�.�.:5900 + 0x17, 0x36, 0x27, 0x0C, // 1032=� �..:5942 + 0x17, 0x5D, 0x33, 0x0D, // 164=�.�.:5981 + 0x17, 0x90, 0x2A, 0x0C, // 1168=�.�.:6032 + 0x17, 0xBA, 0x10, 0x06, // 166=�.�.:6074 + 0x17, 0xCA, 0x2F, 0x0D, // 167=�.�.:6090 + 0x17, 0xF9, 0x3B, 0x10, // 1025=� �.:6137 + 0x18, 0x34, 0x47, 0x12, // 169=�.��:6196 + 0x18, 0x7B, 0x3F, 0x11, // 1028=� �..:6267 + 0x18, 0xBA, 0x27, 0x0D, // 171=�.�.:6330 + 0x18, 0xE1, 0x2F, 0x0E, // 172=�.�.:6369 + 0x19, 0x10, 0x1B, 0x08, // 173=�.�:6416 + 0x19, 0x2B, 0x47, 0x12, // 174=�.�.:6443 + 0x19, 0x72, 0x15, 0x06, // 1031=� �..:6514 + 0x19, 0x87, 0x1E, 0x0A, // 176=�.��:6535 + 0x19, 0xA5, 0x33, 0x0D, // 177=�.�.:6565 + 0x19, 0xD8, 0x0F, 0x06, // 1030=� �. :6616 + 0x19, 0xE7, 0x0F, 0x05, // 1110=�.�..:6631 + 0x19, 0xF6, 0x22, 0x0A, // 1169=�.�.:6646 + 0x1A, 0x18, 0x2F, 0x0E, // 181=�.�.:6680 + 0x1A, 0x47, 0x32, 0x0D, // 182=�.�.:6727 + 0x1A, 0x79, 0x13, 0x08, // 183=�.��:6777 + 0x1A, 0x8C, 0x2F, 0x0D, // 1105=�.�.:6796 + 0x1A, 0xBB, 0x63, 0x1A, // 8470=��..�..:6843 + 0x1B, 0x1E, 0x2B, 0x0C, // 1108=�.�..:6942 + 0x1B, 0x49, 0x2F, 0x0D, // 187=�.�.:6985 + 0x1B, 0x78, 0x10, 0x06, // 1112=�.Ч.:7032 + 0x1B, 0x88, 0x3B, 0x10, // 1029=� �..:7048 + 0x1B, 0xC3, 0x2B, 0x0C, // 1109=�.�..:7107 + 0x1B, 0xEE, 0x16, 0x06, // 1111=�.�..:7150 + 0x1C, 0x04, 0x3B, 0x0F, // 1040=� �.:7172 + 0x1C, 0x3F, 0x3B, 0x10, // 1041=� �.:7231 + 0x1C, 0x7A, 0x3B, 0x10, // 1042=� �..:7290 + 0x1C, 0xB5, 0x32, 0x0D, // 1043=� �..:7349 + 0x1C, 0xE7, 0x40, 0x10, // 1044=� �..:7399 + 0x1D, 0x27, 0x3B, 0x10, // 1045=� �..:7463 + 0x1D, 0x62, 0x57, 0x16, // 1046=� �..:7522 + 0x1D, 0xB9, 0x37, 0x0F, // 1047=� �..:7609 + 0x1D, 0xF0, 0x3B, 0x11, // 1048=� Ч.:7664 + 0x1E, 0x2B, 0x3B, 0x11, // 1049=� �..:7723 + 0x1E, 0x66, 0x37, 0x0E, // 1050=� �.:7782 + 0x1E, 0x9D, 0x37, 0x10, // 1051=� �.�:7837 + 0x1E, 0xD4, 0x43, 0x13, // 1052=� �.:7892 + 0x1F, 0x17, 0x3B, 0x11, // 1053=� �.:7959 + 0x1F, 0x52, 0x47, 0x13, // 1054=� �.:8018 + 0x1F, 0x99, 0x3B, 0x11, // 1055=� �.:8089 + 0x1F, 0xD4, 0x3A, 0x10, // 1056=� � :8148 + 0x20, 0x0E, 0x3F, 0x11, // 1057=� �.:8206 + 0x20, 0x4D, 0x36, 0x0E, // 1058=� �.:8269 + 0x20, 0x83, 0x36, 0x0F, // 1059=� �.:8323 + 0x20, 0xB9, 0x43, 0x12, // 1060=� �.:8377 + 0x20, 0xFC, 0x3B, 0x0F, // 1061=� �.:8444 + 0x21, 0x37, 0x44, 0x12, // 1062=� �.:8503 + 0x21, 0x7B, 0x37, 0x10, // 1063=� �.:8571 + 0x21, 0xB2, 0x53, 0x16, // 1064=� �.:8626 + 0x22, 0x05, 0x5C, 0x17, // 1065=� ��:8709 + 0x22, 0x61, 0x47, 0x13, // 1066=� �.:8801 + 0x22, 0xA8, 0x4B, 0x15, // 1067=� �.:8872 + 0x22, 0xF3, 0x3B, 0x10, // 1068=� �.:8947 + 0x23, 0x2E, 0x3F, 0x11, // 1069=� �:9006 + 0x23, 0x6D, 0x5B, 0x18, // 1070=� �.:9069 + 0x23, 0xC8, 0x3B, 0x11, // 1071=� �.:9160 + 0x24, 0x03, 0x2F, 0x0D, // 1072=� ��:9219 + 0x24, 0x32, 0x33, 0x0E, // 1073=� �.:9266 + 0x24, 0x65, 0x2F, 0x0D, // 1074=� �.:9317 + 0x24, 0x94, 0x22, 0x09, // 1075=� �.:9364 + 0x24, 0xB6, 0x34, 0x0E, // 1076=� �.:9398 + 0x24, 0xEA, 0x2F, 0x0D, // 1077=� �.:9450 + 0x25, 0x19, 0x3B, 0x10, // 1078=� �.:9497 + 0x25, 0x54, 0x27, 0x0B, // 1079=� ��:9556 + 0x25, 0x7B, 0x2F, 0x0D, // 1080=� �.:9595 + 0x25, 0xAA, 0x2F, 0x0D, // 1081=� �..:9642 + 0x25, 0xD9, 0x2B, 0x0B, // 1082=� �.:9689 + 0x26, 0x04, 0x2F, 0x0E, // 1083=� �.:9732 + 0x26, 0x33, 0x3B, 0x11, // 1084=� �:9779 + 0x26, 0x6E, 0x2F, 0x0D, // 1085=� �.:9838 + 0x26, 0x9D, 0x2F, 0x0D, // 1086=� �.:9885 + 0x26, 0xCC, 0x2F, 0x0D, // 1087=� �.:9932 + 0x26, 0xFB, 0x33, 0x0E, // 1088=�.�.:9979 + 0x27, 0x2E, 0x2B, 0x0C, // 1089=�.�.:10030 + 0x27, 0x59, 0x26, 0x0B, // 1090=�.�..:10073 + 0x27, 0x7F, 0x2A, 0x0C, // 1091=�.�.:10111 + 0x27, 0xA9, 0x4B, 0x14, // 1092=�.�..:10153 + 0x27, 0xF4, 0x2B, 0x0B, // 1093=�.�..:10228 + 0x28, 0x1F, 0x34, 0x0E, // 1094=�.�. :10271 + 0x28, 0x53, 0x2B, 0x0D, // 1095=�.�..:10323 + 0x28, 0x7E, 0x47, 0x13, // 1096=�.�..:10366 + 0x28, 0xC5, 0x4C, 0x14, // 1097=�.�.�:10437 + 0x29, 0x11, 0x37, 0x0F, // 1098=�.�.:10513 + 0x29, 0x48, 0x3B, 0x11, // 1099=�.�..:10568 + 0x29, 0x83, 0x2F, 0x0D, // 1100=�.�.:10627 + 0x29, 0xB2, 0x2B, 0x0C, // 1101=�.�.:10674 + 0x29, 0xDD, 0x43, 0x12, // 1102=�.�.:10717 + 0x2A, 0x20, 0x2B, 0x0D, // 1103=�.�.:10784 + // Font Data: + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xCF, 0x00, 0x80, 0xFF, 0xCF, // 33 + 0x00, 0x00, 0x00, 0x00, 0x80, 0x1F, 0x00, 0x00, 0x80, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0x1F, 0x00, 0x00, 0x80, 0x1F, // 34 + 0x00, 0x30, 0x0C, 0x00, 0x00, 0x30, 0xCC, 0x00, 0x00, 0x30, 0xFE, 0x00, 0x00, 0xF0, 0x3F, 0x00, 0x00, 0xFE, 0x0F, 0x00, 0x80, + 0x3F, 0x0C, 0x00, 0x80, 0x31, 0xCC, 0x00, 0x00, 0x30, 0xFE, 0x00, 0x00, 0xF0, 0x3F, 0x00, 0x00, 0xFE, 0x0D, 0x00, 0x80, 0x3F, + 0x0C, 0x00, 0x80, 0x31, 0x0C, 0x00, 0x00, 0x30, 0x0C, // 35 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x18, 0x00, 0x00, 0x3F, 0x78, 0x00, 0x00, 0x63, 0x70, 0x00, 0x80, 0x61, 0xE0, 0x00, 0x80, + 0xC1, 0xC0, 0x00, 0xC0, 0xFF, 0xFF, 0x03, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0x81, 0xC1, 0x00, 0x00, 0x83, 0x61, 0x00, 0x00, 0x07, + 0x7F, 0x00, 0x00, 0x04, 0x1E, // 36 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x80, 0xC1, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, + 0x80, 0x80, 0x00, 0x80, 0xC1, 0xE0, 0x00, 0x00, 0x7F, 0x78, 0x00, 0x00, 0x3E, 0x3E, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0xC0, + 0x03, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x3C, 0x3E, 0x00, 0x00, 0x0F, 0x7F, 0x00, 0x80, 0x83, 0xC1, 0x00, 0x80, 0x80, 0x80, + 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0xC1, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x3E, // 37 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x8E, 0x73, 0x00, 0x00, 0xDF, 0xE1, 0x00, 0x80, + 0xF3, 0xC0, 0x00, 0x80, 0xE1, 0xC0, 0x00, 0x80, 0xE1, 0xC1, 0x00, 0x80, 0xB3, 0xE3, 0x00, 0x00, 0x3F, 0x6E, 0x00, 0x00, 0x0E, + 0x7C, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x00, 0xE2, 0x00, 0x00, 0x00, 0x40, // 38 + 0x00, 0x00, 0x00, 0x00, 0x80, 0x1F, 0x00, 0x00, 0x80, 0x1F, // 39 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x3F, 0x00, 0x00, 0xF8, 0xFF, 0x01, 0x00, 0x3E, 0xC0, 0x07, 0x00, 0x07, 0x00, 0x0E, 0x80, + 0x01, 0x00, 0x18, 0x80, 0x00, 0x00, 0x10, // 40 + 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x10, 0x80, 0x01, 0x00, 0x18, 0x00, 0x07, 0x00, 0x0E, 0x00, 0x3E, 0xC0, 0x07, 0x00, + 0xF8, 0xFF, 0x01, 0x00, 0xC0, 0x3F, // 41 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x80, 0x0F, 0x00, 0x00, 0x80, + 0x0F, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x02, // 42 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, + 0x80, 0x01, 0x00, 0x00, 0xFC, 0x3F, 0x00, 0x00, 0xFC, 0x3F, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, + 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, // 43 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x0C, 0x00, 0x00, 0xC0, 0x07, // 44 + 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, + 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, // 45 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, // 46 + 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x80, 0x3F, 0x00, 0x00, 0xF0, 0x07, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x80, + 0x0F, 0x00, 0x00, 0x80, 0x01, // 47 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x0F, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0x07, 0x70, 0x00, 0x80, 0x03, 0xE0, 0x00, 0x80, + 0x01, 0xC0, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x80, 0x03, 0xE0, 0x00, 0x00, 0x07, 0x70, 0x00, 0x00, 0xFE, + 0x3F, 0x00, 0x00, 0xF8, 0x0F, // 48 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, + 0x0C, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, // 49 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0xC0, 0x00, 0x00, 0x0F, 0xE0, 0x00, 0x00, 0x03, 0xF0, 0x00, 0x80, 0x01, 0xD8, 0x00, 0x80, + 0x01, 0xCC, 0x00, 0x80, 0x01, 0xC6, 0x00, 0x80, 0x01, 0xC3, 0x00, 0x80, 0x81, 0xC1, 0x00, 0x00, 0xC3, 0xC0, 0x00, 0x00, 0x7F, + 0xC0, 0x00, 0x00, 0x3C, 0xC0, // 50 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x18, 0x00, 0x00, 0x07, 0x38, 0x00, 0x00, 0x03, 0x70, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x80, + 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x00, 0xE3, 0xC0, 0x00, 0x00, 0xBF, 0x61, 0x00, 0x00, 0x1E, + 0x3F, 0x00, 0x00, 0x00, 0x1E, // 51 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x00, 0xF0, 0x0C, 0x00, 0x00, + 0x38, 0x0C, 0x00, 0x00, 0x1E, 0x0C, 0x00, 0x00, 0x07, 0x0C, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0x00, + 0x0C, 0x00, 0x00, 0x00, 0x0C, // 52 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x18, 0x00, 0x00, 0xFE, 0x38, 0x00, 0x80, 0x7F, 0x60, 0x00, 0x80, 0x21, 0xC0, 0x00, 0x80, + 0x31, 0xC0, 0x00, 0x80, 0x31, 0xC0, 0x00, 0x80, 0x31, 0xC0, 0x00, 0x80, 0x31, 0xC0, 0x00, 0x80, 0x61, 0x70, 0x00, 0x80, 0xC1, + 0x3F, 0x00, 0x00, 0x80, 0x0F, // 53 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x0F, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0x8F, 0x71, 0x00, 0x00, 0xC3, 0xE0, 0x00, 0x80, + 0x61, 0xC0, 0x00, 0x80, 0x61, 0xC0, 0x00, 0x80, 0x61, 0xC0, 0x00, 0x80, 0x61, 0xC0, 0x00, 0x80, 0xC3, 0x60, 0x00, 0x00, 0xC7, + 0x3F, 0x00, 0x00, 0x06, 0x1F, // 54 + 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0xF0, 0x00, 0x80, + 0x01, 0xFE, 0x00, 0x80, 0xC1, 0x0F, 0x00, 0x80, 0xE1, 0x01, 0x00, 0x80, 0x39, 0x00, 0x00, 0x80, 0x0D, 0x00, 0x00, 0x80, 0x07, + 0x00, 0x00, 0x80, 0x01, // 55 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x1E, 0x7F, 0x00, 0x00, 0xBF, 0x61, 0x00, 0x80, 0xE3, 0xC0, 0x00, 0x80, + 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xE3, 0xC0, 0x00, 0x00, 0xBF, 0x61, 0x00, 0x00, 0x1E, + 0x7F, 0x00, 0x00, 0x00, 0x1E, // 56 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x30, 0x00, 0x00, 0xFE, 0x71, 0x00, 0x00, 0x87, 0xE1, 0x00, 0x80, 0x01, 0xC3, 0x00, 0x80, + 0x01, 0xC3, 0x00, 0x80, 0x01, 0xC3, 0x00, 0x80, 0x01, 0xC3, 0x00, 0x80, 0x81, 0x61, 0x00, 0x00, 0xC7, 0x78, 0x00, 0x00, 0xFE, + 0x3F, 0x00, 0x00, 0xF8, 0x07, // 57 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, 0x18, 0xC0, // 58 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xC0, 0x0C, 0x00, 0x18, 0xC0, 0x07, // 59 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 0x60, 0x03, 0x00, 0x00, + 0x60, 0x03, 0x00, 0x00, 0x30, 0x06, 0x00, 0x00, 0x30, 0x06, 0x00, 0x00, 0x10, 0x04, 0x00, 0x00, 0x18, 0x0C, 0x00, 0x00, 0x18, + 0x0C, 0x00, 0x00, 0x0C, 0x18, // 60 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x06, 0x00, 0x00, 0x30, 0x06, 0x00, 0x00, 0x30, 0x06, 0x00, 0x00, 0x30, 0x06, 0x00, 0x00, + 0x30, 0x06, 0x00, 0x00, 0x30, 0x06, 0x00, 0x00, 0x30, 0x06, 0x00, 0x00, 0x30, 0x06, 0x00, 0x00, 0x30, 0x06, 0x00, 0x00, 0x30, + 0x06, 0x00, 0x00, 0x30, 0x06, // 61 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x18, 0x00, 0x00, 0x18, 0x0C, 0x00, 0x00, 0x18, 0x0C, 0x00, 0x00, 0x10, 0x04, 0x00, 0x00, + 0x30, 0x06, 0x00, 0x00, 0x30, 0x06, 0x00, 0x00, 0x60, 0x03, 0x00, 0x00, 0x60, 0x03, 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 0xC0, + 0x01, 0x00, 0x00, 0x80, // 62 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0x80, + 0x01, 0xCE, 0x00, 0x80, 0x01, 0xCF, 0x00, 0x80, 0x81, 0x01, 0x00, 0x80, 0xC1, 0x00, 0x00, 0x00, 0xE3, 0x00, 0x00, 0x00, 0x7F, + 0x00, 0x00, 0x00, 0x1C, // 63 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3F, 0x00, 0x00, 0xE0, 0xFF, 0x00, 0x00, 0x78, 0xC0, 0x03, 0x00, 0x1C, 0x00, 0x07, 0x00, + 0x0E, 0x1F, 0x06, 0x00, 0xC7, 0x7F, 0x0E, 0x00, 0xE3, 0x60, 0x0C, 0x00, 0x33, 0xC0, 0x0C, 0x80, 0x39, 0xC0, 0x18, 0x80, 0x19, + 0xC0, 0x18, 0x80, 0x19, 0x60, 0x18, 0x80, 0x19, 0x30, 0x18, 0x80, 0x31, 0x78, 0x18, 0x80, 0xE1, 0xFF, 0x18, 0x80, 0xFB, 0xC7, + 0x18, 0x00, 0x3B, 0xC0, 0x18, 0x00, 0x07, 0x60, 0x0C, 0x00, 0x0E, 0x70, 0x0C, 0x00, 0x1C, 0x3C, 0x06, 0x00, 0xF8, 0x1F, 0x06, + 0x00, 0xE0, 0x07, 0x03, 0x00, 0x00, 0x00, 0x01, // 64 + 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x00, 0xF8, 0x07, 0x00, 0x00, + 0x3E, 0x06, 0x00, 0x80, 0x0F, 0x06, 0x00, 0x80, 0x01, 0x06, 0x00, 0x80, 0x0F, 0x06, 0x00, 0x00, 0x3E, 0x06, 0x00, 0x00, 0xF8, + 0x07, 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x00, 0xC0, // 65 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, + 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, + 0xC0, 0x00, 0x00, 0xE3, 0xC1, 0x00, 0x00, 0xFF, 0x61, 0x00, 0x00, 0x1E, 0x7F, 0x00, 0x00, 0x00, 0x1E, // 66 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x07, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0x1E, 0x3C, 0x00, 0x00, 0x07, 0x70, 0x00, 0x00, + 0x03, 0x60, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x80, 0x01, + 0xC0, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x00, 0x03, 0x60, 0x00, 0x00, 0x07, 0x70, 0x00, 0x00, 0x0E, 0x3C, 0x00, 0x00, 0x08, + 0x0C, // 67 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x80, + 0x01, 0xC0, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x80, 0x01, + 0xC0, 0x00, 0x80, 0x03, 0x60, 0x00, 0x00, 0x07, 0x70, 0x00, 0x00, 0x0E, 0x38, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xF0, + 0x07, // 68 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, + 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, + 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0x01, 0xC0, // 69 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xC1, 0x00, 0x00, 0x80, + 0xC1, 0x00, 0x00, 0x80, 0xC1, 0x00, 0x00, 0x80, 0xC1, 0x00, 0x00, 0x80, 0xC1, 0x00, 0x00, 0x80, 0xC1, 0x00, 0x00, 0x80, 0xC1, + 0x00, 0x00, 0x80, 0xC1, 0x00, 0x00, 0x80, 0xC1, 0x00, 0x00, 0x80, 0x01, // 70 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x07, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0x1E, 0x3C, 0x00, 0x00, 0x07, 0x70, 0x00, 0x00, + 0x03, 0x60, 0x00, 0x80, 0x03, 0x60, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x80, 0x81, + 0xC1, 0x00, 0x80, 0x81, 0xC1, 0x00, 0x80, 0x83, 0xC1, 0x00, 0x00, 0x83, 0x61, 0x00, 0x00, 0x87, 0x61, 0x00, 0x00, 0x8E, 0x3F, + 0x00, 0x00, 0x88, 0x3F, // 71 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, + 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, + 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, // 72 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, // 73 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, + 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x80, 0xFF, 0x7F, 0x00, 0x80, 0xFF, 0x3F, // 74 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, + 0xC0, 0x01, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0xF0, 0x01, 0x00, 0x00, 0xF8, 0x03, 0x00, 0x00, 0x9C, 0x07, 0x00, 0x00, 0x0E, + 0x1E, 0x00, 0x00, 0x07, 0x3C, 0x00, 0x80, 0x03, 0x78, 0x00, 0x80, 0x01, 0xE0, 0x00, 0x80, 0x00, 0xC0, 0x00, 0x00, 0x00, + 0x80, // 75 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, + 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, + 0xC0, 0x00, 0x00, 0x00, 0xC0, // 76 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0x07, 0x00, 0x00, 0x00, + 0x3F, 0x00, 0x00, 0x00, 0xF8, 0x03, 0x00, 0x00, 0x80, 0x1F, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, + 0xFC, 0x00, 0x00, 0x80, 0x1F, 0x00, 0x00, 0xF8, 0x03, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0x80, 0xFF, 0xFF, + 0x00, 0x80, 0xFF, 0xFF, // 77 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x0E, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0x00, + 0x0E, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x70, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, // 78 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x07, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0x1E, 0x3C, 0x00, 0x00, 0x07, 0x70, 0x00, 0x00, + 0x03, 0x60, 0x00, 0x80, 0x03, 0xE0, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x80, 0x01, + 0xC0, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x80, 0x03, 0xE0, 0x00, 0x00, 0x03, 0x60, 0x00, 0x00, 0x07, 0x70, 0x00, 0x00, 0x1E, 0x3C, + 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xF0, 0x07, // 79 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0x81, 0x01, 0x00, 0x80, + 0x81, 0x01, 0x00, 0x80, 0x81, 0x01, 0x00, 0x80, 0x81, 0x01, 0x00, 0x80, 0x81, 0x01, 0x00, 0x80, 0x81, 0x01, 0x00, 0x80, 0x81, + 0x01, 0x00, 0x80, 0x81, 0x01, 0x00, 0x00, 0xC3, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x3C, // 80 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x07, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0x1E, 0x3C, 0x00, 0x00, 0x07, 0x30, 0x00, 0x00, + 0x03, 0x60, 0x00, 0x80, 0x03, 0x60, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x80, 0x01, + 0xD8, 0x00, 0x80, 0x01, 0xD8, 0x00, 0x80, 0x03, 0xF0, 0x00, 0x00, 0x03, 0x70, 0x00, 0x00, 0x07, 0x70, 0x00, 0x00, 0x1E, 0xFC, + 0x00, 0x00, 0xFC, 0xDF, 0x01, 0x00, 0xF0, 0x87, 0x01, // 81 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xC1, 0x00, 0x00, 0x80, + 0xC1, 0x00, 0x00, 0x80, 0xC1, 0x00, 0x00, 0x80, 0xC1, 0x00, 0x00, 0x80, 0xC1, 0x01, 0x00, 0x80, 0xC1, 0x03, 0x00, 0x80, 0xC1, + 0x0F, 0x00, 0x80, 0xC1, 0x1E, 0x00, 0x80, 0x63, 0x7C, 0x00, 0x00, 0x7F, 0xF0, 0x00, 0x00, 0x3E, 0xC0, 0x00, 0x00, 0x00, + 0x80, // 82 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x1C, 0x3C, 0x00, 0x00, 0x7F, 0x70, 0x00, 0x00, 0x63, 0x60, 0x00, 0x80, + 0xE1, 0xE0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, + 0xC1, 0x00, 0x80, 0x83, 0xE1, 0x00, 0x00, 0x87, 0x63, 0x00, 0x00, 0x0E, 0x3F, 0x00, 0x00, 0x0C, 0x1E, // 83 + 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, + 0x01, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, + 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, // 84 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0x0F, 0x00, 0x80, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0xE0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, + 0xC0, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0x70, 0x00, 0x80, 0xFF, 0x3F, 0x00, 0x80, 0xFF, 0x0F, // 85 + 0x80, 0x00, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x00, 0xE0, 0x07, 0x00, 0x00, + 0x00, 0x3F, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0xE0, + 0x07, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0x80, // 86 + 0x80, 0x01, 0x00, 0x00, 0x80, 0x1F, 0x00, 0x00, 0x00, 0xFE, 0x03, 0x00, 0x00, 0xE0, 0x3F, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, + 0x00, 0xC0, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x80, 0x3F, 0x00, 0x00, 0xF0, 0x07, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x80, 0x0F, + 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x0F, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0xF0, 0x07, 0x00, 0x00, 0x80, 0x3F, + 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, 0xE0, 0x3F, 0x00, 0x00, 0xFE, 0x03, 0x00, + 0x80, 0x1F, 0x00, 0x00, 0x80, 0x01, // 87 + 0x00, 0x00, 0x80, 0x00, 0x80, 0x00, 0xC0, 0x00, 0x80, 0x01, 0xF0, 0x00, 0x80, 0x07, 0x78, 0x00, 0x00, 0x0F, 0x1E, 0x00, 0x00, + 0x3C, 0x0F, 0x00, 0x00, 0xF8, 0x07, 0x00, 0x00, 0xE0, 0x01, 0x00, 0x00, 0xF8, 0x07, 0x00, 0x00, 0x1E, 0x0F, 0x00, 0x00, 0x0F, + 0x1C, 0x00, 0x80, 0x07, 0x78, 0x00, 0x80, 0x01, 0xF0, 0x00, 0x80, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x80, // 88 + 0x80, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, + 0x78, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, 0xC0, 0xFF, 0x00, 0x00, 0xC0, 0xFF, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x78, + 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, // 89 + 0x00, 0x00, 0xC0, 0x00, 0x80, 0x01, 0xE0, 0x00, 0x80, 0x01, 0xF0, 0x00, 0x80, 0x01, 0xDC, 0x00, 0x80, 0x01, 0xCE, 0x00, 0x80, + 0x01, 0xC7, 0x00, 0x80, 0x81, 0xC3, 0x00, 0x80, 0xE1, 0xC0, 0x00, 0x80, 0x71, 0xC0, 0x00, 0x80, 0x39, 0xC0, 0x00, 0x80, 0x1D, + 0xC0, 0x00, 0x80, 0x07, 0xC0, 0x00, 0x80, 0x03, 0xC0, 0x00, 0x80, 0x01, 0xC0, // 90 + 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x1F, 0x80, 0xFF, 0xFF, 0x1F, 0x80, 0x01, 0x00, 0x18, 0x80, 0x01, 0x00, 0x18, // 91 + 0x80, 0x01, 0x00, 0x00, 0x80, 0x0F, 0x00, 0x00, 0x00, 0xFE, 0x00, 0x00, 0x00, 0xF0, 0x07, 0x00, 0x00, 0x80, 0x3F, 0x00, 0x00, + 0x00, 0xF8, 0x00, 0x00, 0x00, 0xC0, // 92 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x18, 0x80, 0x01, 0x00, 0x18, 0x80, 0xFF, 0xFF, 0x1F, 0x80, + 0xFF, 0xFF, 0x1F, // 93 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x80, + 0x03, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, + 0x80, // 94 + 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, + 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, + 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, // 95 + 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0x00, 0x02, // 96 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x38, 0x00, 0x00, 0x70, 0x7C, 0x00, 0x00, 0x30, 0xE6, 0x00, 0x00, 0x18, 0xC6, 0x00, 0x00, + 0x18, 0xC6, 0x00, 0x00, 0x18, 0xC3, 0x00, 0x00, 0x18, 0x63, 0x00, 0x00, 0x38, 0x63, 0x00, 0x00, 0xF0, 0x7F, 0x00, 0x00, 0xE0, + 0xFF, 0x00, 0x00, 0x00, 0x80, // 97 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0x60, 0x30, 0x00, 0x00, + 0x30, 0x60, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, 0x38, 0xE0, 0x00, 0x00, 0x70, + 0x70, 0x00, 0x00, 0xE0, 0x3F, 0x00, 0x00, 0x80, 0x0F, // 98 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x1F, 0x00, 0x00, 0xE0, 0x3F, 0x00, 0x00, 0x70, 0x70, 0x00, 0x00, 0x38, 0xE0, 0x00, 0x00, + 0x18, 0xC0, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, 0x38, 0xE0, 0x00, 0x00, 0x70, 0x70, 0x00, 0x00, 0x60, + 0x30, // 99 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x0F, 0x00, 0x00, 0xE0, 0x3F, 0x00, 0x00, 0x70, 0x70, 0x00, 0x00, 0x38, 0xE0, 0x00, 0x00, + 0x18, 0xC0, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, 0x30, 0x60, 0x00, 0x00, 0x70, 0x30, 0x00, 0x80, 0xFF, + 0xFF, 0x00, 0x80, 0xFF, 0xFF, // 100 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x1F, 0x00, 0x00, 0xE0, 0x3F, 0x00, 0x00, 0x70, 0x73, 0x00, 0x00, 0x38, 0xE3, 0x00, 0x00, + 0x18, 0xC3, 0x00, 0x00, 0x18, 0xC3, 0x00, 0x00, 0x18, 0xC3, 0x00, 0x00, 0x38, 0xE3, 0x00, 0x00, 0x70, 0x63, 0x00, 0x00, 0xE0, + 0x33, 0x00, 0x00, 0xC0, 0x13, // 101 + 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0x19, 0x00, 0x00, 0x80, + 0x19, 0x00, 0x00, 0x80, 0x19, // 102 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x0F, 0x06, 0x00, 0xE0, 0x3F, 0x0E, 0x00, 0x70, 0x70, 0x1C, 0x00, 0x38, 0xE0, 0x18, 0x00, + 0x18, 0xC0, 0x18, 0x00, 0x18, 0xC0, 0x18, 0x00, 0x18, 0xC0, 0x18, 0x00, 0x30, 0x60, 0x1C, 0x00, 0x60, 0x30, 0x0E, 0x00, 0xF8, + 0xFF, 0x07, 0x00, 0xF8, 0xFF, 0x03, // 103 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, + 0x30, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0xF0, + 0xFF, 0x00, 0x00, 0xE0, 0xFF, // 104 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xF9, 0xFF, 0x00, 0x80, 0xF9, 0xFF, // 105 + 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x80, 0xF9, 0xFF, 0x1F, 0x80, 0xF9, 0xFF, 0x0F, // 106 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, + 0x80, 0x03, 0x00, 0x00, 0xC0, 0x07, 0x00, 0x00, 0x60, 0x1E, 0x00, 0x00, 0x30, 0x38, 0x00, 0x00, 0x18, 0xF0, 0x00, 0x00, 0x08, + 0xC0, 0x00, 0x00, 0x00, 0x80, // 107 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, // 108 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0xF0, 0xFF, 0x00, 0x00, 0xE0, + 0xFF, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x38, 0x00, + 0x00, 0x00, 0xF0, 0xFF, 0x00, 0x00, 0xE0, 0xFF, // 109 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, + 0x30, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0xF0, + 0xFF, 0x00, 0x00, 0xE0, 0xFF, // 110 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x1F, 0x00, 0x00, 0xE0, 0x3F, 0x00, 0x00, 0x70, 0x70, 0x00, 0x00, 0x38, 0xE0, 0x00, 0x00, + 0x18, 0xC0, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, 0x38, 0xE0, 0x00, 0x00, 0x70, 0x70, 0x00, 0x00, 0xE0, + 0x3F, 0x00, 0x00, 0xC0, 0x1F, // 111 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x1F, 0x00, 0xF8, 0xFF, 0x1F, 0x00, 0x60, 0x30, 0x00, 0x00, + 0x30, 0x60, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, 0x38, 0xE0, 0x00, 0x00, 0x70, + 0x70, 0x00, 0x00, 0xE0, 0x3F, 0x00, 0x00, 0xC0, 0x0F, // 112 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x00, 0xE0, 0x3F, 0x00, 0x00, 0x70, 0x70, 0x00, 0x00, 0x38, 0xE0, 0x00, 0x00, + 0x18, 0xC0, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, 0x30, 0x60, 0x00, 0x00, 0x60, 0x30, 0x00, 0x00, 0xF8, + 0xFF, 0x1F, 0x00, 0xF8, 0xFF, 0x1F, // 113 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, // 114 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x30, 0x00, 0x00, 0xF0, 0x71, 0x00, 0x00, 0xB8, 0xE3, 0x00, 0x00, 0x18, 0xC3, 0x00, 0x00, + 0x18, 0xC3, 0x00, 0x00, 0x18, 0xC7, 0x00, 0x00, 0x18, 0xC7, 0x00, 0x00, 0x38, 0xE6, 0x00, 0x00, 0x70, 0x7E, 0x00, 0x00, 0x60, + 0x3C, // 115 + 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0xFF, 0x7F, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, + 0x18, 0xC0, 0x00, 0x00, 0x18, 0xC0, // 116 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x3F, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x00, + 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0xF8, + 0xFF, 0x00, 0x00, 0xF8, 0xFF, // 117 + 0x00, 0x18, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x00, 0xE0, 0x03, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x00, + 0x00, 0xE0, 0x00, 0x00, 0x00, 0x7C, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0xE0, 0x03, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x00, + 0x18, // 118 + 0x00, 0x38, 0x00, 0x00, 0x00, 0xF8, 0x01, 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x00, + 0x00, 0x7E, 0x00, 0x00, 0x80, 0x0F, 0x00, 0x00, 0xF0, 0x01, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0xF0, 0x01, 0x00, 0x00, 0x80, + 0x0F, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x00, 0xF8, 0x01, + 0x00, 0x00, 0x38, // 119 + 0x00, 0x08, 0x80, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, 0x78, 0xF0, 0x00, 0x00, 0xE0, 0x38, 0x00, 0x00, 0xC0, 0x1F, 0x00, 0x00, + 0x00, 0x07, 0x00, 0x00, 0x80, 0x1F, 0x00, 0x00, 0xE0, 0x38, 0x00, 0x00, 0x70, 0xF0, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, 0x08, + 0x80, // 120 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0xF8, 0x01, 0x18, 0x00, 0xC0, 0x07, 0x18, 0x00, 0x00, 0x3E, 0x1C, 0x00, + 0x00, 0xF8, 0x0F, 0x00, 0x00, 0xF0, 0x03, 0x00, 0x00, 0x7F, 0x00, 0x00, 0xE0, 0x0F, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x00, + 0x18, // 121 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x18, 0xF0, 0x00, 0x00, 0x18, 0xF8, 0x00, 0x00, 0x18, 0xDC, 0x00, 0x00, + 0x18, 0xCF, 0x00, 0x00, 0x98, 0xC3, 0x00, 0x00, 0xD8, 0xC1, 0x00, 0x00, 0xF8, 0xC0, 0x00, 0x00, 0x78, 0xC0, 0x00, 0x00, 0x18, + 0xC0, // 122 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0xFF, 0xF9, 0x0F, 0x80, 0xFF, 0xF0, 0x1F, 0x80, + 0x01, 0x00, 0x18, 0x80, 0x01, 0x00, 0x18, // 123 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x3F, 0x80, 0xFF, 0xFF, 0x3F, // 124 + 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x18, 0x80, 0x01, 0x00, 0x18, 0x80, 0xFF, 0xF0, 0x1F, 0x00, 0xFF, 0xFD, 0x0F, 0x00, + 0x00, 0x0F, 0x00, 0x00, 0x00, 0x06, // 125 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, + 0xC0, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0x80, 0x01, // 126 + 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, + 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xC1, 0x00, 0x00, 0x80, 0xC1, + 0x00, 0x00, 0x80, 0x61, 0x00, 0x00, 0x80, 0x61, 0x60, 0x00, 0x80, 0x61, 0xC0, 0x00, 0x80, 0x61, 0xC0, 0x00, 0x00, 0x60, 0xC0, + 0x00, 0x00, 0xE0, 0xE0, 0x00, 0x00, 0xC0, 0x71, 0x00, 0x00, 0x80, 0x3F, 0x00, 0x00, 0x00, 0x1F, // 1026 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, + 0x01, 0x00, 0x00, 0xA0, 0x01, 0x00, 0x00, 0xB8, 0x01, 0x00, 0x00, 0x98, 0x01, 0x00, 0x00, 0x88, 0x01, 0x00, 0x00, 0x80, 0x01, + 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, // 1027 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x0C, 0x00, 0x00, 0xC0, 0x07, // 8218 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0x1A, 0x00, 0x00, 0x80, + 0x1B, 0x00, 0x00, 0x80, 0x19, 0x00, 0x00, 0x80, 0x18, 0x00, 0x00, 0x00, 0x18, // 1107 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x0C, 0x00, 0x00, 0xC0, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0xC0, 0x0C, 0x00, 0x00, 0xC0, 0x07, // 8222 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, // 8230 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, + 0x30, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x0F, 0x80, 0xFF, 0xFF, 0x0F, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, + 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, // 8224 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, + 0x18, 0xC0, 0x00, 0x80, 0xFF, 0xFF, 0x0F, 0x80, 0xFF, 0xFF, 0x0F, 0x00, 0x18, 0xC0, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, 0x18, + 0xC0, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, 0x18, 0xC0, // 8225 + 0x00, 0x30, 0x03, 0x00, 0x00, 0xF8, 0x07, 0x00, 0x00, 0xFE, 0x1F, 0x00, 0x00, 0x36, 0x3B, 0x00, 0x00, 0x33, 0x73, 0x00, 0x00, + 0x33, 0x63, 0x00, 0x80, 0x31, 0xC3, 0x00, 0x80, 0x31, 0xC3, 0x00, 0x80, 0x31, 0xC3, 0x00, 0x80, 0x31, 0xC3, 0x00, 0x80, 0x31, + 0xC0, 0x00, 0x00, 0x03, 0x60, // 8364 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x80, 0xC1, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, + 0xC1, 0xE0, 0x00, 0x00, 0x7F, 0xF8, 0x00, 0x00, 0x3E, 0x3E, 0x00, 0x00, 0xC0, 0x07, 0x00, 0x00, 0xF0, 0x01, 0x00, 0x00, 0x3E, + 0x3E, 0x00, 0x80, 0x0F, 0x7F, 0x00, 0x80, 0x81, 0xC1, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0xC1, 0x00, 0x00, 0x00, 0x7F, + 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x80, 0xC1, 0x00, + 0x00, 0x80, 0x80, 0x00, 0x00, 0x80, 0xC1, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x3E, // 8240 + 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x80, 0xFF, 0x7F, 0x00, 0x80, 0xFF, 0x3F, 0x00, 0x80, + 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, + 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0xC0, 0xC0, + 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0xC0, 0xC0, 0x00, + 0x00, 0x80, 0x61, 0x00, 0x00, 0x80, 0x7F, 0x00, 0x00, 0x00, 0x1E, // 1033 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x80, 0x0F, 0x00, 0x00, 0xE0, 0x3D, 0x00, 0x00, 0x70, 0x70, 0x00, 0x00, + 0x10, 0x40, // 8249 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, + 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, + 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0xC0, 0xC0, + 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0x80, 0x61, 0x00, + 0x00, 0x80, 0x7F, 0x00, 0x00, 0x00, 0x1E, // 1034 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, + 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x20, 0x60, 0x03, 0x00, 0x38, 0x78, 0x07, 0x00, 0x18, 0x1E, 0x0E, 0x00, 0x08, 0x07, + 0x38, 0x00, 0x80, 0x01, 0xF0, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x80, 0x01, 0x80, // 1036 + 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, + 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xC1, 0x00, 0x00, 0x80, 0xC1, + 0x00, 0x00, 0x80, 0x61, 0x00, 0x00, 0x80, 0x61, 0x00, 0x00, 0x80, 0x61, 0x00, 0x00, 0x80, 0x61, 0x00, 0x00, 0x00, 0x60, 0x00, + 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0xC0, 0xFF, 0x00, 0x00, 0x00, 0xFF, // 1035 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, + 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x1F, 0x00, 0x00, 0xC0, 0x1F, 0x00, 0x00, + 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, // 1039 + 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, + 0x33, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x18, 0x00, 0x18, 0x00, 0x18, 0x00, 0x38, 0x00, 0x18, 0x00, 0xF0, + 0xFF, 0x1F, 0x00, 0xE0, 0xFF, 0x0F, // 1106 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x80, 0x19, // 8216 + 0x00, 0x00, 0x00, 0x00, 0x80, 0x19, 0x00, 0x00, 0x80, 0x0F, // 8217 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x80, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x1F, 0x00, 0x00, 0x80, 0x19, // 8220 + 0x00, 0x00, 0x00, 0x00, 0x80, 0x19, 0x00, 0x00, 0x80, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + 0x19, 0x00, 0x00, 0x80, 0x0F, // 8221 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x03, 0x00, 0x00, 0xE0, 0x07, 0x00, 0x00, 0xE0, 0x07, 0x00, 0x00, 0xE0, 0x07, 0x00, 0x00, + 0xE0, 0x07, 0x00, 0x00, 0xC0, 0x03, // 8226 + 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, + 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, // 8211 + 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, + 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, + 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, + 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, // 8212 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, + 0x01, 0x00, 0x00, 0x80, 0xFF, 0x01, 0x00, 0x80, 0xFF, 0x01, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0x01, 0x00, 0x80, 0xFF, 0x01, 0x00, 0x80, 0x03, 0x00, 0x00, 0x00, 0x1E, 0x00, + 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, + 0x80, 0xFF, 0x01, 0x00, 0x80, 0xFF, 0x01, // 8482 + 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, + 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0x00, 0xC3, 0x00, 0x00, 0x00, 0xC3, 0x00, 0x00, 0x00, 0xC3, + 0x00, 0x00, 0x00, 0xC3, 0x00, 0x00, 0x00, 0xC3, 0x00, 0x00, 0x00, 0xE7, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, + 0x3C, // 1113 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x40, 0x00, 0x00, 0x70, 0x70, 0x00, 0x00, 0xE0, 0x3D, 0x00, 0x00, + 0x80, 0x0F, 0x00, 0x00, 0x00, 0x02, // 8250 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0xF8, + 0xFF, 0x00, 0x00, 0x00, 0xC3, 0x00, 0x00, 0x00, 0xC3, 0x00, 0x00, 0x00, 0xC3, 0x00, 0x00, 0x00, 0xC3, 0x00, 0x00, 0x00, 0xC3, + 0x00, 0x00, 0x00, 0xE7, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x3C, // 1114 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0x02, 0x02, 0x00, 0x80, + 0x03, 0x07, 0x00, 0x80, 0xC1, 0x0D, 0x00, 0x80, 0xF0, 0x38, 0x00, 0x00, 0x18, 0x70, 0x00, 0x00, 0x18, 0xE0, 0x00, 0x00, 0x00, + 0x80, // 1116 + 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, + 0x33, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x1B, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0xF0, + 0xFF, 0x00, 0x00, 0xE0, 0xFF, // 1115 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, + 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x1F, 0x00, 0x00, 0xC0, 0x1F, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0xF8, + 0xFF, 0x00, 0x00, 0xF8, 0xFF, // 1119 + 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0x00, 0x1E, 0xC0, 0x00, 0x18, 0x78, 0xC0, 0x00, 0x30, + 0xE0, 0xC1, 0x00, 0x20, 0x80, 0x77, 0x00, 0x20, 0x00, 0x3E, 0x00, 0x20, 0x80, 0x07, 0x00, 0x30, 0xE0, 0x01, 0x00, 0x18, 0x78, + 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0x80, 0x01, // 1038 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0xF8, 0x01, 0x18, 0x80, 0xC1, 0x07, 0x18, 0x00, 0x03, 0x3E, 0x1C, 0x00, + 0x02, 0xF8, 0x0F, 0x00, 0x02, 0xF0, 0x03, 0x00, 0x02, 0x7F, 0x00, 0x00, 0xE3, 0x0F, 0x00, 0x80, 0xF9, 0x00, 0x00, 0x00, + 0x18, // 1118 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, + 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x80, 0xFF, 0x7F, 0x00, 0x80, 0xFF, 0x3F, // 1032 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x10, 0x00, 0x00, 0xDC, 0x3B, 0x00, 0x00, 0xF8, 0x1F, 0x00, 0x00, 0x30, 0x0C, 0x00, 0x00, + 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x30, 0x0C, 0x00, 0x00, 0xF8, + 0x1F, 0x00, 0x00, 0xDC, 0x3B, 0x00, 0x00, 0x08, 0x10, // 164 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, + 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0xFC, 0x01, 0x00, 0x00, 0xFC, + 0x01, // 1168 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xE1, 0x3F, 0x80, 0xFF, 0xE1, 0x3F, // 166 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x03, 0x00, 0x00, 0xCE, 0x07, 0x03, 0x00, 0x7F, 0x0C, 0x0F, 0x80, 0x33, 0x1C, 0x0C, 0x80, + 0x71, 0x18, 0x18, 0x80, 0x61, 0x30, 0x18, 0x80, 0xC1, 0x70, 0x18, 0x80, 0xC3, 0xE1, 0x1C, 0x00, 0x87, 0xD3, 0x0F, 0x00, 0x06, + 0x9F, 0x07, 0x00, 0x00, 0x0E, // 167 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0xB0, + 0xC1, 0xC0, 0x00, 0xB0, 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0xB0, 0xC1, 0xC0, 0x00, 0xB0, 0xC1, + 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0x01, 0xC0, // 1025 + 0x00, 0xE0, 0x03, 0x00, 0x00, 0xF8, 0x0F, 0x00, 0x00, 0x1C, 0x1C, 0x00, 0x00, 0x06, 0x30, 0x00, 0x00, 0xE7, 0x71, 0x00, 0x00, + 0xFB, 0x67, 0x00, 0x80, 0x19, 0xC6, 0x00, 0x80, 0x0D, 0xCC, 0x00, 0x80, 0x0D, 0xCC, 0x00, 0x80, 0x0D, 0xCC, 0x00, 0x80, 0x0D, + 0xCC, 0x00, 0x80, 0x1D, 0xCE, 0x00, 0x00, 0x1B, 0x66, 0x00, 0x00, 0x17, 0x72, 0x00, 0x00, 0x06, 0x30, 0x00, 0x00, 0x1C, 0x1C, + 0x00, 0x00, 0xF8, 0x0F, 0x00, 0x00, 0xE0, 0x03, // 169 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x07, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xCE, 0x3C, 0x00, 0x00, 0xC7, 0x70, 0x00, 0x00, + 0xC3, 0x60, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0x01, + 0xC0, 0x00, 0x80, 0x03, 0xE0, 0x00, 0x00, 0x03, 0x60, 0x00, 0x00, 0x0F, 0x78, 0x00, 0x00, 0x1E, 0x3C, 0x00, 0x00, 0x08, + 0x08, // 1028 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x80, 0x0F, 0x00, 0x00, 0xE0, 0x3D, 0x00, 0x00, 0x70, 0x70, 0x00, 0x00, + 0x10, 0x42, 0x00, 0x00, 0x80, 0x0F, 0x00, 0x00, 0xE0, 0x3D, 0x00, 0x00, 0x70, 0x70, 0x00, 0x00, 0x10, 0x40, // 171 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, + 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0xF0, + 0x07, 0x00, 0x00, 0xF0, 0x07, // 172 + 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, + 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, // 173 + 0x00, 0xE0, 0x03, 0x00, 0x00, 0xF8, 0x0F, 0x00, 0x00, 0x1C, 0x1C, 0x00, 0x00, 0x06, 0x30, 0x00, 0x00, 0x07, 0x70, 0x00, 0x00, + 0xFB, 0x6F, 0x00, 0x80, 0xF9, 0xCF, 0x00, 0x80, 0x99, 0xC1, 0x00, 0x80, 0x99, 0xC1, 0x00, 0x80, 0x99, 0xC3, 0x00, 0x80, 0xF9, + 0xC7, 0x00, 0x80, 0xF1, 0xCC, 0x00, 0x00, 0x03, 0x68, 0x00, 0x00, 0x07, 0x70, 0x00, 0x00, 0x06, 0x30, 0x00, 0x00, 0x1C, 0x1C, + 0x00, 0x00, 0xF8, 0x0F, 0x00, 0x00, 0xE0, 0x03, // 174 + 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x30, 0x00, 0x00, 0x00, + 0x30, // 1031 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x80, 0x20, 0x00, 0x00, 0x80, 0x20, 0x00, 0x00, 0x80, + 0x20, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x0E, // 176 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xC1, 0x00, 0x00, 0x80, 0xC1, 0x00, 0x00, 0x80, 0xC1, 0x00, 0x00, 0x80, 0xC1, 0x00, 0x00, + 0x80, 0xC1, 0x00, 0x00, 0xFC, 0xFF, 0x00, 0x00, 0xFC, 0xFF, 0x00, 0x00, 0x80, 0xC1, 0x00, 0x00, 0x80, 0xC1, 0x00, 0x00, 0x80, + 0xC1, 0x00, 0x00, 0x80, 0xC1, 0x00, 0x00, 0x80, 0xC1, // 177 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, // 1030 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xF9, 0xFF, 0x00, 0x80, 0xF9, 0xFF, // 1110 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x80, 0x1F, 0x00, 0x00, 0x80, 0x1F, // 1169 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x1F, 0x00, 0xF8, 0xFF, 0x1F, 0x00, 0x00, 0x60, 0x00, 0x00, + 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x60, 0x00, 0x00, 0xF8, + 0xFF, 0x00, 0x00, 0xF8, 0xFF, // 181 + 0x00, 0x3C, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x80, 0xFF, 0x01, 0x00, 0x80, 0xFF, 0x01, 0x00, 0x80, + 0xFF, 0xFF, 0x1F, 0x80, 0xFF, 0xFF, 0x1F, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x1F, 0x80, 0xFF, + 0xFF, 0x1F, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, // 182 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, // 183 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x1F, 0x00, 0x00, 0xE0, 0x3F, 0x00, 0x00, 0x70, 0x73, 0x00, 0x00, 0x3B, 0xE3, 0x00, 0x00, + 0x1B, 0xC3, 0x00, 0x00, 0x18, 0xC3, 0x00, 0x00, 0x18, 0xC3, 0x00, 0x00, 0x3B, 0xE3, 0x00, 0x00, 0x73, 0x63, 0x00, 0x00, 0xE0, + 0x33, 0x00, 0x00, 0xC0, 0x13, // 1105 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, + 0x1C, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0x00, + 0x0E, 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x78, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x63, 0x00, 0x00, 0xF0, 0x67, 0x00, 0x00, 0x38, 0x6E, 0x00, 0x00, 0x18, 0x6C, 0x00, + 0x00, 0x18, 0x6C, 0x00, 0x00, 0x38, 0x6E, 0x00, 0x00, 0xF0, 0x67, 0x00, 0x00, 0xE0, 0x63, // 8470 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x1F, 0x00, 0x00, 0xE0, 0x7F, 0x00, 0x00, 0x70, 0x73, 0x00, 0x00, 0x18, 0xC3, 0x00, 0x00, + 0x18, 0xC3, 0x00, 0x00, 0x18, 0xC3, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, 0x38, 0x60, 0x00, 0x00, 0x70, 0x78, 0x00, 0x00, 0x60, + 0x18, // 1108 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x40, 0x00, 0x00, 0x70, 0x70, 0x00, 0x00, + 0xE0, 0x3D, 0x00, 0x00, 0x80, 0x0F, 0x00, 0x00, 0x10, 0x42, 0x00, 0x00, 0x70, 0x70, 0x00, 0x00, 0xE0, 0x3D, 0x00, 0x00, 0x80, + 0x0F, 0x00, 0x00, 0x00, 0x02, // 187 + 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x80, 0xF9, 0xFF, 0x1F, 0x80, 0xF9, 0xFF, 0x0F, // 1112 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x1C, 0x3C, 0x00, 0x00, 0x7F, 0x70, 0x00, 0x00, 0x63, 0x60, 0x00, 0x80, + 0xE1, 0xE0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, + 0xC1, 0x00, 0x80, 0x83, 0xE1, 0x00, 0x00, 0x87, 0x63, 0x00, 0x00, 0x0E, 0x3F, 0x00, 0x00, 0x0C, 0x1E, // 1029 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x30, 0x00, 0x00, 0xF0, 0x71, 0x00, 0x00, 0xB8, 0xE3, 0x00, 0x00, 0x18, 0xC3, 0x00, 0x00, + 0x18, 0xC3, 0x00, 0x00, 0x18, 0xC7, 0x00, 0x00, 0x18, 0xC7, 0x00, 0x00, 0x38, 0xE6, 0x00, 0x00, 0x70, 0x7E, 0x00, 0x00, 0x60, + 0x3C, // 1109 + 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x03, // 1111 + 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x00, 0xF8, 0x07, 0x00, 0x00, + 0x3E, 0x06, 0x00, 0x80, 0x0F, 0x06, 0x00, 0x80, 0x01, 0x06, 0x00, 0x80, 0x0F, 0x06, 0x00, 0x00, 0x3E, 0x06, 0x00, 0x00, 0xF8, + 0x07, 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x00, 0xC0, // 1040 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, + 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, + 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0x81, 0x61, 0x00, 0x00, 0x80, 0x7F, 0x00, 0x00, 0x00, 0x1E, // 1041 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, + 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, + 0xC0, 0x00, 0x00, 0xE3, 0xC1, 0x00, 0x00, 0xFF, 0x61, 0x00, 0x00, 0x1E, 0x7F, 0x00, 0x00, 0x00, 0x1E, // 1042 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, + 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, + 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, // 1043 + 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x00, 0xE0, 0x0F, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, 0xDF, 0x00, 0x80, 0xFF, 0xC7, 0x00, 0x80, + 0x7F, 0xC0, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x80, 0x01, + 0xC0, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x00, 0xC0, + 0x0F, // 1044 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, + 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, + 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0x01, 0xC0, // 1045 + 0x80, 0x01, 0x80, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x80, 0x01, 0xF0, 0x00, 0x00, 0x07, 0x3C, 0x00, 0x00, 0x1E, 0x0E, 0x00, 0x00, + 0x38, 0x07, 0x00, 0x00, 0xE0, 0x03, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x80, 0xFF, + 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0xE0, 0x03, + 0x00, 0x00, 0x38, 0x07, 0x00, 0x00, 0x1E, 0x0E, 0x00, 0x00, 0x07, 0x3C, 0x00, 0x80, 0x01, 0xF0, 0x00, 0x80, 0x01, 0xC0, 0x00, + 0x80, 0x01, 0x80, // 1046 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x08, 0x00, 0x00, 0x1E, 0x3C, 0x00, 0x00, 0x07, 0x78, 0x00, 0x80, 0x03, 0x60, 0x00, 0x80, + 0x01, 0xE0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x00, 0xE3, + 0xE1, 0x00, 0x00, 0xBF, 0x73, 0x00, 0x00, 0x1C, 0x3F, 0x00, 0x00, 0x00, 0x1E, // 1047 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, + 0x00, 0x3C, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x38, + 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, // 1048 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x70, 0x00, 0x18, + 0x00, 0x3C, 0x00, 0x30, 0x00, 0x0E, 0x00, 0x20, 0x80, 0x07, 0x00, 0x20, 0xC0, 0x01, 0x00, 0x20, 0xF0, 0x00, 0x00, 0x30, 0x38, + 0x00, 0x00, 0x18, 0x1E, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, // 1049 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, + 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x01, 0x00, 0x00, 0x60, 0x03, 0x00, 0x00, 0x78, 0x07, 0x00, 0x00, 0x1E, 0x0E, 0x00, 0x00, 0x07, + 0x38, 0x00, 0x80, 0x01, 0xF0, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x80, 0x01, 0x80, // 1050 + 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x80, 0xFF, 0x7F, 0x00, 0x80, 0xFF, 0x3F, 0x00, 0x80, + 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, + 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, // 1051 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0x07, 0x00, 0x00, 0x00, + 0x3F, 0x00, 0x00, 0x00, 0xF8, 0x03, 0x00, 0x00, 0x80, 0x1F, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, + 0xFC, 0x00, 0x00, 0x80, 0x1F, 0x00, 0x00, 0xF8, 0x03, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0x80, 0xFF, 0xFF, + 0x00, 0x80, 0xFF, 0xFF, // 1052 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, + 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, + 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, // 1053 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x07, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0x1E, 0x3C, 0x00, 0x00, 0x07, 0x70, 0x00, 0x00, + 0x03, 0x60, 0x00, 0x80, 0x03, 0xE0, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x80, 0x01, + 0xC0, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x80, 0x03, 0xE0, 0x00, 0x00, 0x03, 0x60, 0x00, 0x00, 0x07, 0x70, 0x00, 0x00, 0x1E, 0x3C, + 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xF0, 0x07, // 1054 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, + 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, + 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, // 1055 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0x81, 0x01, 0x00, 0x80, + 0x81, 0x01, 0x00, 0x80, 0x81, 0x01, 0x00, 0x80, 0x81, 0x01, 0x00, 0x80, 0x81, 0x01, 0x00, 0x80, 0x81, 0x01, 0x00, 0x80, 0x81, + 0x01, 0x00, 0x80, 0x81, 0x01, 0x00, 0x00, 0xC3, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x3C, // 1056 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xF0, 0x07, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0x1E, 0x3C, 0x00, 0x00, 0x07, 0x70, 0x00, 0x00, + 0x03, 0x60, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x80, 0x01, + 0xC0, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x00, 0x03, 0x60, 0x00, 0x00, 0x07, 0x70, 0x00, 0x00, 0x0E, 0x3C, 0x00, 0x00, 0x08, + 0x0C, // 1057 + 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, + 0x01, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, + 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, // 1058 + 0x00, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0x00, 0x1E, 0xC0, 0x00, 0x00, 0x78, 0xC0, 0x00, 0x00, + 0xE0, 0xC1, 0x00, 0x00, 0x80, 0x77, 0x00, 0x00, 0x00, 0x3E, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0xE0, 0x01, 0x00, 0x00, 0x78, + 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0x80, 0x01, // 1059 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0x03, 0x00, 0x00, 0xF8, 0x0F, 0x00, 0x00, 0x1C, 0x1C, 0x00, 0x00, 0x0C, 0x18, 0x00, 0x00, + 0x0E, 0x38, 0x00, 0x00, 0x06, 0x30, 0x00, 0x00, 0x06, 0x30, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0x06, + 0x30, 0x00, 0x00, 0x06, 0x30, 0x00, 0x00, 0x0E, 0x38, 0x00, 0x00, 0x0C, 0x18, 0x00, 0x00, 0x1C, 0x1C, 0x00, 0x00, 0xF8, 0x0F, + 0x00, 0x00, 0xE0, 0x03, // 1060 + 0x00, 0x00, 0x80, 0x00, 0x80, 0x00, 0xC0, 0x00, 0x80, 0x01, 0xF0, 0x00, 0x80, 0x07, 0x78, 0x00, 0x00, 0x0F, 0x1E, 0x00, 0x00, + 0x3C, 0x0F, 0x00, 0x00, 0xF8, 0x07, 0x00, 0x00, 0xE0, 0x01, 0x00, 0x00, 0xF8, 0x07, 0x00, 0x00, 0x1E, 0x0F, 0x00, 0x00, 0x0F, + 0x1C, 0x00, 0x80, 0x07, 0x78, 0x00, 0x80, 0x01, 0xF0, 0x00, 0x80, 0x00, 0xC0, 0x00, 0x00, 0x00, 0x80, // 1061 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, + 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, + 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xC0, + 0x1F, 0x00, 0x00, 0xC0, 0x1F, // 1062 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x7F, 0x00, 0x00, 0x80, 0xFF, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x80, + 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, // 1063 + 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, + 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x80, 0xFF, + 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, + 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, + 0xFF, // 1064 + 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, + 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x80, 0xFF, + 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, + 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, + 0x00, 0x00, 0xC0, 0x1F, 0x00, 0x00, 0xC0, 0x1F, // 1065 + 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x80, + 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0xC0, + 0xC0, 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0x80, 0x61, + 0x00, 0x00, 0x80, 0x7F, 0x00, 0x00, 0x00, 0x1E, // 1066 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00, + 0xC0, 0xC0, 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0xC0, + 0xC0, 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0x80, 0x61, 0x00, 0x00, 0x80, 0x7F, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, // 1067 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00, + 0xC0, 0xC0, 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0xC0, + 0xC0, 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0x80, 0x61, 0x00, 0x00, 0x80, 0x7F, 0x00, 0x00, 0x00, 0x1E, // 1068 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0x1E, 0x3C, 0x00, 0x00, 0x0F, 0x78, 0x00, 0x00, 0x03, 0x60, 0x00, 0x80, + 0x03, 0xE0, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, 0xC0, 0x00, 0x80, 0xC1, + 0xC0, 0x00, 0x00, 0xC3, 0x60, 0x00, 0x00, 0xC7, 0x70, 0x00, 0x00, 0xCE, 0x38, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xF0, + 0x07, // 1069 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, + 0x80, 0x01, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0xF0, 0x07, 0x00, 0x00, 0xFC, 0x1F, 0x00, 0x00, 0x1E, 0x3C, 0x00, 0x00, 0x07, + 0x70, 0x00, 0x00, 0x03, 0x60, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x80, 0x01, 0xC0, + 0x00, 0x80, 0x01, 0xC0, 0x00, 0x80, 0x01, 0xC0, 0x00, 0x00, 0x03, 0x60, 0x00, 0x00, 0x07, 0x70, 0x00, 0x00, 0x1E, 0x3C, 0x00, + 0x00, 0xFC, 0x1F, 0x00, 0x00, 0xF0, 0x07, // 1070 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x3E, 0xC0, 0x00, 0x00, 0x7F, 0xF0, 0x00, 0x80, 0x63, 0x7C, 0x00, 0x80, + 0xC1, 0x1E, 0x00, 0x80, 0xC1, 0x0F, 0x00, 0x80, 0xC1, 0x03, 0x00, 0x80, 0xC1, 0x01, 0x00, 0x80, 0xC1, 0x00, 0x00, 0x80, 0xC1, + 0x00, 0x00, 0x80, 0xC1, 0x00, 0x00, 0x80, 0xC1, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x00, 0x80, 0xFF, 0xFF, // 1071 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x38, 0x00, 0x00, 0x70, 0x7C, 0x00, 0x00, 0x30, 0xE6, 0x00, 0x00, 0x18, 0xC6, 0x00, 0x00, + 0x18, 0xC6, 0x00, 0x00, 0x18, 0xC3, 0x00, 0x00, 0x18, 0x63, 0x00, 0x00, 0x38, 0x63, 0x00, 0x00, 0xF0, 0x7F, 0x00, 0x00, 0xE0, + 0xFF, 0x00, 0x00, 0x00, 0x80, // 1072 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x0F, 0x00, 0x00, 0xFE, 0x3F, 0x00, 0x00, 0x73, 0x70, 0x00, 0x00, 0x31, 0xE0, 0x00, 0x80, + 0x19, 0xC0, 0x00, 0x80, 0x19, 0xC0, 0x00, 0x80, 0x19, 0xC0, 0x00, 0x80, 0x19, 0xC0, 0x00, 0x80, 0x39, 0xE0, 0x00, 0x80, 0x71, + 0x70, 0x00, 0x80, 0xE1, 0x3F, 0x00, 0x80, 0x80, 0x0F, // 1073 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0x18, 0xC3, 0x00, 0x00, + 0x18, 0xC3, 0x00, 0x00, 0x18, 0xC3, 0x00, 0x00, 0x18, 0xC3, 0x00, 0x00, 0x18, 0xC3, 0x00, 0x00, 0xF0, 0xE7, 0x00, 0x00, 0xF0, + 0x7E, 0x00, 0x00, 0x00, 0x3C, // 1074 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, // 1075 + 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x00, 0xE0, 0x0F, 0x00, 0x00, 0xFC, 0x00, 0x00, 0xF8, 0xDF, 0x00, 0x00, 0xF8, 0xC3, 0x00, 0x00, + 0x18, 0xC0, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0xF8, + 0xFF, 0x00, 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x00, 0xC0, 0x0F, // 1076 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x1F, 0x00, 0x00, 0xE0, 0x3F, 0x00, 0x00, 0x70, 0x73, 0x00, 0x00, 0x38, 0xE3, 0x00, 0x00, + 0x18, 0xC3, 0x00, 0x00, 0x18, 0xC3, 0x00, 0x00, 0x18, 0xC3, 0x00, 0x00, 0x38, 0xE3, 0x00, 0x00, 0x70, 0x63, 0x00, 0x00, 0xE0, + 0x33, 0x00, 0x00, 0xC0, 0x13, // 1077 + 0x00, 0x18, 0xE0, 0x00, 0x00, 0x18, 0x70, 0x00, 0x00, 0xF8, 0x38, 0x00, 0x00, 0xE0, 0x0D, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, + 0x00, 0x02, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0xE0, + 0x0D, 0x00, 0x00, 0xF8, 0x38, 0x00, 0x00, 0x18, 0x70, 0x00, 0x00, 0x18, 0xE0, 0x00, 0x00, 0x00, 0x80, // 1078 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x30, 0x00, 0x00, 0x70, 0x70, 0x00, 0x00, 0x38, 0xE0, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, + 0x18, 0xC3, 0x00, 0x00, 0x18, 0xC3, 0x00, 0x00, 0x38, 0xE7, 0x00, 0x00, 0xF0, 0x7F, 0x00, 0x00, 0xE0, 0x3C, // 1079 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0x00, 0xF0, 0x00, 0x00, + 0x00, 0x3C, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x80, 0x07, 0x00, 0x00, 0xE0, 0x01, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0xF8, + 0xFF, 0x00, 0x00, 0xF8, 0xFF, // 1080 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x80, 0x01, 0xF0, 0x00, 0x00, + 0x03, 0x3C, 0x00, 0x00, 0x02, 0x0F, 0x00, 0x00, 0x82, 0x07, 0x00, 0x00, 0xE2, 0x01, 0x00, 0x00, 0x7B, 0x00, 0x00, 0x80, 0xF9, + 0xFF, 0x00, 0x00, 0xF8, 0xFF, // 1081 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x00, 0x07, 0x00, 0x00, 0xC0, 0x0D, 0x00, 0x00, 0xF0, 0x38, 0x00, 0x00, 0x18, 0x70, 0x00, 0x00, 0x18, 0xE0, 0x00, 0x00, 0x00, + 0x80, // 1082 + 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0xF8, + 0xFF, 0x00, 0x00, 0xF8, 0xFF, // 1083 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, + 0xF0, 0x03, 0x00, 0x00, 0x80, 0x3F, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x00, 0xE0, 0x00, 0x00, 0x00, 0xFC, 0x00, 0x00, 0x80, + 0x1F, 0x00, 0x00, 0xF0, 0x03, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0xF8, 0xFF, // 1084 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0xF8, + 0xFF, 0x00, 0x00, 0xF8, 0xFF, // 1085 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x1F, 0x00, 0x00, 0xE0, 0x3F, 0x00, 0x00, 0x70, 0x70, 0x00, 0x00, 0x38, 0xE0, 0x00, 0x00, + 0x18, 0xC0, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, 0x38, 0xE0, 0x00, 0x00, 0x70, 0x70, 0x00, 0x00, 0xE0, + 0x3F, 0x00, 0x00, 0xC0, 0x1F, // 1086 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0xF8, + 0xFF, 0x00, 0x00, 0xF8, 0xFF, // 1087 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x1F, 0x00, 0xF8, 0xFF, 0x1F, 0x00, 0x60, 0x30, 0x00, 0x00, + 0x30, 0x60, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, 0x38, 0xE0, 0x00, 0x00, 0x70, + 0x70, 0x00, 0x00, 0xE0, 0x3F, 0x00, 0x00, 0xC0, 0x0F, // 1088 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x1F, 0x00, 0x00, 0xE0, 0x3F, 0x00, 0x00, 0x70, 0x70, 0x00, 0x00, 0x38, 0xE0, 0x00, 0x00, + 0x18, 0xC0, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, 0x38, 0xE0, 0x00, 0x00, 0x70, 0x70, 0x00, 0x00, 0x60, + 0x30, // 1089 + 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, + 0xF8, 0xFF, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, // 1090 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0xF8, 0x01, 0x18, 0x00, 0xC0, 0x07, 0x18, 0x00, 0x00, 0x3E, 0x1C, 0x00, + 0x00, 0xF8, 0x0F, 0x00, 0x00, 0xF0, 0x03, 0x00, 0x00, 0x7F, 0x00, 0x00, 0xE0, 0x0F, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x00, + 0x18, // 1091 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x1F, 0x00, 0x00, 0xE0, 0x3F, 0x00, 0x00, 0x70, 0x70, 0x00, 0x00, 0x38, 0xE0, 0x00, 0x00, + 0x18, 0xC0, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, 0x70, 0x60, 0x00, 0x80, 0xFF, 0xFF, 0x1F, 0x80, 0xFF, + 0xFF, 0x1F, 0x00, 0x70, 0x60, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, 0x18, 0xE0, + 0x00, 0x00, 0x70, 0x70, 0x00, 0x00, 0xE0, 0x3F, 0x00, 0x00, 0xC0, 0x1F, // 1092 + 0x00, 0x08, 0x80, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, 0x78, 0xF0, 0x00, 0x00, 0xE0, 0x38, 0x00, 0x00, 0xC0, 0x1F, 0x00, 0x00, + 0x00, 0x07, 0x00, 0x00, 0x80, 0x1F, 0x00, 0x00, 0xE0, 0x38, 0x00, 0x00, 0x70, 0xF0, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, 0x08, + 0x80, // 1093 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, + 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0xF8, + 0xFF, 0x00, 0x00, 0xF8, 0xFF, 0x1F, 0x00, 0x00, 0xC0, 0x1F, // 1094 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0x01, 0x00, 0x00, 0xF8, 0x07, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, + 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0xF8, + 0xFF, // 1095 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, + 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0xF8, + 0xFF, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, + 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0xF8, 0xFF, // 1096 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, + 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0xF8, + 0xFF, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, 0x00, 0x00, 0x00, 0xC0, + 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0xF8, 0xFF, 0x1F, 0x00, 0x00, 0xC0, 0x1F, // 1097 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, + 0xF8, 0xFF, 0x00, 0x00, 0x00, 0xC3, 0x00, 0x00, 0x00, 0xC3, 0x00, 0x00, 0x00, 0xC3, 0x00, 0x00, 0x00, 0xC3, 0x00, 0x00, 0x00, + 0xC3, 0x00, 0x00, 0x00, 0xE7, 0x00, 0x00, 0x00, 0x7E, 0x00, 0x00, 0x00, 0x3C, // 1098 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0x00, 0xC3, 0x00, 0x00, + 0x00, 0xC3, 0x00, 0x00, 0x00, 0xC3, 0x00, 0x00, 0x00, 0xC3, 0x00, 0x00, 0x00, 0xC3, 0x00, 0x00, 0x00, 0xE7, 0x00, 0x00, 0x00, + 0x7E, 0x00, 0x00, 0x00, 0x3C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0xF8, 0xFF, // 1099 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0x00, 0xC3, 0x00, 0x00, + 0x00, 0xC3, 0x00, 0x00, 0x00, 0xC3, 0x00, 0x00, 0x00, 0xC3, 0x00, 0x00, 0x00, 0xC3, 0x00, 0x00, 0x00, 0xE7, 0x00, 0x00, 0x00, + 0x7E, 0x00, 0x00, 0x00, 0x3C, // 1100 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, 0x18, 0x00, 0x00, 0x70, 0x78, 0x00, 0x00, 0x38, 0x60, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, + 0x18, 0xC3, 0x00, 0x00, 0x18, 0xC3, 0x00, 0x00, 0x18, 0xC3, 0x00, 0x00, 0x70, 0x73, 0x00, 0x00, 0xE0, 0x7F, 0x00, 0x00, 0xC0, + 0x1F, // 1101 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x00, 0xC0, 0x1F, 0x00, 0x00, 0xE0, 0x3F, 0x00, 0x00, 0x70, 0x70, 0x00, 0x00, 0x38, 0xE0, 0x00, 0x00, 0x18, + 0xC0, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, 0x18, 0xC0, 0x00, 0x00, 0x38, 0xE0, 0x00, 0x00, 0x70, 0x70, 0x00, 0x00, 0xE0, 0x3F, + 0x00, 0x00, 0xC0, 0x1F, // 1102 + 0x00, 0x00, 0x00, 0x00, 0x00, 0xE0, 0xC1, 0x00, 0x00, 0xF0, 0xE3, 0x00, 0x00, 0x38, 0x7B, 0x00, 0x00, 0x18, 0x1A, 0x00, 0x00, + 0x18, 0x0E, 0x00, 0x00, 0x18, 0x06, 0x00, 0x00, 0x18, 0x06, 0x00, 0x00, 0x18, 0x06, 0x00, 0x00, 0xF8, 0xFF, 0x00, 0x00, 0xF8, + 0xFF, // 1103 }; \ No newline at end of file diff --git a/src/graphics/fonts/OLEDDisplayFontsUA.h b/src/graphics/fonts/OLEDDisplayFontsUA.h index 3bd9bb4ca..dc313aed2 100644 --- a/src/graphics/fonts/OLEDDisplayFontsUA.h +++ b/src/graphics/fonts/OLEDDisplayFontsUA.h @@ -8,4 +8,6 @@ #endif extern const uint8_t ArialMT_Plain_10_UA[] PROGMEM; +extern const uint8_t ArialMT_Plain_16_UA[] PROGMEM; +extern const uint8_t ArialMT_Plain_24_UA[] PROGMEM; #endif \ No newline at end of file diff --git a/src/modules/ExternalNotificationModule.cpp b/src/modules/ExternalNotificationModule.cpp index 3ec6ff690..bbb3f90e0 100644 --- a/src/modules/ExternalNotificationModule.cpp +++ b/src/modules/ExternalNotificationModule.cpp @@ -124,7 +124,8 @@ int32_t ExternalNotificationModule::runOnce() if (externalTurnedOn[2] + (moduleConfig.external_notification.output_ms ? moduleConfig.external_notification.output_ms : EXT_NOTIFICATION_MODULE_OUTPUT_MS) < millis()) { - LOG_DEBUG("EXTERNAL 2 %d compared to %d", externalTurnedOn[2]+moduleConfig.external_notification.output_ms, millis()); + LOG_DEBUG("EXTERNAL 2 %d compared to %d", externalTurnedOn[2] + moduleConfig.external_notification.output_ms, + millis()); setExternalState(2, !getExternal(2)); } #if defined(HAS_NCP5623) || defined(RGBLED_RED) || defined(HAS_NEOPIXEL) || defined(UNPHONE) From 060a3bde4d1d708ee42f91090e54198cc6eef177 Mon Sep 17 00:00:00 2001 From: virgil Date: Thu, 28 Nov 2024 20:19:18 +0800 Subject: [PATCH 059/101] fix: Solve the lightsleep crash problem via disable lightsleep for indicator. (#5470) --- src/mesh/NodeDB.cpp | 2 +- src/sleep.cpp | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index b529fa934..b38f55ae6 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -542,7 +542,7 @@ void NodeDB::initConfigIntervals() config.display.screen_on_secs = default_screen_on_secs; -#if defined(T_WATCH_S3) || defined(T_DECK) || defined(RAK14014) || defined(SENSECAP_INDICATOR) +#if defined(T_WATCH_S3) || defined(T_DECK) || defined(RAK14014) config.power.is_power_saving = true; config.display.screen_on_secs = 30; config.power.wait_bluetooth_secs = 30; diff --git a/src/sleep.cpp b/src/sleep.cpp index 05597cdfa..904bc3ab8 100644 --- a/src/sleep.cpp +++ b/src/sleep.cpp @@ -336,6 +336,11 @@ esp_sleep_wakeup_cause_t doLightSleep(uint64_t sleepMsec) // FIXME, use a more r { // LOG_DEBUG("Enter light sleep"); + //LORA_DIO1 is an extended IO pin. Setting it as a wake-up pin will cause problems, such as the indicator device not entering LightSleep. +#if defined(SENSECAP_INDICATOR) + return ESP_SLEEP_WAKEUP_TIMER; +#endif + waitEnterSleep(false); uint64_t sleepUsec = sleepMsec * 1000LL; From 5ad30a55ea3ec18ab81bed2db0d3a6c8fe8bf80b Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Thu, 28 Nov 2024 06:26:51 -0600 Subject: [PATCH 060/101] Trunk --- CODE_OF_CONDUCT.md | 2 +- src/sleep.cpp | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 1e23cdf4d..6843fc85d 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -1,4 +1,4 @@ # Contributor Covenant Code of Conduct -The Meshtastic Firmware project is subject to the code of conduct for the parent project, which can be found here: +The Meshtastic Firmware project is subject to the code of conduct for the parent project, which can be found here: https://meshtastic.org/docs/legal/conduct/ diff --git a/src/sleep.cpp b/src/sleep.cpp index 904bc3ab8..69eb0349a 100644 --- a/src/sleep.cpp +++ b/src/sleep.cpp @@ -336,7 +336,8 @@ esp_sleep_wakeup_cause_t doLightSleep(uint64_t sleepMsec) // FIXME, use a more r { // LOG_DEBUG("Enter light sleep"); - //LORA_DIO1 is an extended IO pin. Setting it as a wake-up pin will cause problems, such as the indicator device not entering LightSleep. + // LORA_DIO1 is an extended IO pin. Setting it as a wake-up pin will cause problems, such as the indicator device not entering + // LightSleep. #if defined(SENSECAP_INDICATOR) return ESP_SLEEP_WAKEUP_TIMER; #endif From b5777beb7d2dc3b835646128596642a8107b3523 Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Thu, 28 Nov 2024 11:20:06 -0600 Subject: [PATCH 061/101] Warnings and log cleanup (#5472) * Don't log if keyboard not found * Signed comparison issue --- src/gps/GPS.h | 6 +++--- src/input/cardKbI2cImpl.cpp | 3 ++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/gps/GPS.h b/src/gps/GPS.h index 74d73e39a..15fc50fe7 100644 --- a/src/gps/GPS.h +++ b/src/gps/GPS.h @@ -158,8 +158,8 @@ class GPS : private concurrency::OSThread uint32_t rx_gpio = 0; uint32_t tx_gpio = 0; - int speedSelect = 0; - int probeTries = 0; + uint8_t speedSelect = 0; + uint8_t probeTries = 0; /** * hasValidLocation - indicates that the position variables contain a complete @@ -239,4 +239,4 @@ class GPS : private concurrency::OSThread }; extern GPS *gps; -#endif // Exclude GPS +#endif // Exclude GPS \ No newline at end of file diff --git a/src/input/cardKbI2cImpl.cpp b/src/input/cardKbI2cImpl.cpp index b940f5448..eb9b07d6e 100644 --- a/src/input/cardKbI2cImpl.cpp +++ b/src/input/cardKbI2cImpl.cpp @@ -49,10 +49,11 @@ void CardKbI2cImpl::init() kb_model = 0x00; } } - LOG_DEBUG("Keyboard Type: 0x%02x Model: 0x%02x Address: 0x%02x", kb_info.type, kb_model, cardkb_found.address); if (cardkb_found.address == 0x00) { disable(); return; + } else { + LOG_DEBUG("Keyboard Type: 0x%02x Model: 0x%02x Address: 0x%02x", kb_info.type, kb_model, cardkb_found.address); } } #else From 79da2365f0ee900ca194db0c0828bca59140c0c4 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 29 Nov 2024 08:03:46 -0600 Subject: [PATCH 062/101] [create-pull-request] automated change (#5475) Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com> --- version.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.properties b/version.properties index bed14bad5..a27fba5c0 100644 --- a/version.properties +++ b/version.properties @@ -1,4 +1,4 @@ [VERSION] major = 2 minor = 5 -build = 14 +build = 15 From ac6b6c8d835bd16a0eeb7c1c88fdbe2687eabe65 Mon Sep 17 00:00:00 2001 From: Jonathan Bennett Date: Fri, 29 Nov 2024 17:05:28 -0600 Subject: [PATCH 063/101] Adds libusb dev package to Raspbian build steps (#5480) --- .github/workflows/build_native.yml | 2 +- .github/workflows/build_raspbian.yml | 2 +- .github/workflows/build_raspbian_armv7l.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build_native.yml b/.github/workflows/build_native.yml index 1fb44a717..d4b0c8d58 100644 --- a/.github/workflows/build_native.yml +++ b/.github/workflows/build_native.yml @@ -14,7 +14,7 @@ jobs: shell: bash run: | sudo apt-get update --fix-missing - sudo apt-get install -y libbluetooth-dev libgpiod-dev libyaml-cpp-dev openssl libssl-dev libulfius-dev liborcania-dev + sudo apt-get install -y libbluetooth-dev libgpiod-dev libyaml-cpp-dev openssl libssl-dev libulfius-dev liborcania-dev libusb-1.0-0-dev - name: Checkout code uses: actions/checkout@v4 diff --git a/.github/workflows/build_raspbian.yml b/.github/workflows/build_raspbian.yml index e857ae635..1826504f0 100644 --- a/.github/workflows/build_raspbian.yml +++ b/.github/workflows/build_raspbian.yml @@ -14,7 +14,7 @@ jobs: shell: bash run: | sudo apt-get update -y --fix-missing - sudo apt-get install -y libbluetooth-dev libgpiod-dev libyaml-cpp-dev openssl libssl-dev libulfius-dev liborcania-dev + sudo apt-get install -y libbluetooth-dev libgpiod-dev libyaml-cpp-dev openssl libssl-dev libulfius-dev liborcania-dev libusb-1.0-0-dev - name: Checkout code uses: actions/checkout@v4 diff --git a/.github/workflows/build_raspbian_armv7l.yml b/.github/workflows/build_raspbian_armv7l.yml index f7fddd038..fd53585a5 100644 --- a/.github/workflows/build_raspbian_armv7l.yml +++ b/.github/workflows/build_raspbian_armv7l.yml @@ -14,7 +14,7 @@ jobs: shell: bash run: | sudo apt-get update -y --fix-missing - sudo apt-get install -y libbluetooth-dev libgpiod-dev libyaml-cpp-dev openssl libssl-dev libulfius-dev liborcania-dev + sudo apt-get install -y libbluetooth-dev libgpiod-dev libyaml-cpp-dev openssl libssl-dev libulfius-dev liborcania-dev libusb-1.0-0-dev - name: Checkout code uses: actions/checkout@v4 From fe8e0713cc9897fec2e66f134a878e0879a8c257 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 29 Nov 2024 19:40:44 -0600 Subject: [PATCH 064/101] [create-pull-request] automated change (#5478) Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com> --- version.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.properties b/version.properties index a27fba5c0..9d03516e4 100644 --- a/version.properties +++ b/version.properties @@ -1,4 +1,4 @@ [VERSION] major = 2 minor = 5 -build = 15 +build = 16 From 43b897217199696daf16747112bb5272ccf0acc1 Mon Sep 17 00:00:00 2001 From: Jonathan Bennett Date: Fri, 29 Nov 2024 21:29:45 -0600 Subject: [PATCH 065/101] Portduino fixes (#5479) * Set config.yaml defaults even if General is missing * Unsigned values should get %u in logging --- src/mesh/NodeDB.cpp | 4 ++-- src/platform/portduino/PortduinoGlue.cpp | 8 +++----- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index b38f55ae6..0d63d3b9b 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -1349,7 +1349,7 @@ meshtastic_NodeInfoLite *NodeDB::getOrCreateMeshNode(NodeNum n) if (!lite) { if (isFull()) { - LOG_INFO("Node database full with %i nodes and %i bytes free. Erasing oldest entry", numMeshNodes, + LOG_INFO("Node database full with %i nodes and %u bytes free. Erasing oldest entry", numMeshNodes, memGet.getFreeHeap()); // look for oldest node and erase it uint32_t oldest = UINT32_MAX; @@ -1385,7 +1385,7 @@ meshtastic_NodeInfoLite *NodeDB::getOrCreateMeshNode(NodeNum n) // everything is missing except the nodenum memset(lite, 0, sizeof(*lite)); lite->num = n; - LOG_INFO("Adding node to database with %i nodes and %i bytes free!", numMeshNodes, memGet.getFreeHeap()); + LOG_INFO("Adding node to database with %i nodes and %u bytes free!", numMeshNodes, memGet.getFreeHeap()); } return lite; diff --git a/src/platform/portduino/PortduinoGlue.cpp b/src/platform/portduino/PortduinoGlue.cpp index 686564cc1..d53a5be94 100644 --- a/src/platform/portduino/PortduinoGlue.cpp +++ b/src/platform/portduino/PortduinoGlue.cpp @@ -400,11 +400,9 @@ bool loadConfig(const char *configPath) settingsStrings[webserverrootpath] = (yamlConfig["Webserver"]["RootPath"]).as(""); } - if (yamlConfig["General"]) { - settingsMap[maxnodes] = (yamlConfig["General"]["MaxNodes"]).as(200); - settingsMap[maxtophone] = (yamlConfig["General"]["MaxMessageQueue"]).as(100); - settingsStrings[config_directory] = (yamlConfig["General"]["ConfigDirectory"]).as(""); - } + settingsMap[maxnodes] = (yamlConfig["General"]["MaxNodes"]).as(200); + settingsMap[maxtophone] = (yamlConfig["General"]["MaxMessageQueue"]).as(100); + settingsStrings[config_directory] = (yamlConfig["General"]["ConfigDirectory"]).as(""); } catch (YAML::Exception &e) { std::cout << "*** Exception " << e.what() << std::endl; From 9f4c8a28043633fbeffc00da8c0ede02cebfdf9a Mon Sep 17 00:00:00 2001 From: GUVWAF <78759985+GUVWAF@users.noreply.github.com> Date: Sat, 30 Nov 2024 20:16:02 +0100 Subject: [PATCH 066/101] Update arduino-pico core and remove MDNS restriction (#5483) --- arch/rp2xx0/rp2040.ini | 4 ++-- arch/rp2xx0/rp2350.ini | 4 ++-- src/mesh/wifi/WiFiAPClient.cpp | 6 +----- 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/arch/rp2xx0/rp2040.ini b/arch/rp2xx0/rp2040.ini index 85efa583c..5cfa678d5 100644 --- a/arch/rp2xx0/rp2040.ini +++ b/arch/rp2xx0/rp2040.ini @@ -1,8 +1,8 @@ ; Common settings for rp2040 Processor based targets [rp2040_base] -platform = https://github.com/maxgerhardt/platform-raspberrypi.git#19e30129fb1428b823be585c787dcb4ac0d9014c ; For arduino-pico 4.2.1 +platform = https://github.com/maxgerhardt/platform-raspberrypi.git#19e30129fb1428b823be585c787dcb4ac0d9014c ; For arduino-pico >=4.2.1 extends = arduino_base -platform_packages = framework-arduinopico@https://github.com/earlephilhower/arduino-pico.git#996c3bfab9758f12c07aa20cc6d352e630c16987 ; 4.2.1 with fix for sporadic hangs +platform_packages = framework-arduinopico@https://github.com/earlephilhower/arduino-pico.git#6024e9a7e82a72e38dd90f42029ba3748835eb2e ; 4.3.0 with fix MDNS board_build.core = earlephilhower board_build.filesystem_size = 0.5m diff --git a/arch/rp2xx0/rp2350.ini b/arch/rp2xx0/rp2350.ini index 6daf59bdf..c5849ff2a 100644 --- a/arch/rp2xx0/rp2350.ini +++ b/arch/rp2xx0/rp2350.ini @@ -1,8 +1,8 @@ ; Common settings for rp2040 Processor based targets [rp2350_base] -platform = https://github.com/maxgerhardt/platform-raspberrypi.git#19e30129fb1428b823be585c787dcb4ac0d9014c ; For arduino-pico 4.2.1 +platform = https://github.com/maxgerhardt/platform-raspberrypi.git#19e30129fb1428b823be585c787dcb4ac0d9014c ; For arduino-pico >=4.2.1 extends = arduino_base -platform_packages = framework-arduinopico@https://github.com/earlephilhower/arduino-pico.git#96c3bfab9758f12c07aa20cc6d352e630c16987 ; 4.2.1 with fix for sporadic hangs +platform_packages = framework-arduinopico@https://github.com/earlephilhower/arduino-pico.git#6024e9a7e82a72e38dd90f42029ba3748835eb2e ; 4.3.0 with fix MDNS board_build.core = earlephilhower board_build.filesystem_size = 0.5m diff --git a/src/mesh/wifi/WiFiAPClient.cpp b/src/mesh/wifi/WiFiAPClient.cpp index 779576d64..911a47093 100644 --- a/src/mesh/wifi/WiFiAPClient.cpp +++ b/src/mesh/wifi/WiFiAPClient.cpp @@ -62,11 +62,7 @@ static void onNetworkConnected() LOG_INFO("Start WiFi network services"); // start mdns - if ( -#ifdef ARCH_RP2040 - !moduleConfig.mqtt.enabled && // MDNS is not supported when MQTT is enabled on ARCH_RP2040 -#endif - !MDNS.begin("Meshtastic")) { + if (!MDNS.begin("Meshtastic")) { LOG_ERROR("Error setting up MDNS responder!"); } else { LOG_INFO("mDNS Host: Meshtastic.local"); From 594af0cacd68885aa34192778717b7ca2f5515f3 Mon Sep 17 00:00:00 2001 From: dylanli Date: Mon, 2 Dec 2024 16:59:34 +0800 Subject: [PATCH 067/101] Update xiao_esp32 fully support L67K (#5488) L67K module hardware changed --- variants/seeed_xiao_s3/variant.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/variants/seeed_xiao_s3/variant.h b/variants/seeed_xiao_s3/variant.h index ab886d354..f854ba38a 100644 --- a/variants/seeed_xiao_s3/variant.h +++ b/variants/seeed_xiao_s3/variant.h @@ -41,7 +41,7 @@ L76K GPS Module Information : https://www.seeedstudio.com/L76K-GNSS-Module-for-S L76K Expansion Board can not directly used, L76K Reset Pin needs to override or physically remove it, otherwise it will conflict with the SPI pins */ -// #define GPS_L76K +#define GPS_L76K #ifdef GPS_L76K #define GPS_RX_PIN 44 #define GPS_TX_PIN 43 @@ -81,4 +81,4 @@ L76K GPS Module Information : https://www.seeedstudio.com/L76K-GNSS-Module-for-S // DIO2 controlls an antenna switch and the TCXO voltage is controlled by DIO3 #define SX126X_DIO2_AS_RF_SWITCH #define SX126X_DIO3_TCXO_VOLTAGE 1.8 -#endif \ No newline at end of file +#endif From d00e0f6911005b2904bed64adcbdc6f0103336ee Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Tue, 3 Dec 2024 06:17:25 -0600 Subject: [PATCH 068/101] Convert userprefs to a json file instead of header file which has to be included everywhere (#5471) * WIP * Got string quoting and macro expansion working * Need the placeholder * Cleanup * Missed a user prefs reference * Update jsonc --- .trunk/trunk.yaml | 4 +- bin/build-userprefs-json.py | 2 +- bin/platformio-custom.py | 36 ++++++++++-- src/ButtonThread.cpp | 2 +- src/graphics/Screen.h | 3 +- src/main.cpp | 1 - src/mesh/Channels.cpp | 2 +- src/mesh/Default.cpp | 2 +- src/mesh/FloodingRouter.cpp | 2 +- src/mesh/NodeDB.cpp | 1 - src/mesh/Router.cpp | 1 - src/modules/AdminModule.cpp | 4 +- userPrefs.h | 107 ------------------------------------ userPrefs.json | 16 ------ userPrefs.jsonc | 37 +++++++++++++ 15 files changed, 79 insertions(+), 141 deletions(-) delete mode 100644 userPrefs.h delete mode 100644 userPrefs.json create mode 100644 userPrefs.jsonc diff --git a/.trunk/trunk.yaml b/.trunk/trunk.yaml index 040712e1d..743f4214d 100644 --- a/.trunk/trunk.yaml +++ b/.trunk/trunk.yaml @@ -30,7 +30,7 @@ lint: - git-diff-check - gitleaks@8.21.1 - clang-format@16.0.3 - - prettier@3.3.3 + #- prettier@3.3.3 ignore: - linters: [ALL] paths: @@ -46,4 +46,4 @@ actions: enabled: - trunk-fmt-pre-commit - trunk-check-pre-push - - trunk-upgrade-available + - trunk-upgrade-available \ No newline at end of file diff --git a/bin/build-userprefs-json.py b/bin/build-userprefs-json.py index 58f460bcf..d155bae01 100644 --- a/bin/build-userprefs-json.py +++ b/bin/build-userprefs-json.py @@ -24,7 +24,7 @@ def write_macros_to_json(macros, output_file): def main(): header_file = 'userPrefs.h' - output_file = 'userPrefs.json' + output_file = 'userPrefs.jsonc' # Uncomment all macros in the header file with open(header_file, 'r') as file: lines = file.readlines() diff --git a/bin/platformio-custom.py b/bin/platformio-custom.py index 701f6b5d8..acfeae10c 100644 --- a/bin/platformio-custom.py +++ b/bin/platformio-custom.py @@ -3,6 +3,8 @@ # trunk-ignore-all(flake8/F821): For SConstruct imports import sys from os.path import join +import json +import re from readprops import readProps @@ -90,11 +92,37 @@ prefsLoc = projenv["PROJECT_DIR"] + "/version.properties" verObj = readProps(prefsLoc) print("Using meshtastic platformio-custom.py, firmware version " + verObj["long"] + " on " + env.get("PIOENV")) +jsonLoc = env["PROJECT_DIR"] + "/userPrefs.jsonc" +with open(jsonLoc) as f: + jsonStr = re.sub("//.*","", f.read(), flags=re.MULTILINE) + userPrefs = json.loads(jsonStr) + +pref_flags = [] +# Pre-process the userPrefs +for pref in userPrefs: + if userPrefs[pref].startswith("{"): + pref_flags.append("-D" + pref + "=" + userPrefs[pref]) + elif userPrefs[pref].replace(".", "").isdigit(): + pref_flags.append("-D" + pref + "=" + userPrefs[pref]) + elif userPrefs[pref] == "true" or userPrefs[pref] == "false": + pref_flags.append("-D" + pref + "=" + userPrefs[pref]) + elif userPrefs[pref].startswith("meshtastic_"): + pref_flags.append("-D" + pref + "=" + userPrefs[pref]) + # If the value is a string, we need to wrap it in quotes + else: + pref_flags.append("-D" + pref + "=" + env.StringifyMacro(userPrefs[pref]) + "") + # General options that are passed to the C and C++ compilers -projenv.Append( - CCFLAGS=[ +flags = [ "-DAPP_VERSION=" + verObj["long"], "-DAPP_VERSION_SHORT=" + verObj["short"], "-DAPP_ENV=" + env.get("PIOENV"), - ] -) + ] + pref_flags + +print ("Using flags:") +for flag in flags: + print(flag) + +projenv.Append( + CCFLAGS=flags, +) \ No newline at end of file diff --git a/src/ButtonThread.cpp b/src/ButtonThread.cpp index 238359952..3f64b3b3e 100644 --- a/src/ButtonThread.cpp +++ b/src/ButtonThread.cpp @@ -1,5 +1,5 @@ #include "ButtonThread.h" -#include "../userPrefs.h" + #include "configuration.h" #if !MESHTASTIC_EXCLUDE_GPS #include "GPS.h" diff --git a/src/graphics/Screen.h b/src/graphics/Screen.h index 41c90ca9a..00884c5af 100644 --- a/src/graphics/Screen.h +++ b/src/graphics/Screen.h @@ -1,6 +1,5 @@ #pragma once -#include "../userPrefs.h" #include "configuration.h" #include "detect/ScanI2C.h" @@ -606,4 +605,4 @@ class Screen : public concurrency::OSThread } // namespace graphics -#endif +#endif \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 9036cd59c..902668d23 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,4 +1,3 @@ -#include "../userPrefs.h" #include "configuration.h" #if !MESHTASTIC_EXCLUDE_GPS #include "GPS.h" diff --git a/src/mesh/Channels.cpp b/src/mesh/Channels.cpp index a516268eb..cfaff7640 100644 --- a/src/mesh/Channels.cpp +++ b/src/mesh/Channels.cpp @@ -1,5 +1,5 @@ #include "Channels.h" -#include "../userPrefs.h" + #include "CryptoEngine.h" #include "Default.h" #include "DisplayFormatters.h" diff --git a/src/mesh/Default.cpp b/src/mesh/Default.cpp index ba1dafe70..1bd0340f8 100644 --- a/src/mesh/Default.cpp +++ b/src/mesh/Default.cpp @@ -1,5 +1,5 @@ #include "Default.h" -#include "../userPrefs.h" + #include "meshUtils.h" uint32_t Default::getConfiguredOrDefaultMs(uint32_t configuredInterval, uint32_t defaultInterval) diff --git a/src/mesh/FloodingRouter.cpp b/src/mesh/FloodingRouter.cpp index 81ea72381..e959297bf 100644 --- a/src/mesh/FloodingRouter.cpp +++ b/src/mesh/FloodingRouter.cpp @@ -1,5 +1,5 @@ #include "FloodingRouter.h" -#include "../userPrefs.h" + #include "configuration.h" #include "mesh-pb-constants.h" diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index 0d63d3b9b..8935e1215 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -1,4 +1,3 @@ -#include "../userPrefs.h" #include "configuration.h" #if !MESHTASTIC_EXCLUDE_GPS #include "GPS.h" diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp index 7b792db30..1303c5caa 100644 --- a/src/mesh/Router.cpp +++ b/src/mesh/Router.cpp @@ -20,7 +20,6 @@ #if ENABLE_JSON_LOGGING || ARCH_PORTDUINO #include "serialization/MeshPacketSerializer.h" #endif -#include "../userPrefs.h" #define MAX_RX_FROMRADIO \ 4 // max number of packets destined to our queue, we dispatch packets quickly so it doesn't need to be big diff --git a/src/modules/AdminModule.cpp b/src/modules/AdminModule.cpp index c81b6ede4..2d33b723d 100644 --- a/src/modules/AdminModule.cpp +++ b/src/modules/AdminModule.cpp @@ -18,7 +18,7 @@ #ifdef ARCH_PORTDUINO #include "unistd.h" #endif -#include "../userPrefs.h" + #include "Default.h" #include "TypeConversions.h" @@ -1123,4 +1123,4 @@ void disableBluetooth() nrf52Bluetooth->shutdown(); #endif #endif -} +} \ No newline at end of file diff --git a/userPrefs.h b/userPrefs.h deleted file mode 100644 index 00f04149a..000000000 --- a/userPrefs.h +++ /dev/null @@ -1,107 +0,0 @@ -#ifndef _USERPREFS_ -#define _USERPREFS_ - -// Slipstream values: - -#define USERPREFS_TZ_STRING "tzplaceholder " - -// Uncomment and modify to set device defaults - -// #define USERPREFS_EVENT_MODE 1 - -// #define USERPREFS_CONFIG_LORA_REGION meshtastic_Config_LoRaConfig_RegionCode_US -// #define USERPREFS_LORACONFIG_MODEM_PRESET meshtastic_Config_LoRaConfig_ModemPreset_SHORT_FAST -// #define USERPREFS_LORACONFIG_CHANNEL_NUM 31 -// #define USERPREFS_CONFIG_LORA_IGNORE_MQTT true - -// #define USERPREFS_CONFIG_GPS_MODE meshtastic_Config_PositionConfig_GpsMode_ENABLED - -// #define USERPREFS_CHANNELS_TO_WRITE 3 -/* -#define USERPREFS_CHANNEL_0_PSK \ - { \ - 0x38, 0x4b, 0xbc, 0xc0, 0x1d, 0xc0, 0x22, 0xd1, 0x81, 0xbf, 0x36, 0xb8, 0x61, 0x21, 0xe1, 0xfb, 0x96, 0xb7, 0x2e, 0x55, \ - 0xbf, 0x74, 0x22, 0x7e, 0x9d, 0x6a, 0xfb, 0x48, 0xd6, 0x4c, 0xb1, 0xa1 \ - } -*/ -// #define USERPREFS_CHANNEL_0_NAME "DEFCONnect" -// #define USERPREFS_CHANNEL_0_PRECISION 14 -// #define USERPREFS_CHANNEL_0_UPLINK_ENABLED true -// #define USERPREFS_CHANNEL_0_DOWNLINK_ENABLED true -/* -#define USERPREFS_CHANNEL_1_PSK \ - { \ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 \ - } -*/ -// #define USERPREFS_CHANNEL_1_NAME "REPLACEME" -// #define USERPREFS_CHANNEL_1_PRECISION 14 -// #define USERPREFS_CHANNEL_1_UPLINK_ENABLED true -// #define USERPREFS_CHANNEL_1_DOWNLINK_ENABLED true -/* -#define USERPREFS_CHANNEL_2_PSK \ - { \ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 \ - } -*/ -// #define USERPREFS_CHANNEL_2_NAME "REPLACEME" -// #define USERPREFS_CHANNEL_2_PRECISION 14 -// #define USERPREFS_CHANNEL_2_UPLINK_ENABLED true -// #define USERPREFS_CHANNEL_2_DOWNLINK_ENABLED true - -// #define USERPREFS_CONFIG_OWNER_LONG_NAME "My Long Name" -// #define USERPREFS_CONFIG_OWNER_SHORT_NAME "MLN" - -// #define USERPREFS_SPLASH_TITLE "DEFCONtastic" -// #define icon_width 34 -// #define icon_height 29 -// #define USERPREFS_HAS_SPLASH -/* -static unsigned char icon_bits[] = { - 0x00, 0xC0, 0x0F, 0x00, 0x00, 0x00, 0xF0, 0x3F, 0x00, 0x00, 0x00, 0xF8, 0x7F, 0x00, 0x00, 0x00, 0xFC, 0xFF, 0x00, 0x00, 0x00, - 0x9E, 0xE7, 0x00, 0x00, 0x00, 0x0E, 0xC7, 0x01, 0x00, 0x1C, 0x0F, 0xC7, 0x01, 0x00, 0x1C, 0xDF, 0xE7, 0x63, 0x00, 0x1C, 0xFF, - 0xBF, 0xE1, 0x00, 0x3C, 0xF3, 0xBF, 0xE3, 0x00, 0x7F, 0xF7, 0xBF, 0xF1, 0x00, 0xFF, 0xF7, 0xBF, 0xF9, 0x03, 0xFF, 0xE7, 0x9F, - 0xFF, 0x03, 0xC0, 0xCF, 0xEF, 0xDF, 0x03, 0x00, 0xDF, 0xE3, 0x8F, 0x00, 0x00, 0x7C, 0xFB, 0x03, 0x00, 0x00, 0xF8, 0xFF, 0x00, - 0x00, 0x00, 0xE0, 0x0F, 0x00, 0x00, 0x00, 0xC0, 0x0F, 0x00, 0x00, 0x00, 0x78, 0x3F, 0x00, 0x00, 0x00, 0xFC, 0xFC, 0x00, 0x00, - 0x98, 0x3F, 0xF0, 0x23, 0x00, 0xFC, 0x0F, 0xE0, 0x7F, 0x00, 0xFC, 0x03, 0x80, 0xFF, 0x01, 0xFC, 0x00, 0x00, 0x3E, 0x00, 0x70, - 0x00, 0x00, 0x1C, 0x00, 0x70, 0x00, 0x00, 0x1C, 0x00, 0x70, 0x00, 0x00, 0x1C, 0x00, 0x70, 0x00, 0x00, 0x1C, 0x00}; -*/ - -/* - * PKI Admin keys. - * If a Admin key is set with '{};' - * then it will be ignored, a PKI key must have a size of 32 byte. - */ -/* -#define USERPREFS_USE_ADMIN_KEY_0 \ - { \ - 0xcd, 0xc0, 0xb4, 0x3c, 0x53, 0x24, 0xdf, 0x13, 0xca, 0x5a, 0xa6, 0x0c, 0x0d, 0xec, 0x85, 0x5a, 0x4c, 0xf6, 0x1a, 0x96, \ - 0x04, 0x1a, 0x3e, 0xfc, 0xbb, 0x8e, 0x33, 0x71, 0xe5, 0xfc, 0xff, 0x3c \ - }; -*/ -// #define USERPREFS_USE_ADMIN_KEY_1 {}; -// #define USERPREFS_USE_ADMIN_KEY_2 {}; - -/* - * USERPREF_FIXED_GPS_LAT and USERPREF_FIXED_GPS_LON must be set, USERPREF_FIXED_GPS_ALT is optional - * - * Fixed GPS is Eiffel Tower, Paris, France - */ -// #define USERPREFS_FIXED_GPS -// #define USERPREFS_FIXED_GPS_LAT 48.85873920 -// #define USERPREFS_FIXED_GPS_LON 2.294508368 -// #define USERPREFS_FIXED_GPS_ALT 0 - -/* - * Set Fixed Bluetooth paring code - */ -// #define USERPREFS_FIXED_BLUETOOTH 121212 - -/* - * Will overwrite BUTTON_PIN if set - */ -// #define USERPREFS_BUTTON_PIN 36 - -#endif \ No newline at end of file diff --git a/userPrefs.json b/userPrefs.json deleted file mode 100644 index bc62602be..000000000 --- a/userPrefs.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "USERPREFS_CHANNEL_0_NAME": "\"DEFCONnect\"", - "USERPREFS_CHANNEL_0_PRECISION": "14", - "USERPREFS_CHANNEL_0_PSK": "{ 0x38, 0x4b, 0xbc, 0xc0, 0x1d, 0xc0, 0x22, 0xd1, 0x81, 0xbf, 0x36, 0xb8, 0x61, 0x21, 0xe1, 0xfb, 0x96, 0xb7, 0x2e, 0x55, 0xbf, 0x74, 0x22, 0x7e, 0x9d, 0x6a, 0xfb, 0x48, 0xd6, 0x4c, 0xb1, 0xa1 }", - "USERPREFS_CONFIG_LORA_IGNORE_MQTT": "true", - "USERPREFS_CONFIG_LORA_REGION": "meshtastic_Config_LoRaConfig_RegionCode_US", - "USERPREFS_CONFIG_OWNER_LONG_NAME": "\"My Long Name\"", - "USERPREFS_CONFIG_OWNER_SHORT_NAME": "\"MLN\"", - "USERPREFS_EVENT_MODE": "1", - "USERPREFS_HAS_SPLASH": "", - "USERPREFS_LORACONFIG_CHANNEL_NUM": "31", - "USERPREFS_LORACONFIG_MODEM_PRESET": "meshtastic_Config_LoRaConfig_ModemPreset_SHORT_FAST", - "USERPREFS_SPLASH_TITLE": "\"DEFCONtastic\"", - "USERPREFS_TZ_STRING": "\"tzplaceholder \"", - "USERPREFS_USE_ADMIN_KEY": "1" -} diff --git a/userPrefs.jsonc b/userPrefs.jsonc new file mode 100644 index 000000000..055f59273 --- /dev/null +++ b/userPrefs.jsonc @@ -0,0 +1,37 @@ +{ + // "USERPREFS_BUTTON_PIN": "36", + // "USERPREFS_CHANNELS_TO_WRITE": "3", + // "USERPREFS_CHANNEL_0_DOWNLINK_ENABLED": "true", + // "USERPREFS_CHANNEL_0_NAME": "DEFCONnect", + // "USERPREFS_CHANNEL_0_PRECISION": "14", + // "USERPREFS_CHANNEL_0_PSK": "{ 0x38, 0x4b, 0xbc, 0xc0, 0x1d, 0xc0, 0x22, 0xd1, 0x81, 0xbf, 0x36, 0xb8, 0x61, 0x21, 0xe1, 0xfb, 0x96, 0xb7, 0x2e, 0x55, 0xbf, 0x74, 0x22, 0x7e, 0x9d, 0x6a, 0xfb, 0x48, 0xd6, 0x4c, 0xb1, 0xa1 }", + // "USERPREFS_CHANNEL_0_UPLINK_ENABLED": "true", + // "USERPREFS_CHANNEL_1_DOWNLINK_ENABLED": "true", + // "USERPREFS_CHANNEL_1_NAME": "REPLACEME", + // "USERPREFS_CHANNEL_1_PRECISION": "14", + // "USERPREFS_CHANNEL_1_PSK": "{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }", + // "USERPREFS_CHANNEL_1_UPLINK_ENABLED": "true", + // "USERPREFS_CHANNEL_2_DOWNLINK_ENABLED": "true", + // "USERPREFS_CHANNEL_2_NAME": "REPLACEME", + // "USERPREFS_CHANNEL_2_PRECISION": "14", + // "USERPREFS_CHANNEL_2_PSK": "{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }", + // "USERPREFS_CHANNEL_2_UPLINK_ENABLED": "true", + // "USERPREFS_CONFIG_GPS_MODE": "meshtastic_Config_PositionConfig_GpsMode_ENABLED", + // "USERPREFS_CONFIG_LORA_IGNORE_MQTT": "true", + // "USERPREFS_CONFIG_LORA_REGION": "meshtastic_Config_LoRaConfig_RegionCode_US", + // "USERPREFS_CONFIG_OWNER_LONG_NAME": "My Long Name", + // "USERPREFS_CONFIG_OWNER_SHORT_NAME": "MLN", + // "USERPREFS_EVENT_MODE": "1", + // "USERPREFS_FIXED_BLUETOOTH": "121212", + // "USERPREFS_FIXED_GPS": "", + // "USERPREFS_FIXED_GPS_ALT": "0", + // "USERPREFS_FIXED_GPS_LAT": "48.85873920", + // "USERPREFS_FIXED_GPS_LON": "2.294508368", + // "USERPREFS_LORACONFIG_CHANNEL_NUM": "31", + // "USERPREFS_LORACONFIG_MODEM_PRESET": "meshtastic_Config_LoRaConfig_ModemPreset_SHORT_FAST", + // "USERPREFS_SPLASH_TITLE": "DEFCONtastic", + "USERPREFS_TZ_STRING": "tzplaceholder " + // "USERPREFS_USE_ADMIN_KEY_0": "{ 0xcd, 0xc0, 0xb4, 0x3c, 0x53, 0x24, 0xdf, 0x13, 0xca, 0x5a, 0xa6, 0x0c, 0x0d, 0xec, 0x85, 0x5a, 0x4c, 0xf6, 0x1a, 0x96, 0x04, 0x1a, 0x3e, 0xfc, 0xbb, 0x8e, 0x33, 0x71, 0xe5, 0xfc, 0xff, 0x3c }", + // "USERPREFS_USE_ADMIN_KEY_1": "{}", + // "USERPREFS_USE_ADMIN_KEY_2": "{}" +} \ No newline at end of file From 57ea6a265e6e35d7ee36d50497dafdca120ea6f3 Mon Sep 17 00:00:00 2001 From: GUVWAF <78759985+GUVWAF@users.noreply.github.com> Date: Tue, 3 Dec 2024 13:21:24 +0100 Subject: [PATCH 069/101] SimRadio: clean-up and emulate collisions (#5487) * Clean up SimRadio and don't let it use PKC * Add collision emulation for SimRadio * Add stats from SimRadio to LocalStats * Make emulating collisions optional --- src/main.cpp | 4 +- src/mesh/MeshService.cpp | 25 +----- src/mesh/MeshService.h | 4 +- src/mesh/PhoneAPI.cpp | 15 ++-- src/mesh/Router.cpp | 3 + src/modules/Telemetry/DeviceTelemetry.cpp | 8 ++ src/platform/portduino/SimRadio.cpp | 97 ++++++++++++++++++----- src/platform/portduino/SimRadio.h | 19 +++-- src/platform/portduino/architecture.h | 3 + 9 files changed, 121 insertions(+), 57 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 902668d23..33eaa131e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -82,7 +82,7 @@ NRF52Bluetooth *nrf52Bluetooth = nullptr; #include "STM32WLE5JCInterface.h" #endif -#if !HAS_RADIO && defined(ARCH_PORTDUINO) +#if defined(ARCH_PORTDUINO) #include "platform/portduino/SimRadio.h" #endif @@ -896,7 +896,7 @@ void setup() } #endif -#if !HAS_RADIO && defined(ARCH_PORTDUINO) +#if defined(ARCH_PORTDUINO) if (!rIf) { rIf = new SimRadio; if (!rIf->init()) { diff --git a/src/mesh/MeshService.cpp b/src/mesh/MeshService.cpp index 8f7717585..773ab7053 100644 --- a/src/mesh/MeshService.cpp +++ b/src/mesh/MeshService.cpp @@ -166,27 +166,10 @@ NodeNum MeshService::getNodenumFromRequestId(uint32_t request_id) */ void MeshService::handleToRadio(meshtastic_MeshPacket &p) { -#if defined(ARCH_PORTDUINO) && !HAS_RADIO - // Simulates device received a packet via the LoRa chip - if (p.decoded.portnum == meshtastic_PortNum_SIMULATOR_APP) { - // Simulator packet (=Compressed packet) is encapsulated in a MeshPacket, so need to unwrap first - meshtastic_Compressed scratch; - meshtastic_Compressed *decoded = NULL; - if (p.which_payload_variant == meshtastic_MeshPacket_decoded_tag) { - memset(&scratch, 0, sizeof(scratch)); - p.decoded.payload.size = - pb_decode_from_bytes(p.decoded.payload.bytes, p.decoded.payload.size, &meshtastic_Compressed_msg, &scratch); - if (p.decoded.payload.size) { - decoded = &scratch; - // Extract the original payload and replace - memcpy(&p.decoded.payload, &decoded->data, sizeof(decoded->data)); - // Switch the port from PortNum_SIMULATOR_APP back to the original PortNum - p.decoded.portnum = decoded->portnum; - } else - LOG_ERROR("Error decoding proto for simulator message!"); - } - // Let SimRadio receive as if it did via its LoRa chip - SimRadio::instance->startReceive(&p); +#if defined(ARCH_PORTDUINO) + if (SimRadio::instance && p.decoded.portnum == meshtastic_PortNum_SIMULATOR_APP) { + // Simulates device received a packet via the LoRa chip + SimRadio::instance->unpackAndReceive(p); return; } #endif diff --git a/src/mesh/MeshService.h b/src/mesh/MeshService.h index 1ccca4e6d..268c4308f 100644 --- a/src/mesh/MeshService.h +++ b/src/mesh/MeshService.h @@ -10,7 +10,7 @@ #include "MeshTypes.h" #include "Observer.h" #include "PointerQueue.h" -#if defined(ARCH_PORTDUINO) && !HAS_RADIO +#if defined(ARCH_PORTDUINO) #include "../platform/portduino/SimRadio.h" #endif #if defined(ARCH_ESP32) || defined(ARCH_PORTDUINO) @@ -165,4 +165,4 @@ class MeshService friend class RoutingModule; }; -extern MeshService *service; +extern MeshService *service; \ No newline at end of file diff --git a/src/mesh/PhoneAPI.cpp b/src/mesh/PhoneAPI.cpp index 20421e73e..f49718c5e 100644 --- a/src/mesh/PhoneAPI.cpp +++ b/src/mesh/PhoneAPI.cpp @@ -613,13 +613,14 @@ bool PhoneAPI::handleToRadioPacket(meshtastic_MeshPacket &p) { printPacket("PACKET FROM PHONE", &p); -// For use with the simulator, we should not ignore duplicate packets -#if !(defined(ARCH_PORTDUINO) && !HAS_RADIO) - if (p.id > 0 && wasSeenRecently(p.id)) { - LOG_DEBUG("Ignore packet from phone, already seen recently"); - return false; - } +#if defined(ARCH_PORTDUINO) + // For use with the simulator, we should not ignore duplicate packets from the phone + if (SimRadio::instance == nullptr) #endif + if (p.id > 0 && wasSeenRecently(p.id)) { + LOG_DEBUG("Ignore packet from phone, already seen recently"); + return false; + } if (p.decoded.portnum == meshtastic_PortNum_TRACEROUTE_APP && lastPortNumToRadio[p.decoded.portnum] && Throttle::isWithinTimespanMs(lastPortNumToRadio[p.decoded.portnum], THIRTY_SECONDS_MS)) { @@ -656,4 +657,4 @@ int PhoneAPI::onNotify(uint32_t newValue) } return timeout ? -1 : 0; // If we timed out, MeshService should stop iterating through observers as we just removed one -} +} \ No newline at end of file diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp index 1303c5caa..e9c62ff27 100644 --- a/src/mesh/Router.cpp +++ b/src/mesh/Router.cpp @@ -6,6 +6,7 @@ #include "NodeDB.h" #include "RTC.h" #include "configuration.h" +#include "detect/LoRaRadioType.h" #include "main.h" #include "mesh-pb-constants.h" #include "meshUtils.h" @@ -491,6 +492,8 @@ meshtastic_Routing_Error perhapsEncode(meshtastic_MeshPacket *p) // is not in the local nodedb // First, only PKC encrypt packets we are originating if (isFromUs(p) && + // Don't use PKC with simulator + radioType != SIM_RADIO && // Don't use PKC with Ham mode !owner.is_licensed && // Don't use PKC if it's not explicitly requested and a non-primary channel is requested diff --git a/src/modules/Telemetry/DeviceTelemetry.cpp b/src/modules/Telemetry/DeviceTelemetry.cpp index 4989b88e2..192754e09 100644 --- a/src/modules/Telemetry/DeviceTelemetry.cpp +++ b/src/modules/Telemetry/DeviceTelemetry.cpp @@ -130,6 +130,14 @@ meshtastic_Telemetry DeviceTelemetryModule::getLocalStatsTelemetry() telemetry.variant.local_stats.num_packets_rx_bad = RadioLibInterface::instance->rxBad; telemetry.variant.local_stats.num_tx_relay = RadioLibInterface::instance->txRelay; } +#ifdef ARCH_PORTDUINO + if (SimRadio::instance) { + telemetry.variant.local_stats.num_packets_tx = SimRadio::instance->txGood; + telemetry.variant.local_stats.num_packets_rx = SimRadio::instance->rxGood + SimRadio::instance->rxBad; + telemetry.variant.local_stats.num_packets_rx_bad = SimRadio::instance->rxBad; + telemetry.variant.local_stats.num_tx_relay = SimRadio::instance->txRelay; + } +#endif if (router) { telemetry.variant.local_stats.num_rx_dupe = router->rxDupe; telemetry.variant.local_stats.num_tx_relay_canceled = router->txRelayCanceled; diff --git a/src/platform/portduino/SimRadio.cpp b/src/platform/portduino/SimRadio.cpp index 0a77b6088..7e63b995e 100644 --- a/src/platform/portduino/SimRadio.cpp +++ b/src/platform/portduino/SimRadio.cpp @@ -73,6 +73,10 @@ void SimRadio::handleTransmitInterrupt() // ignore the transmit interrupt if (sendingPacket) completeSending(); + + isReceiving = true; + if (receivingPacket) // This happens when we don't consider something a collision if we weren't sending long enough + handleReceiveInterrupt(); } void SimRadio::completeSending() @@ -84,6 +88,8 @@ void SimRadio::completeSending() if (p) { txGood++; + if (!isFromUs(p)) + txRelay++; printPacket("Completed sending", p); // We are done sending that packet, release it @@ -113,12 +119,12 @@ bool SimRadio::canSendImmediately() bool SimRadio::isActivelyReceiving() { - return false; // TODO check how this should be simulated + return receivingPacket != nullptr; } bool SimRadio::isChannelActive() { - return false; // TODO ask simulator + return receivingPacket != nullptr; } /** Attempt to cancel a previously sent packet. Returns true if a packet was found we could cancel */ @@ -142,10 +148,16 @@ void SimRadio::onNotify(uint32_t notification) startTransmitTimer(); break; case ISR_RX: + handleReceiveInterrupt(); // LOG_DEBUG("rx complete - starting timer"); startTransmitTimer(); break; case TRANSMIT_DELAY_COMPLETED: + if (receivingPacket) { // This happens when we had a timer pending and we started receiving + handleReceiveInterrupt(); + startTransmitTimer(); + break; + } LOG_DEBUG("delay done"); // If we are not currently in receive mode, then restart the random delay (this can happen if the main thread @@ -183,6 +195,7 @@ void SimRadio::onNotify(uint32_t notification) void SimRadio::startSend(meshtastic_MeshPacket *txp) { printPacket("Start low level send", txp); + isReceiving = false; size_t numbytes = beginSending(txp); meshtastic_MeshPacket *p = packetPool.allocCopy(*txp); perhapsDecode(p); @@ -201,15 +214,64 @@ void SimRadio::startSend(meshtastic_MeshPacket *txp) service->sendQueueStatusToPhone(router->getQueueStatus(), 0, p->id); service->sendToPhone(p); // Sending back to simulator + service->loop(); // Process the send immediately +} + +// Simulates device received a packet via the LoRa chip +void SimRadio::unpackAndReceive(meshtastic_MeshPacket &p) +{ + // Simulator packet (=Compressed packet) is encapsulated in a MeshPacket, so need to unwrap first + meshtastic_Compressed scratch; + meshtastic_Compressed *decoded = NULL; + if (p.which_payload_variant == meshtastic_MeshPacket_decoded_tag) { + memset(&scratch, 0, sizeof(scratch)); + p.decoded.payload.size = + pb_decode_from_bytes(p.decoded.payload.bytes, p.decoded.payload.size, &meshtastic_Compressed_msg, &scratch); + if (p.decoded.payload.size) { + decoded = &scratch; + // Extract the original payload and replace + memcpy(&p.decoded.payload, &decoded->data, sizeof(decoded->data)); + // Switch the port from PortNum_SIMULATOR_APP back to the original PortNum + p.decoded.portnum = decoded->portnum; + } else + LOG_ERROR("Error decoding proto for simulator message!"); + } + // Let SimRadio receive as if it did via its LoRa chip + startReceive(&p); } void SimRadio::startReceive(meshtastic_MeshPacket *p) { +#ifdef USERPREFS_SIMRADIO_EMULATE_COLLISIONS + if (isActivelyReceiving()) { + LOG_WARN("Collision detected, dropping current and previous packet!"); + rxBad++; + airTime->logAirtime(RX_ALL_LOG, getPacketTime(receivingPacket)); + packetPool.release(receivingPacket); + receivingPacket = nullptr; + return; + } else if (sendingPacket) { + uint32_t airtimeLeft = tillRun(millis()); + if (airtimeLeft <= 0) { + LOG_WARN("Transmitting packet was already done"); + handleTransmitInterrupt(); // Finish sending first + } else if ((interval - airtimeLeft) > preambleTimeMsec) { + // Only if transmitting for longer than preamble there is a collision + // (channel should actually be detected as active otherwise) + LOG_WARN("Collision detected during transmission!"); + return; + } + } isReceiving = true; - size_t length = getPacketLength(p); - uint32_t xmitMsec = getPacketTime(length); - delay(xmitMsec); // Model the time it is busy receiving - handleReceiveInterrupt(p); + receivingPacket = packetPool.allocCopy(*p); + uint32_t airtimeMsec = getPacketTime(p); + notifyLater(airtimeMsec, ISR_RX, false); // Model the time it is busy receiving +#else + isReceiving = true; + receivingPacket = packetPool.allocCopy(*p); + handleReceiveInterrupt(); // Simulate receiving the packet immediately + startTransmitTimer(); +#endif } meshtastic_QueueStatus SimRadio::getQueueStatus() @@ -223,28 +285,27 @@ meshtastic_QueueStatus SimRadio::getQueueStatus() return qs; } -void SimRadio::handleReceiveInterrupt(meshtastic_MeshPacket *p) +void SimRadio::handleReceiveInterrupt() { - LOG_DEBUG("HANDLE RECEIVE INTERRUPT"); - uint32_t xmitMsec; + if (receivingPacket == nullptr) { + return; + } if (!isReceiving) { LOG_DEBUG("*** WAS_ASSERT *** handleReceiveInterrupt called when not in receive mode"); return; } - isReceiving = false; + LOG_DEBUG("HANDLE RECEIVE INTERRUPT"); + rxGood++; - // read the number of actually received bytes - size_t length = getPacketLength(p); - xmitMsec = getPacketTime(length); - // LOG_DEBUG("Payload size %d vs length (includes header) %d", p->decoded.payload.size, length); - - meshtastic_MeshPacket *mp = packetPool.allocCopy(*p); // keep a copy in packetPool + meshtastic_MeshPacket *mp = packetPool.allocCopy(*receivingPacket); // keep a copy in packetPool + packetPool.release(receivingPacket); // release the original + receivingPacket = nullptr; printPacket("Lora RX", mp); - airTime->logAirtime(RX_LOG, xmitMsec); + airTime->logAirtime(RX_LOG, getPacketTime(mp)); deliverToReceiver(mp); } @@ -265,4 +326,4 @@ int16_t SimRadio::readData(uint8_t *data, size_t len) } return state; -} +} \ No newline at end of file diff --git a/src/platform/portduino/SimRadio.h b/src/platform/portduino/SimRadio.h index 1edb4963b..c082444e5 100644 --- a/src/platform/portduino/SimRadio.h +++ b/src/platform/portduino/SimRadio.h @@ -11,11 +11,6 @@ class SimRadio : public RadioInterface, protected concurrency::NotifiedWorkerThr { enum PendingISR { ISR_NONE = 0, ISR_RX, ISR_TX, TRANSMIT_DELAY_COMPLETED }; - /** - * Debugging counts - */ - uint32_t rxBad = 0, rxGood = 0, txGood = 0; - MeshPacketQueue txQueue = MeshPacketQueue(MAX_TX_QUEUE); public: @@ -47,9 +42,17 @@ class SimRadio : public RadioInterface, protected concurrency::NotifiedWorkerThr meshtastic_QueueStatus getQueueStatus() override; + // Convert Compressed_msg to normal msg and receive it + void unpackAndReceive(meshtastic_MeshPacket &p); + + /** + * Debugging counts + */ + uint32_t rxBad = 0, rxGood = 0, txGood = 0, txRelay = 0; + protected: /// are _trying_ to receive a packet currently (note - we might just be waiting for one) - bool isReceiving = false; + bool isReceiving = true; private: void setTransmitDelay(); @@ -61,7 +64,7 @@ class SimRadio : public RadioInterface, protected concurrency::NotifiedWorkerThr void startTransmitTimerSNR(float snr); void handleTransmitInterrupt(); - void handleReceiveInterrupt(meshtastic_MeshPacket *p); + void handleReceiveInterrupt(); void onNotify(uint32_t notification); @@ -73,6 +76,8 @@ class SimRadio : public RadioInterface, protected concurrency::NotifiedWorkerThr int16_t readData(uint8_t *str, size_t len); + meshtastic_MeshPacket *receivingPacket = nullptr; // The packet we are currently receiving + protected: /** Could we send right now (i.e. either not actively receiving or transmitting)? */ virtual bool canSendImmediately(); diff --git a/src/platform/portduino/architecture.h b/src/platform/portduino/architecture.h index 321949226..3dde87199 100644 --- a/src/platform/portduino/architecture.h +++ b/src/platform/portduino/architecture.h @@ -11,6 +11,9 @@ #ifndef HAS_WIFI #define HAS_WIFI 1 #endif +#ifndef HAS_RADIO +#define HAS_RADIO 1 +#endif #ifndef HAS_RTC #define HAS_RTC 1 #endif From 7ad137b56a3fb25606b944de659839ede67269e0 Mon Sep 17 00:00:00 2001 From: Robert Date: Tue, 3 Dec 2024 06:28:46 -0600 Subject: [PATCH 070/101] add nodeId to nodeinfo update log lines and removed redundant nodeinfo update log line (#5493) --- src/mesh/NodeDB.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index 8935e1215..cd5011ea2 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -1242,7 +1242,6 @@ bool NodeDB::updateUser(uint32_t nodeId, meshtastic_User &p, uint8_t channelInde return false; } - LOG_DEBUG("old user %s/%s, channel=%d", info->user.long_name, info->user.short_name, info->channel); #if !(MESHTASTIC_EXCLUDE_PKI) if (p.public_key.size > 0) { printBytes("Incoming Pubkey: ", p.public_key.bytes, 32); @@ -1266,7 +1265,8 @@ bool NodeDB::updateUser(uint32_t nodeId, meshtastic_User &p, uint8_t channelInde } if (nodeId != getNodeNum()) info->channel = channelIndex; // Set channel we need to use to reach this node (but don't set our own channel) - LOG_DEBUG("Update changed=%d user %s/%s, channel=%d", changed, info->user.long_name, info->user.short_name, info->channel); + LOG_DEBUG("Update changed=%d user %s/%s, id=0x%08x, channel=%d", changed, info->user.long_name, info->user.short_name, nodeId, + info->channel); info->has_user = true; if (changed) { From 85b2bad2753db5db5d67b0b3e4f1dcb04b581cfe Mon Sep 17 00:00:00 2001 From: dylanli Date: Tue, 3 Dec 2024 20:29:33 +0800 Subject: [PATCH 071/101] Refact the macro definition of GPS initialization of GPSDEFAULTD_NOT_PRESENT and added seeeed Indicator to this sequence (#5494) Co-authored-by: Ben Meadors --- src/mesh/NodeDB.cpp | 2 +- variants/seeed-sensecap-indicator/variant.h | 1 + variants/t-deck/variant.h | 2 +- variants/tlora_t3s3_epaper/variant.h | 1 + 4 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index cd5011ea2..4bb9e68dd 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -464,7 +464,7 @@ void NodeDB::installDefaultConfig(bool preserveKey = false) #endif #if defined(USERPREFS_CONFIG_GPS_MODE) config.position.gps_mode = USERPREFS_CONFIG_GPS_MODE; -#elif !HAS_GPS || defined(T_DECK) || defined(TLORA_T3S3_EPAPER) +#elif !HAS_GPS || GPS_DEFAULT_NOT_PRESENT config.position.gps_mode = meshtastic_Config_PositionConfig_GpsMode_NOT_PRESENT; #elif !defined(GPS_RX_PIN) if (config.position.rx_gpio == 0) diff --git a/variants/seeed-sensecap-indicator/variant.h b/variants/seeed-sensecap-indicator/variant.h index 55895f353..6028a3ffa 100644 --- a/variants/seeed-sensecap-indicator/variant.h +++ b/variants/seeed-sensecap-indicator/variant.h @@ -40,6 +40,7 @@ // // Buzzer // #define PIN_BUZZER 19 +#define GPS_DEFAULT_NOT_PRESENT 1 #define GPS_RX_PIN 20 #define GPS_TX_PIN 19 #define HAS_GPS 1 diff --git a/variants/t-deck/variant.h b/variants/t-deck/variant.h index 6d398391e..91c12ab3d 100644 --- a/variants/t-deck/variant.h +++ b/variants/t-deck/variant.h @@ -29,7 +29,7 @@ #define BUTTON_PIN 0 // #define BUTTON_NEED_PULLUP - +#define GPS_DEFAULT_NOT_PRESENT 1 #define GPS_RX_PIN 44 #define GPS_TX_PIN 43 diff --git a/variants/tlora_t3s3_epaper/variant.h b/variants/tlora_t3s3_epaper/variant.h index 461ce0c31..732869b20 100644 --- a/variants/tlora_t3s3_epaper/variant.h +++ b/variants/tlora_t3s3_epaper/variant.h @@ -19,6 +19,7 @@ #define I2C_SCL SCL // external qwiic connector +#define GPS_DEFAULT_NOT_PRESENT 1 #define GPS_RX_PIN 44 #define GPS_TX_PIN 43 From f846503cbfa55edccdb8ec38b8f6e7b362b7bc53 Mon Sep 17 00:00:00 2001 From: Robert Date: Tue, 3 Dec 2024 06:30:19 -0600 Subject: [PATCH 072/101] Extend Length of Source and Destination Node IDs Logged (#5492) * show 8 chars for logging source and destination ids * extend legnth of source and destination nodes in log --- src/mesh/RadioInterface.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mesh/RadioInterface.cpp b/src/mesh/RadioInterface.cpp index 53b66ff0a..5161ac41f 100644 --- a/src/mesh/RadioInterface.cpp +++ b/src/mesh/RadioInterface.cpp @@ -284,8 +284,8 @@ uint32_t RadioInterface::getTxDelayMsecWeighted(float snr) void printPacket(const char *prefix, const meshtastic_MeshPacket *p) { #ifdef DEBUG_PORT - std::string out = DEBUG_PORT.mt_sprintf("%s (id=0x%08x fr=0x%02x to=0x%02x, WantAck=%d, HopLim=%d Ch=0x%x", prefix, p->id, - p->from & 0xff, p->to & 0xff, p->want_ack, p->hop_limit, p->channel); + std::string out = DEBUG_PORT.mt_sprintf("%s (id=0x%08x fr=0x%08x to=0x%08x, WantAck=%d, HopLim=%d Ch=0x%x", prefix, p->id, + p->from, p->to, p->want_ack, p->hop_limit, p->channel); if (p->which_payload_variant == meshtastic_MeshPacket_decoded_tag) { auto &s = p->decoded; @@ -622,4 +622,4 @@ size_t RadioInterface::beginSending(meshtastic_MeshPacket *p) sendingPacket = p; return p->encrypted.size + sizeof(PacketHeader); -} +} \ No newline at end of file From 10e10450cfb8f8a36fa0934ea38bbdcab15b01ce Mon Sep 17 00:00:00 2001 From: noon92 <40807970+noon92@users.noreply.github.com> Date: Tue, 3 Dec 2024 14:33:27 +0200 Subject: [PATCH 073/101] Added femtofox configs (#5477) * added femtofox configs * Rename bin/config.d/femtofox_Waveshare-SX126X-XXXM_AI-Thinker-RA-01SH.yaml to bin/config.d/femtofox/femtofox_Waveshare-SX126X-XXXM_AI-Thinker-RA-01SH.yaml * moved femtofox configs to subdir --- ...ofox_EByte-E22-900M30S_Ebyte-E22-900M22S.yaml | 16 ++++++++++++++++ .../femtofox/femtofox_EByte-E22-900MM22S.yaml | 16 ++++++++++++++++ ...femtofox_Heltec-HT-RA62_Seeed-WIO-SX1262.yaml | 14 ++++++++++++++ ...Waveshare-SX126X-XXXM_AI-Thinker-RA-01SH.yaml | 13 +++++++++++++ 4 files changed, 59 insertions(+) create mode 100644 bin/config.d/femtofox/femtofox_EByte-E22-900M30S_Ebyte-E22-900M22S.yaml create mode 100644 bin/config.d/femtofox/femtofox_EByte-E22-900MM22S.yaml create mode 100644 bin/config.d/femtofox/femtofox_Heltec-HT-RA62_Seeed-WIO-SX1262.yaml create mode 100644 bin/config.d/femtofox/femtofox_Waveshare-SX126X-XXXM_AI-Thinker-RA-01SH.yaml diff --git a/bin/config.d/femtofox/femtofox_EByte-E22-900M30S_Ebyte-E22-900M22S.yaml b/bin/config.d/femtofox/femtofox_EByte-E22-900M30S_Ebyte-E22-900M22S.yaml new file mode 100644 index 000000000..6c88b1eb2 --- /dev/null +++ b/bin/config.d/femtofox/femtofox_EByte-E22-900M30S_Ebyte-E22-900M22S.yaml @@ -0,0 +1,16 @@ +--- +Lora: +## Ebyte E22-900M30S, E22-900M22S with no external RF switching setup +## Will work with any module without RF switching, and with TCXO + Module: sx1262 + gpiochip: 1 # subtract 32 from the gpio numbers + DIO2_AS_RF_SWITCH: true + DIO3_TCXO_VOLTAGE: true + CS: 16 #pin6 / GPIO48 1C0 + IRQ: 23 #pin17 / GPIO55 1C7 + Busy: 22 #pin16 / GPIO54 1C6 + Reset: 25 #pin13 / GPIO57 1D1 + RXen: 24 #pin12 / GPIO56 1D0 + #TXen: bridge to DIO2 on E22 module + spidev: spidev0.0 + spiSpeed: 2000000 \ No newline at end of file diff --git a/bin/config.d/femtofox/femtofox_EByte-E22-900MM22S.yaml b/bin/config.d/femtofox/femtofox_EByte-E22-900MM22S.yaml new file mode 100644 index 000000000..451d5d3f4 --- /dev/null +++ b/bin/config.d/femtofox/femtofox_EByte-E22-900MM22S.yaml @@ -0,0 +1,16 @@ +--- +Lora: +## Ebyte E22-900MM22S with no external RF switching setup +## Will work with any module without RF switching and no TCXO + Module: sx1262 + gpiochip: 1 # subtract 32 from the gpio numbers + DIO2_AS_RF_SWITCH: true + DIO3_TCXO_VOLTAGE: true + CS: 16 #pin6 / GPIO48 1C0 + IRQ: 23 #pin17 / GPIO55 1C7 + Busy: 22 #pin16 / GPIO54 1C6 + Reset: 25 #pin13 / GPIO57 1D1 + RXen: 24 #pin12 / GPIO56 1D0 + #TXen: bridge to DIO2 on E22 module + spidev: spidev0.0 + spiSpeed: 2000000 \ No newline at end of file diff --git a/bin/config.d/femtofox/femtofox_Heltec-HT-RA62_Seeed-WIO-SX1262.yaml b/bin/config.d/femtofox/femtofox_Heltec-HT-RA62_Seeed-WIO-SX1262.yaml new file mode 100644 index 000000000..d5f02b42c --- /dev/null +++ b/bin/config.d/femtofox/femtofox_Heltec-HT-RA62_Seeed-WIO-SX1262.yaml @@ -0,0 +1,14 @@ +--- +Lora: +## Heltec HT-RA62, Seeed WIO SX1262 +## Will work with any module with automatic RF switching, and with TCXO + Module: sx1262 + gpiochip: 1 # subtract 32 from the gpio numbers + DIO2_AS_RF_SWITCH: true + DIO3_TCXO_VOLTAGE: true + CS: 16 #pin6 (GPIO pin 48 1C0) + IRQ: 23 #pin17 (GPIO pin 55 1C7) + Reset: 25 #pin13 (GPIO pin 57 1D1) + Busy: 22 #pin16 (GPIO pin 54 1C6) + spidev: spidev0.0 #pins are (CS=6, CLK=7, MOSI=8, MISO=9) + spiSpeed: 2000000 \ No newline at end of file diff --git a/bin/config.d/femtofox/femtofox_Waveshare-SX126X-XXXM_AI-Thinker-RA-01SH.yaml b/bin/config.d/femtofox/femtofox_Waveshare-SX126X-XXXM_AI-Thinker-RA-01SH.yaml new file mode 100644 index 000000000..23834adec --- /dev/null +++ b/bin/config.d/femtofox/femtofox_Waveshare-SX126X-XXXM_AI-Thinker-RA-01SH.yaml @@ -0,0 +1,13 @@ +--- +Lora: +## Waveshare SX126X XXXM, AI Thinker RA-01SH +## Will work with any module with automatic RF switching, and with no TCXO + Module: sx1262 + gpiochip: 1 # subtract 32 from the gpio numbers + DIO2_AS_RF_SWITCH: true + CS: 16 #pin6 (GPIO pin 48 1C0) + IRQ: 23 #pin17 (GPIO pin 55 1C7) + Reset: 25 #pin13 (GPIO pin 57 1D1) + Busy: 22 #pin16 (GPIO pin 54 1C6) + spidev: spidev0.0 #pins are (CS=6, CLK=7, MOSI=8, MISO=9) + spiSpeed: 2000000 From e4f53677fca9ad718706a471b4926e24b7dba2cc Mon Sep 17 00:00:00 2001 From: Mark Trevor Birss Date: Wed, 4 Dec 2024 13:39:02 +0200 Subject: [PATCH 074/101] [Add] LR1110, LR1120 and LR1121 to linux native Portduino (#5496) * Update main.cpp * Update PortduinoGlue.h * Update PortduinoGlue.cpp * Update PortduinoGlue.cpp * Update PortduinoGlue.cpp * Update main.cpp --- src/main.cpp | 47 +++++++++++++++++++++++- src/platform/portduino/PortduinoGlue.cpp | 11 +++++- src/platform/portduino/PortduinoGlue.h | 5 ++- 3 files changed, 60 insertions(+), 3 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 33eaa131e..53a662272 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -858,6 +858,51 @@ void setup() LOG_INFO("SX1280 init success"); } } + } else if (settingsMap[use_lr1110]) { + if (!rIf) { + LOG_DEBUG("Activate lr1110 radio on SPI port %s", settingsStrings[spidev].c_str()); + LockingArduinoHal *RadioLibHAL = new LockingArduinoHal(SPI, spiSettings); + rIf = new LR1110Interface((LockingArduinoHal *)RadioLibHAL, settingsMap[cs], settingsMap[irq], settingsMap[reset], + settingsMap[busy]); + if (!rIf->init()) { + LOG_WARN("No LR1110 radio"); + delete rIf; + rIf = NULL; + exit(EXIT_FAILURE); + } else { + LOG_INFO("LR1110 init success"); + } + } + } else if (settingsMap[use_lr1120]) { + if (!rIf) { + LOG_DEBUG("Activate lr1120 radio on SPI port %s", settingsStrings[spidev].c_str()); + LockingArduinoHal *RadioLibHAL = new LockingArduinoHal(SPI, spiSettings); + rIf = new LR1120Interface((LockingArduinoHal *)RadioLibHAL, settingsMap[cs], settingsMap[irq], settingsMap[reset], + settingsMap[busy]); + if (!rIf->init()) { + LOG_WARN("No LR1120 radio"); + delete rIf; + rIf = NULL; + exit(EXIT_FAILURE); + } else { + LOG_INFO("LR1120 init success"); + } + } + } else if (settingsMap[use_lr1121]) { + if (!rIf) { + LOG_DEBUG("Activate lr1121 radio on SPI port %s", settingsStrings[spidev].c_str()); + LockingArduinoHal *RadioLibHAL = new LockingArduinoHal(SPI, spiSettings); + rIf = new LR1121Interface((LockingArduinoHal *)RadioLibHAL, settingsMap[cs], settingsMap[irq], settingsMap[reset], + settingsMap[busy]); + if (!rIf->init()) { + LOG_WARN("No LR1121 radio"); + delete rIf; + rIf = NULL; + exit(EXIT_FAILURE); + } else { + LOG_INFO("LR1121 init success"); + } + } } else if (settingsMap[use_sx1268]) { if (!rIf) { LOG_DEBUG("Activate sx1268 radio on SPI port %s", settingsStrings[spidev].c_str()); @@ -1218,4 +1263,4 @@ void loop() mainDelay.delay(delayMsec); } } -#endif \ No newline at end of file +#endif diff --git a/src/platform/portduino/PortduinoGlue.cpp b/src/platform/portduino/PortduinoGlue.cpp index d53a5be94..a4485e91f 100644 --- a/src/platform/portduino/PortduinoGlue.cpp +++ b/src/platform/portduino/PortduinoGlue.cpp @@ -272,6 +272,9 @@ bool loadConfig(const char *configPath) settingsMap[use_sx1262] = false; settingsMap[use_rf95] = false; settingsMap[use_sx1280] = false; + settingsMap[use_lr1110] = false; + settingsMap[use_lr1120] = false; + settingsMap[use_lr1121] = false; settingsMap[use_sx1268] = false; if (yamlConfig["Lora"]["Module"] && yamlConfig["Lora"]["Module"].as("") == "sx1262") { @@ -280,6 +283,12 @@ bool loadConfig(const char *configPath) settingsMap[use_rf95] = true; } else if (yamlConfig["Lora"]["Module"] && yamlConfig["Lora"]["Module"].as("") == "sx1280") { settingsMap[use_sx1280] = true; + } else if (yamlConfig["Lora"]["Module"] && yamlConfig["Lora"]["Module"].as("") == "lr1110") { + settingsMap[use_lr1110] = true; + } else if (yamlConfig["Lora"]["Module"] && yamlConfig["Lora"]["Module"].as("") == "lr1120") { + settingsMap[use_lr1120] = true; + } else if (yamlConfig["Lora"]["Module"] && yamlConfig["Lora"]["Module"].as("") == "lr1121") { + settingsMap[use_lr1121] = true; } else if (yamlConfig["Lora"]["Module"] && yamlConfig["Lora"]["Module"].as("") == "sx1268") { settingsMap[use_sx1268] = true; } @@ -415,4 +424,4 @@ bool loadConfig(const char *configPath) static bool ends_with(std::string_view str, std::string_view suffix) { return str.size() >= suffix.size() && str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0; -} \ No newline at end of file +} diff --git a/src/platform/portduino/PortduinoGlue.h b/src/platform/portduino/PortduinoGlue.h index 95d82c1a2..1e0223c48 100644 --- a/src/platform/portduino/PortduinoGlue.h +++ b/src/platform/portduino/PortduinoGlue.h @@ -16,6 +16,9 @@ enum configNames { ch341Quirk, use_rf95, use_sx1280, + use_lr1110, + use_lr1120, + use_lr1121, use_sx1268, user, gpiochip, @@ -67,4 +70,4 @@ extern std::map settingsStrings; extern std::ofstream traceFile; int initGPIOPin(int pinNum, std::string gpioChipname); bool loadConfig(const char *configPath); -static bool ends_with(std::string_view str, std::string_view suffix); \ No newline at end of file +static bool ends_with(std::string_view str, std::string_view suffix); From 8eca6a2df8698196ae98b319000386df0be9a2d3 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 4 Dec 2024 08:15:50 -0600 Subject: [PATCH 075/101] [create-pull-request] automated change (#5500) Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com> --- protobufs | 2 +- src/mesh/generated/meshtastic/mesh.pb.h | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/protobufs b/protobufs index 02e6576ef..00c9c9932 160000 --- a/protobufs +++ b/protobufs @@ -1 +1 @@ -Subproject commit 02e6576efaa2f691be9504b8c1c6261703f7a277 +Subproject commit 00c9c9932ea50c14cdc44d497d2672a0031641ce diff --git a/src/mesh/generated/meshtastic/mesh.pb.h b/src/mesh/generated/meshtastic/mesh.pb.h index a173adb4d..da439c375 100644 --- a/src/mesh/generated/meshtastic/mesh.pb.h +++ b/src/mesh/generated/meshtastic/mesh.pb.h @@ -215,6 +215,11 @@ typedef enum _meshtastic_HardwareModel { /* WisMesh Tap RAK-4631 w/ TFT in injection modled case */ meshtastic_HardwareModel_WISMESH_TAP = 84, + /* Similar to PORTDUINO but used by Routastic devices, this is not any + particular device and does not run Meshtastic's code but supports + the same frame format. + Runs on linux, see https://github.com/Jorropo/routastic */ + meshtastic_HardwareModel_ROUTASTIC = 85, /* ------------------------------------------------------------------------------------------------------------------------------------------ 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. ------------------------------------------------------------------------------------------------------------------------------------------ */ From d3e3985e397e539417d0cd5ebbcf3081aacf8a91 Mon Sep 17 00:00:00 2001 From: Jonathan Bennett Date: Wed, 4 Dec 2024 12:15:17 -0600 Subject: [PATCH 076/101] Fix minor typos in package workflows (#5505) --- .github/workflows/package_amd64.yml | 6 +++--- .github/workflows/package_raspbian.yml | 6 +++--- .github/workflows/package_raspbian_armv7l.yml | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/package_amd64.yml b/.github/workflows/package_amd64.yml index c11566deb..ce2c85d54 100644 --- a/.github/workflows/package_amd64.yml +++ b/.github/workflows/package_amd64.yml @@ -57,11 +57,11 @@ jobs: shopt -s dotglob nullglob if [ -d .debpkg/usr/share/doc/meshtasticd/web/build ]; then mv .debpkg/usr/share/doc/meshtasticd/web/build/* .debpkg/usr/share/doc/meshtasticd/web/; fi if [ -d .debpkg/usr/share/doc/meshtasticd/web/build ]; then rmdir .debpkg/usr/share/doc/meshtasticd/web/build; fi - if [ -d .debpkg/usr/share/doc/meshtasticd/web/.DS_Store]; then rm -f .debpkg/usr/share/doc/meshtasticd/web/.DS_Store; fi + if [ -d .debpkg/usr/share/doc/meshtasticd/web/.DS_Store ]; then rm -f .debpkg/usr/share/doc/meshtasticd/web/.DS_Store; fi gunzip .debpkg/usr/share/doc/meshtasticd/web/ -r cp release/meshtasticd_linux_x86_64 .debpkg/usr/sbin/meshtasticd cp bin/config-dist.yaml .debpkg/etc/meshtasticd/config.yaml - cp bin/config.d/* .debpkg/etc/meshtasticd/available.d/ + cp bin/config.d/* .debpkg/etc/meshtasticd/available.d/ -r chmod +x .debpkg/usr/sbin/meshtasticd cp bin/meshtasticd.service .debpkg/usr/lib/systemd/system/meshtasticd.service echo "/etc/meshtasticd/config.yaml" > .debpkg/DEBIAN/conffiles @@ -82,4 +82,4 @@ jobs: name: meshtasticd_${{ steps.version.outputs.version }}_amd64.deb overwrite: true path: | - ./*.deb + ./*.deb \ No newline at end of file diff --git a/.github/workflows/package_raspbian.yml b/.github/workflows/package_raspbian.yml index 56b683fdd..46039b6ea 100644 --- a/.github/workflows/package_raspbian.yml +++ b/.github/workflows/package_raspbian.yml @@ -57,11 +57,11 @@ jobs: shopt -s dotglob nullglob if [ -d .debpkg/usr/share/doc/meshtasticd/web/build ]; then mv .debpkg/usr/share/doc/meshtasticd/web/build/* .debpkg/usr/share/doc/meshtasticd/web/; fi if [ -d .debpkg/usr/share/doc/meshtasticd/web/build ]; then rmdir .debpkg/usr/share/doc/meshtasticd/web/build; fi - if [ -d .debpkg/usr/share/doc/meshtasticd/web/.DS_Store]; then rm -f .debpkg/usr/share/doc/meshtasticd/web/.DS_Store; fi + if [ -d .debpkg/usr/share/doc/meshtasticd/web/.DS_Store ]; then rm -f .debpkg/usr/share/doc/meshtasticd/web/.DS_Store; fi gunzip .debpkg/usr/share/doc/meshtasticd/web/ -r cp release/meshtasticd_linux_aarch64 .debpkg/usr/sbin/meshtasticd cp bin/config-dist.yaml .debpkg/etc/meshtasticd/config.yaml - cp bin/config.d/* .debpkg/etc/meshtasticd/available.d/ + cp bin/config.d/* .debpkg/etc/meshtasticd/available.d/ -r chmod +x .debpkg/usr/sbin/meshtasticd cp bin/meshtasticd.service .debpkg/usr/lib/systemd/system/meshtasticd.service echo "/etc/meshtasticd/config.yaml" > .debpkg/DEBIAN/conffiles @@ -82,4 +82,4 @@ jobs: name: meshtasticd_${{ steps.version.outputs.version }}_arm64.deb overwrite: true path: | - ./*.deb + ./*.deb \ No newline at end of file diff --git a/.github/workflows/package_raspbian_armv7l.yml b/.github/workflows/package_raspbian_armv7l.yml index 663903e10..2eda103ca 100644 --- a/.github/workflows/package_raspbian_armv7l.yml +++ b/.github/workflows/package_raspbian_armv7l.yml @@ -57,11 +57,11 @@ jobs: shopt -s dotglob nullglob if [ -d .debpkg/usr/share/doc/meshtasticd/web/build ]; then mv .debpkg/usr/share/doc/meshtasticd/web/build/* .debpkg/usr/share/doc/meshtasticd/web/; fi if [ -d .debpkg/usr/share/doc/meshtasticd/web/build ]; then rmdir .debpkg/usr/share/doc/meshtasticd/web/build; fi - if [ -d .debpkg/usr/share/doc/meshtasticd/web/.DS_Store]; then rm -f .debpkg/usr/share/doc/meshtasticd/web/.DS_Store; fi + if [ -d .debpkg/usr/share/doc/meshtasticd/web/.DS_Store ]; then rm -f .debpkg/usr/share/doc/meshtasticd/web/.DS_Store; fi gunzip .debpkg/usr/share/doc/meshtasticd/web/ -r cp release/meshtasticd_linux_armv7l .debpkg/usr/sbin/meshtasticd cp bin/config-dist.yaml .debpkg/etc/meshtasticd/config.yaml - cp bin/config.d/* .debpkg/etc/meshtasticd/available.d/ + cp bin/config.d/* .debpkg/etc/meshtasticd/available.d/ -r chmod +x .debpkg/usr/sbin/meshtasticd cp bin/meshtasticd.service .debpkg/usr/lib/systemd/system/meshtasticd.service echo "/etc/meshtasticd/config.yaml" > .debpkg/DEBIAN/conffiles @@ -82,4 +82,4 @@ jobs: name: meshtasticd_${{ steps.version.outputs.version }}_armhf.deb overwrite: true path: | - ./*.deb + ./*.deb \ No newline at end of file From c3d60342f443d1980dca86a22d703b9370cdd702 Mon Sep 17 00:00:00 2001 From: GUVWAF <78759985+GUVWAF@users.noreply.github.com> Date: Thu, 5 Dec 2024 03:00:19 +0100 Subject: [PATCH 077/101] Don't use channel index for encrypted packet (#5509) * Don't use channel index for encrypted packet * Remove assert in `getKey`, set invalid key length So encrypting will fail without reboot * Reset channel to 0 when unable to encrypt Such that the NAK doesn't use the failing channel hash --- src/mesh/Channels.cpp | 3 +-- src/mesh/FloodingRouter.cpp | 3 ++- src/mesh/Router.cpp | 1 + 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/mesh/Channels.cpp b/src/mesh/Channels.cpp index cfaff7640..4bdd9e674 100644 --- a/src/mesh/Channels.cpp +++ b/src/mesh/Channels.cpp @@ -178,12 +178,11 @@ CryptoKey Channels::getKey(ChannelIndex chIndex) { meshtastic_Channel &ch = getByIndex(chIndex); const meshtastic_ChannelSettings &channelSettings = ch.settings; - assert(ch.has_settings); CryptoKey k; memset(k.bytes, 0, sizeof(k.bytes)); // In case the user provided a short key, we want to pad the rest with zeros - if (ch.role == meshtastic_Channel_Role_DISABLED) { + if (!ch.has_settings || ch.role == meshtastic_Channel_Role_DISABLED) { k.length = -1; // invalid } else { memcpy(k.bytes, channelSettings.psk.bytes, channelSettings.psk.size); diff --git a/src/mesh/FloodingRouter.cpp b/src/mesh/FloodingRouter.cpp index e959297bf..e29c596df 100644 --- a/src/mesh/FloodingRouter.cpp +++ b/src/mesh/FloodingRouter.cpp @@ -36,7 +36,8 @@ bool FloodingRouter::shouldFilterReceived(const meshtastic_MeshPacket *p) if (isRepeated) { LOG_DEBUG("Repeated reliable tx"); if (!perhapsRebroadcast(p) && isToUs(p) && p->want_ack) { - sendAckNak(meshtastic_Routing_Error_NONE, getFrom(p), p->id, p->channel, 0); + // FIXME - channel index should be used, but the packet is still encrypted here + sendAckNak(meshtastic_Routing_Error_NONE, getFrom(p), p->id, 0, 0); } } diff --git a/src/mesh/Router.cpp b/src/mesh/Router.cpp index e9c62ff27..e714ef215 100644 --- a/src/mesh/Router.cpp +++ b/src/mesh/Router.cpp @@ -271,6 +271,7 @@ ErrorCode Router::send(meshtastic_MeshPacket *p) auto encodeResult = perhapsEncode(p); if (encodeResult != meshtastic_Routing_Error_NONE) { packetPool.release(p_decoded); + p->channel = 0; // Reset the channel to 0, so we don't use the failing hash again abortSendAndNak(encodeResult, p); return encodeResult; // FIXME - this isn't a valid ErrorCode } From de774188c99ba94c8e857b984ab42db802d48771 Mon Sep 17 00:00:00 2001 From: broglep <20624281+broglep@users.noreply.github.com> Date: Thu, 5 Dec 2024 13:02:10 +0100 Subject: [PATCH 078/101] Always Announce MDNS meshtastic service (#5503) * refactor server api port into define * always announce MDNS meshtastic service --- src/mesh/api/ServerAPI.h | 2 ++ src/mesh/api/WiFiServerAPI.h | 2 +- src/mesh/api/ethServerAPI.h | 2 +- src/mesh/wifi/WiFiAPClient.cpp | 6 +++--- src/platform/portduino/PortduinoGlue.cpp | 3 ++- 5 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/mesh/api/ServerAPI.h b/src/mesh/api/ServerAPI.h index 5b84fddd7..fe6a733a7 100644 --- a/src/mesh/api/ServerAPI.h +++ b/src/mesh/api/ServerAPI.h @@ -2,6 +2,8 @@ #include "StreamAPI.h" +#define SERVER_API_DEFAULT_PORT 4403 + /** * Provides both debug printing and, if the client starts sending protobufs to us, switches to send/receive protobufs * (and starts dropping debug printing - FIXME, eventually those prints should be encapsulated in protobufs). diff --git a/src/mesh/api/WiFiServerAPI.h b/src/mesh/api/WiFiServerAPI.h index 7a3d2967f..6e60bb678 100644 --- a/src/mesh/api/WiFiServerAPI.h +++ b/src/mesh/api/WiFiServerAPI.h @@ -22,5 +22,5 @@ class WiFiServerPort : public APIServerPort explicit WiFiServerPort(int port); }; -void initApiServer(int port = 4403); +void initApiServer(int port = SERVER_API_DEFAULT_PORT); void deInitApiServer(); \ No newline at end of file diff --git a/src/mesh/api/ethServerAPI.h b/src/mesh/api/ethServerAPI.h index 6f214c75a..9d25a2fc1 100644 --- a/src/mesh/api/ethServerAPI.h +++ b/src/mesh/api/ethServerAPI.h @@ -22,4 +22,4 @@ class ethServerPort : public APIServerPort explicit ethServerPort(int port); }; -void initApiServer(int port = 4403); +void initApiServer(int port = SERVER_API_DEFAULT_PORT); diff --git a/src/mesh/wifi/WiFiAPClient.cpp b/src/mesh/wifi/WiFiAPClient.cpp index 911a47093..f9e5d1cc9 100644 --- a/src/mesh/wifi/WiFiAPClient.cpp +++ b/src/mesh/wifi/WiFiAPClient.cpp @@ -66,13 +66,13 @@ static void onNetworkConnected() LOG_ERROR("Error setting up MDNS responder!"); } else { LOG_INFO("mDNS Host: Meshtastic.local"); + MDNS.addService("meshtastic", "tcp", SERVER_API_DEFAULT_PORT); #ifdef ARCH_ESP32 MDNS.addService("http", "tcp", 80); MDNS.addService("https", "tcp", 443); + // ESP32 prints obtained IP address in WiFiEvent #elif defined(ARCH_RP2040) - // ARCH_RP2040 does not support HTTPS, create a "meshtastic" service - MDNS.addService("meshtastic", "tcp", 4403); - // ESP32 handles this in WiFiEvent + // ARCH_RP2040 does not support HTTPS LOG_INFO("Obtained IP address: %s", WiFi.localIP().toString().c_str()); #endif } diff --git a/src/platform/portduino/PortduinoGlue.cpp b/src/platform/portduino/PortduinoGlue.cpp index a4485e91f..2aa6c9054 100644 --- a/src/platform/portduino/PortduinoGlue.cpp +++ b/src/platform/portduino/PortduinoGlue.cpp @@ -9,6 +9,7 @@ #include #include "PortduinoGlue.h" +#include "api/ServerAPI.h" #include "linux/gpio/LinuxGPIOPin.h" #include "yaml-cpp/yaml.h" #include @@ -34,7 +35,7 @@ void cpuDeepSleep(uint32_t msecs) void updateBatteryLevel(uint8_t level) NOT_IMPLEMENTED("updateBatteryLevel"); -int TCPPort = 4403; +int TCPPort = SERVER_API_DEFAULT_PORT; static error_t parse_opt(int key, char *arg, struct argp_state *state) { From bac9fec17f0c23e33a0e02bc9067aeaed68c9ef8 Mon Sep 17 00:00:00 2001 From: Tom Fifield Date: Sat, 7 Dec 2024 11:39:30 +1100 Subject: [PATCH 079/101] fix nodeDB erase loop when free mem returns invalid value (0, -1). (#5519) Co-authored-by: mverch67 --- src/mesh/NodeDB.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index 4bb9e68dd..90b3e0747 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -1372,11 +1372,14 @@ meshtastic_NodeInfoLite *NodeDB::getOrCreateMeshNode(NodeNum n) if (oldestBoringIndex != -1) { oldestIndex = oldestBoringIndex; } - // Shove the remaining nodes down the chain - for (int i = oldestIndex; i < numMeshNodes - 1; i++) { - meshNodes->at(i) = meshNodes->at(i + 1); + + if (oldestIndex != -1) { + // Shove the remaining nodes down the chain + for (int i = oldestIndex; i < numMeshNodes - 1; i++) { + meshNodes->at(i) = meshNodes->at(i + 1); + } + (numMeshNodes)--; } - (numMeshNodes)--; } // add the node at the end lite = &meshNodes->at((numMeshNodes)++); From fc16d9342116235fa86cf6ac163b17125bb4b50e Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Fri, 6 Dec 2024 20:01:47 -0600 Subject: [PATCH 080/101] Add heltec capsule back --- lib/device-ui | 1 + .../heltec_capsule_sensor_v3/platformio.ini | 10 ++++ variants/heltec_capsule_sensor_v3/variant.h | 53 +++++++++++++++++++ 3 files changed, 64 insertions(+) create mode 160000 lib/device-ui create mode 100644 variants/heltec_capsule_sensor_v3/platformio.ini create mode 100644 variants/heltec_capsule_sensor_v3/variant.h diff --git a/lib/device-ui b/lib/device-ui new file mode 160000 index 000000000..6b760f537 --- /dev/null +++ b/lib/device-ui @@ -0,0 +1 @@ +Subproject commit 6b760f5373b91de1d8234922a446f7232d5247d0 diff --git a/variants/heltec_capsule_sensor_v3/platformio.ini b/variants/heltec_capsule_sensor_v3/platformio.ini new file mode 100644 index 000000000..b5ffb65c2 --- /dev/null +++ b/variants/heltec_capsule_sensor_v3/platformio.ini @@ -0,0 +1,10 @@ +[env:heltec_capsule_sensor_v3] +extends = esp32s3_base +board = heltec_wifi_lora_32_V3 +board_check = true + +build_flags = + ${esp32s3_base.build_flags} -I variants/heltec_capsule_sensor_v3 + -D HELTEC_CAPSULE_SENSOR_V3 + -D GPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely. + ;-D DEBUG_DISABLED ; uncomment this line to disable DEBUG output \ No newline at end of file diff --git a/variants/heltec_capsule_sensor_v3/variant.h b/variants/heltec_capsule_sensor_v3/variant.h new file mode 100644 index 000000000..415de0559 --- /dev/null +++ b/variants/heltec_capsule_sensor_v3/variant.h @@ -0,0 +1,53 @@ +#define LED_PIN 33 +#define LED_PIN2 34 +#define EXT_PWR_DETECT 35 + +#define BUTTON_PIN 18 + +#define BATTERY_PIN 7 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage +#define ADC_CHANNEL ADC1_GPIO7_CHANNEL +#define ADC_ATTENUATION ADC_ATTEN_DB_2_5 // lower dB for high resistance voltage divider +#define ADC_MULTIPLIER (4.9 * 1.045) +#define ADC_CTRL 36 // active HIGH, powers the voltage divider. Only on 1.1 +#define ADC_CTRL_ENABLED HIGH + +#undef GPS_RX_PIN +#undef GPS_TX_PIN +#define GPS_RX_PIN 5 +#define GPS_TX_PIN 4 +#define PIN_GPS_RESET 3 +#define GPS_RESET_MODE LOW +#define PIN_GPS_PPS 1 +#define PIN_GPS_EN 21 +#define GPS_EN_ACTIVE HIGH + +#define USE_SX1262 +#define LORA_DIO0 -1 // a No connect on the SX1262 module +#define LORA_RESET 12 +#define LORA_DIO1 14 // SX1262 IRQ +#define LORA_DIO2 13 // SX1262 BUSY +#define LORA_DIO3 // Not connected on PCB, but internally on the TTGO SX1262, if DIO3 is high the TXCO is enabled + +#define LORA_SCK 9 +#define LORA_MISO 11 +#define LORA_MOSI 10 +#define LORA_CS 8 + +#define SX126X_CS LORA_CS +#define SX126X_DIO1 LORA_DIO1 +#define SX126X_BUSY LORA_DIO2 +#define SX126X_RESET LORA_RESET + +#define SX126X_DIO2_AS_RF_SWITCH +#define SX126X_DIO3_TCXO_VOLTAGE 1.8 + +#define I2C_SDA 1 +#define I2C_SCL 2 +#define HAS_SCREEN 0 +#define SENSOR_POWER_CTRL_PIN 21 +#define SENSOR_POWER_ON 1 + +#define PERIPHERAL_WARMUP_MS 100 +#define SENSOR_GPS_CONFLICT + +#define ESP32S3_WAKE_TYPE ESP_EXT1_WAKEUP_ANY_HIGH \ No newline at end of file From 39b5fb041e2423ed5b4d4d67b51be2feeb2a7e4b Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Sat, 7 Dec 2024 05:29:13 -0600 Subject: [PATCH 081/101] Revert "Add heltec capsule back" This reverts commit fc16d9342116235fa86cf6ac163b17125bb4b50e. --- lib/device-ui | 1 - .../heltec_capsule_sensor_v3/platformio.ini | 10 ---- variants/heltec_capsule_sensor_v3/variant.h | 53 ------------------- 3 files changed, 64 deletions(-) delete mode 160000 lib/device-ui delete mode 100644 variants/heltec_capsule_sensor_v3/platformio.ini delete mode 100644 variants/heltec_capsule_sensor_v3/variant.h diff --git a/lib/device-ui b/lib/device-ui deleted file mode 160000 index 6b760f537..000000000 --- a/lib/device-ui +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 6b760f5373b91de1d8234922a446f7232d5247d0 diff --git a/variants/heltec_capsule_sensor_v3/platformio.ini b/variants/heltec_capsule_sensor_v3/platformio.ini deleted file mode 100644 index b5ffb65c2..000000000 --- a/variants/heltec_capsule_sensor_v3/platformio.ini +++ /dev/null @@ -1,10 +0,0 @@ -[env:heltec_capsule_sensor_v3] -extends = esp32s3_base -board = heltec_wifi_lora_32_V3 -board_check = true - -build_flags = - ${esp32s3_base.build_flags} -I variants/heltec_capsule_sensor_v3 - -D HELTEC_CAPSULE_SENSOR_V3 - -D GPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely. - ;-D DEBUG_DISABLED ; uncomment this line to disable DEBUG output \ No newline at end of file diff --git a/variants/heltec_capsule_sensor_v3/variant.h b/variants/heltec_capsule_sensor_v3/variant.h deleted file mode 100644 index 415de0559..000000000 --- a/variants/heltec_capsule_sensor_v3/variant.h +++ /dev/null @@ -1,53 +0,0 @@ -#define LED_PIN 33 -#define LED_PIN2 34 -#define EXT_PWR_DETECT 35 - -#define BUTTON_PIN 18 - -#define BATTERY_PIN 7 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage -#define ADC_CHANNEL ADC1_GPIO7_CHANNEL -#define ADC_ATTENUATION ADC_ATTEN_DB_2_5 // lower dB for high resistance voltage divider -#define ADC_MULTIPLIER (4.9 * 1.045) -#define ADC_CTRL 36 // active HIGH, powers the voltage divider. Only on 1.1 -#define ADC_CTRL_ENABLED HIGH - -#undef GPS_RX_PIN -#undef GPS_TX_PIN -#define GPS_RX_PIN 5 -#define GPS_TX_PIN 4 -#define PIN_GPS_RESET 3 -#define GPS_RESET_MODE LOW -#define PIN_GPS_PPS 1 -#define PIN_GPS_EN 21 -#define GPS_EN_ACTIVE HIGH - -#define USE_SX1262 -#define LORA_DIO0 -1 // a No connect on the SX1262 module -#define LORA_RESET 12 -#define LORA_DIO1 14 // SX1262 IRQ -#define LORA_DIO2 13 // SX1262 BUSY -#define LORA_DIO3 // Not connected on PCB, but internally on the TTGO SX1262, if DIO3 is high the TXCO is enabled - -#define LORA_SCK 9 -#define LORA_MISO 11 -#define LORA_MOSI 10 -#define LORA_CS 8 - -#define SX126X_CS LORA_CS -#define SX126X_DIO1 LORA_DIO1 -#define SX126X_BUSY LORA_DIO2 -#define SX126X_RESET LORA_RESET - -#define SX126X_DIO2_AS_RF_SWITCH -#define SX126X_DIO3_TCXO_VOLTAGE 1.8 - -#define I2C_SDA 1 -#define I2C_SCL 2 -#define HAS_SCREEN 0 -#define SENSOR_POWER_CTRL_PIN 21 -#define SENSOR_POWER_ON 1 - -#define PERIPHERAL_WARMUP_MS 100 -#define SENSOR_GPS_CONFLICT - -#define ESP32S3_WAKE_TYPE ESP_EXT1_WAKEUP_ANY_HIGH \ No newline at end of file From 46eab20a9025d22d97b84eeb9ad96f7e5170e43c Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Sat, 7 Dec 2024 05:30:59 -0600 Subject: [PATCH 082/101] Lets try this again minus device ui --- .../heltec_capsule_sensor_v3/platformio.ini | 10 ++++ variants/heltec_capsule_sensor_v3/variant.h | 53 +++++++++++++++++++ 2 files changed, 63 insertions(+) create mode 100644 variants/heltec_capsule_sensor_v3/platformio.ini create mode 100644 variants/heltec_capsule_sensor_v3/variant.h diff --git a/variants/heltec_capsule_sensor_v3/platformio.ini b/variants/heltec_capsule_sensor_v3/platformio.ini new file mode 100644 index 000000000..b5ffb65c2 --- /dev/null +++ b/variants/heltec_capsule_sensor_v3/platformio.ini @@ -0,0 +1,10 @@ +[env:heltec_capsule_sensor_v3] +extends = esp32s3_base +board = heltec_wifi_lora_32_V3 +board_check = true + +build_flags = + ${esp32s3_base.build_flags} -I variants/heltec_capsule_sensor_v3 + -D HELTEC_CAPSULE_SENSOR_V3 + -D GPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely. + ;-D DEBUG_DISABLED ; uncomment this line to disable DEBUG output \ No newline at end of file diff --git a/variants/heltec_capsule_sensor_v3/variant.h b/variants/heltec_capsule_sensor_v3/variant.h new file mode 100644 index 000000000..415de0559 --- /dev/null +++ b/variants/heltec_capsule_sensor_v3/variant.h @@ -0,0 +1,53 @@ +#define LED_PIN 33 +#define LED_PIN2 34 +#define EXT_PWR_DETECT 35 + +#define BUTTON_PIN 18 + +#define BATTERY_PIN 7 // A battery voltage measurement pin, voltage divider connected here to measure battery voltage +#define ADC_CHANNEL ADC1_GPIO7_CHANNEL +#define ADC_ATTENUATION ADC_ATTEN_DB_2_5 // lower dB for high resistance voltage divider +#define ADC_MULTIPLIER (4.9 * 1.045) +#define ADC_CTRL 36 // active HIGH, powers the voltage divider. Only on 1.1 +#define ADC_CTRL_ENABLED HIGH + +#undef GPS_RX_PIN +#undef GPS_TX_PIN +#define GPS_RX_PIN 5 +#define GPS_TX_PIN 4 +#define PIN_GPS_RESET 3 +#define GPS_RESET_MODE LOW +#define PIN_GPS_PPS 1 +#define PIN_GPS_EN 21 +#define GPS_EN_ACTIVE HIGH + +#define USE_SX1262 +#define LORA_DIO0 -1 // a No connect on the SX1262 module +#define LORA_RESET 12 +#define LORA_DIO1 14 // SX1262 IRQ +#define LORA_DIO2 13 // SX1262 BUSY +#define LORA_DIO3 // Not connected on PCB, but internally on the TTGO SX1262, if DIO3 is high the TXCO is enabled + +#define LORA_SCK 9 +#define LORA_MISO 11 +#define LORA_MOSI 10 +#define LORA_CS 8 + +#define SX126X_CS LORA_CS +#define SX126X_DIO1 LORA_DIO1 +#define SX126X_BUSY LORA_DIO2 +#define SX126X_RESET LORA_RESET + +#define SX126X_DIO2_AS_RF_SWITCH +#define SX126X_DIO3_TCXO_VOLTAGE 1.8 + +#define I2C_SDA 1 +#define I2C_SCL 2 +#define HAS_SCREEN 0 +#define SENSOR_POWER_CTRL_PIN 21 +#define SENSOR_POWER_ON 1 + +#define PERIPHERAL_WARMUP_MS 100 +#define SENSOR_GPS_CONFLICT + +#define ESP32S3_WAKE_TYPE ESP_EXT1_WAKEUP_ANY_HIGH \ No newline at end of file From b99e57a6fa3ade8cc75c080cfaadb0ad221290ba Mon Sep 17 00:00:00 2001 From: Ben Meadors Date: Sat, 7 Dec 2024 07:03:58 -0600 Subject: [PATCH 083/101] Add popular nrf52 pro micro to the builds (#5523) --- variants/diy/platformio.ini | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/variants/diy/platformio.ini b/variants/diy/platformio.ini index 00ff88da2..b60d46996 100644 --- a/variants/diy/platformio.ini +++ b/variants/diy/platformio.ini @@ -61,7 +61,6 @@ debug_tool = jlink [env:nrf52_promicro_diy_tcxo] extends = nrf52840_base board = promicro-nrf52840 -board_level = extra build_flags = ${nrf52840_base.build_flags} -I variants/diy/nrf52_promicro_diy_tcxo -D NRF52_PROMICRO_DIY @@ -157,4 +156,4 @@ build_src_filter = ${esp32_base.build_src_filter} lib_deps = ${esp32_base.lib_deps} lovyan03/LovyanGFX@^1.1.16 earlephilhower/ESP8266Audio@^1.9.7 - earlephilhower/ESP8266SAM@^1.0.1 + earlephilhower/ESP8266SAM@^1.0.1 \ No newline at end of file From 4a34bf648f40e2e70f92000598dff32f8e78cfdf Mon Sep 17 00:00:00 2001 From: Jonathan Bennett Date: Sat, 7 Dec 2024 10:29:49 -0600 Subject: [PATCH 084/101] Add MACAddress to config.yaml (#5506) * Add MACAddress to config.yaml * Better error handling on native, including failing to launch with blank MAC Address and real hardware. * Re-arrange Mac Address handling and add MACAddressSource * Bump portduino to remove macaddr function there --------- Co-authored-by: Ben Meadors --- arch/portduino/portduino.ini | 2 +- bin/config-dist.yaml | 4 +- src/platform/portduino/PortduinoGlue.cpp | 126 +++++++++++++++++++++-- src/platform/portduino/PortduinoGlue.h | 5 +- 4 files changed, 124 insertions(+), 13 deletions(-) diff --git a/arch/portduino/portduino.ini b/arch/portduino/portduino.ini index 04fd6db09..946a1489b 100644 --- a/arch/portduino/portduino.ini +++ b/arch/portduino/portduino.ini @@ -1,6 +1,6 @@ ; The Portduino based sim environment on top of any host OS, all hardware will be simulated [portduino_base] -platform = https://github.com/meshtastic/platform-native.git#bcd02436cfca91f7d28ad0f7dab977c6aaa781af +platform = https://github.com/meshtastic/platform-native.git#7fcee253a928535ff8b142704035b4b982f7e2d2 framework = arduino build_src_filter = diff --git a/bin/config-dist.yaml b/bin/config-dist.yaml index 77680cc63..cb25b36e7 100644 --- a/bin/config-dist.yaml +++ b/bin/config-dist.yaml @@ -160,4 +160,6 @@ Webserver: General: MaxNodes: 200 MaxMessageQueue: 100 - ConfigDirectory: /etc/meshtasticd/config.d/ \ No newline at end of file + ConfigDirectory: /etc/meshtasticd/config.d/ +# MACAddress: AA:BB:CC:DD:EE:FF +# MACAddressSource: eth0 \ No newline at end of file diff --git a/src/platform/portduino/PortduinoGlue.cpp b/src/platform/portduino/PortduinoGlue.cpp index 2aa6c9054..b6a017d9f 100644 --- a/src/platform/portduino/PortduinoGlue.cpp +++ b/src/platform/portduino/PortduinoGlue.cpp @@ -5,22 +5,27 @@ #include "sleep.h" #include "target_specific.h" -#include -#include - #include "PortduinoGlue.h" #include "api/ServerAPI.h" #include "linux/gpio/LinuxGPIOPin.h" +#include "meshUtils.h" #include "yaml-cpp/yaml.h" +#include +#include +#include +#include #include +#include #include #include +#include #include std::map settingsMap; std::map settingsStrings; std::ofstream traceFile; char *configPath = nullptr; +char *optionMac = nullptr; // FIXME - move setBluetoothEnable into a HALPlatform class void setBluetoothEnable(bool enable) @@ -49,6 +54,10 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state) case 'c': configPath = arg; break; + case 'h': + optionMac = arg; + break; + case ARGP_KEY_ARG: return 0; default: @@ -61,6 +70,7 @@ void portduinoCustomInit() { static struct argp_option options[] = {{"port", 'p', "PORT", 0, "The TCP port to use."}, {"config", 'c', "CONFIG_PATH", 0, "Full path of the .yaml config file to use."}, + {"hwid", 'h', "HWID", 0, "The mac address to assign to this virtual machine"}, {0}}; static void *childArguments; static char doc[] = "Meshtastic native build."; @@ -70,6 +80,51 @@ void portduinoCustomInit() portduinoAddArguments(child, childArguments); } +void getMacAddr(uint8_t *dmac) +{ + // We should store this value, and short-circuit all this if it's already been set. + if (optionMac != nullptr && strlen(optionMac) > 0) { + if (strlen(optionMac) >= 12) { + MAC_from_string(optionMac, dmac); + std::cout << optionMac << std::endl; + } else { + uint32_t hwId = sscanf(optionMac, "%u", &hwId); + dmac[0] = 0x80; + dmac[1] = 0; + dmac[2] = hwId >> 24; + dmac[3] = hwId >> 16; + dmac[4] = hwId >> 8; + dmac[5] = hwId & 0xff; + } + } else if (settingsStrings[mac_address].length() > 11) { + MAC_from_string(settingsStrings[mac_address], dmac); + std::cout << settingsStrings[mac_address] << std::endl; + exit; + } else { + + struct hci_dev_info di; + di.dev_id = 0; + bdaddr_t bdaddr; + char addr[18]; + int btsock; + btsock = socket(AF_BLUETOOTH, SOCK_RAW, 1); + if (btsock < 0) { // If anything fails, just return with the default value + return; + } + + if (ioctl(btsock, HCIGETDEVINFO, (void *)&di)) { + return; + } + + dmac[0] = di.bdaddr.b[5]; + dmac[1] = di.bdaddr.b[4]; + dmac[2] = di.bdaddr.b[3]; + dmac[3] = di.bdaddr.b[2]; + dmac[4] = di.bdaddr.b[1]; + dmac[5] = di.bdaddr.b[0]; + } +} + /** apps run under portduino can optionally define a portduinoSetup() to * use portduino specific init code (such as gpioBind) to setup portduino on their host machine, * before running 'arduino' code. @@ -114,10 +169,20 @@ void portduinoSetup() std::cout << "Unable to use " << configPath << " as config file" << std::endl; exit(EXIT_FAILURE); } - } else if (access("config.yaml", R_OK) == 0 && loadConfig("config.yaml")) { - std::cout << "Using local config.yaml as config file" << std::endl; - } else if (access("/etc/meshtasticd/config.yaml", R_OK) == 0 && loadConfig("/etc/meshtasticd/config.yaml")) { - std::cout << "Using /etc/meshtasticd/config.yaml as config file" << std::endl; + } else if (access("config.yaml", R_OK) == 0) { + if (loadConfig("config.yaml")) { + std::cout << "Using local config.yaml as config file" << std::endl; + } else { + std::cout << "Unable to use local config.yaml as config file" << std::endl; + exit(EXIT_FAILURE); + } + } else if (access("/etc/meshtasticd/config.yaml", R_OK) == 0) { + if (loadConfig("/etc/meshtasticd/config.yaml")) { + std::cout << "Using /etc/meshtasticd/config.yaml as config file" << std::endl; + } else { + std::cout << "Unable to use /etc/meshtasticd/config.yaml as config file" << std::endl; + exit(EXIT_FAILURE); + } } else { std::cout << "No 'config.yaml' found, running simulated." << std::endl; settingsMap[maxnodes] = 200; // Default to 200 nodes @@ -138,6 +203,14 @@ void portduinoSetup() } } + uint8_t dmac[6]; + getMacAddr(dmac); + if (dmac[0] == 0 && dmac[1] == 0 && dmac[2] == 0 && dmac[3] == 0 && dmac[4] == 0 && dmac[5] == 0) { + std::cout << "*** Blank MAC Address not allowed!" << std::endl; + std::cout << "Please set a MAC Address in config.yaml using either MACAddress or MACAddressSource." << std::endl; + exit(EXIT_FAILURE); + } + printBytes("MAC Address: ", dmac, 6); // Rather important to set this, if not running simulated. randomSeed(time(NULL)); @@ -410,10 +483,27 @@ bool loadConfig(const char *configPath) settingsStrings[webserverrootpath] = (yamlConfig["Webserver"]["RootPath"]).as(""); } - settingsMap[maxnodes] = (yamlConfig["General"]["MaxNodes"]).as(200); - settingsMap[maxtophone] = (yamlConfig["General"]["MaxMessageQueue"]).as(100); - settingsStrings[config_directory] = (yamlConfig["General"]["ConfigDirectory"]).as(""); + if (yamlConfig["General"]) { + settingsMap[maxnodes] = (yamlConfig["General"]["MaxNodes"]).as(200); + settingsMap[maxtophone] = (yamlConfig["General"]["MaxMessageQueue"]).as(100); + settingsStrings[config_directory] = (yamlConfig["General"]["ConfigDirectory"]).as(""); + if ((yamlConfig["General"]["MACAddress"]).as("") != "" && + (yamlConfig["General"]["MACAddressSource"]).as("") != "") { + std::cout << "Cannot set both MACAddress and MACAddressSource!" << std::endl; + exit(EXIT_FAILURE); + } + settingsStrings[mac_address] = (yamlConfig["General"]["MACAddress"]).as(""); + if ((yamlConfig["General"]["MACAddressSource"]).as("") != "") { + std::ifstream infile("/sys/class/net/" + (yamlConfig["General"]["MACAddressSource"]).as("") + + "/address"); + std::getline(infile, settingsStrings[mac_address]); + } + // https://stackoverflow.com/a/20326454 + settingsStrings[mac_address].erase( + std::remove(settingsStrings[mac_address].begin(), settingsStrings[mac_address].end(), ':'), + settingsStrings[mac_address].end()); + } } catch (YAML::Exception &e) { std::cout << "*** Exception " << e.what() << std::endl; return false; @@ -426,3 +516,19 @@ static bool ends_with(std::string_view str, std::string_view suffix) { return str.size() >= suffix.size() && str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0; } + +bool MAC_from_string(std::string mac_str, uint8_t *dmac) +{ + mac_str.erase(std::remove(mac_str.begin(), mac_str.end(), ':'), mac_str.end()); + if (mac_str.length() == 12) { + dmac[0] = std::stoi(settingsStrings[mac_address].substr(0, 2), nullptr, 16); + dmac[1] = std::stoi(settingsStrings[mac_address].substr(2, 2), nullptr, 16); + dmac[2] = std::stoi(settingsStrings[mac_address].substr(4, 2), nullptr, 16); + dmac[3] = std::stoi(settingsStrings[mac_address].substr(6, 2), nullptr, 16); + dmac[4] = std::stoi(settingsStrings[mac_address].substr(8, 2), nullptr, 16); + dmac[5] = std::stoi(settingsStrings[mac_address].substr(10, 2), nullptr, 16); + return true; + } else { + return false; + } +} \ No newline at end of file diff --git a/src/platform/portduino/PortduinoGlue.h b/src/platform/portduino/PortduinoGlue.h index 1e0223c48..01541eeed 100644 --- a/src/platform/portduino/PortduinoGlue.h +++ b/src/platform/portduino/PortduinoGlue.h @@ -59,7 +59,8 @@ enum configNames { maxtophone, maxnodes, ascii_logs, - config_directory + config_directory, + mac_address }; enum { no_screen, x11, st7789, st7735, st7735s, st7796, ili9341, ili9342, ili9488, hx8357d }; enum { no_touchscreen, xpt2046, stmpe610, gt911, ft5x06 }; @@ -71,3 +72,5 @@ extern std::ofstream traceFile; int initGPIOPin(int pinNum, std::string gpioChipname); bool loadConfig(const char *configPath); static bool ends_with(std::string_view str, std::string_view suffix); +void getMacAddr(uint8_t *dmac); +bool MAC_from_string(std::string mac_str, uint8_t *dmac); \ No newline at end of file From 59ed5c90491ced8c88d348a25456224fc3116dde Mon Sep 17 00:00:00 2001 From: Matthias Granberry Date: Sat, 7 Dec 2024 14:32:49 -0600 Subject: [PATCH 085/101] Configure Seeed Xiao S3 RX enable pin (#5517) --- variants/seeed_xiao_s3/variant.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/variants/seeed_xiao_s3/variant.h b/variants/seeed_xiao_s3/variant.h index f854ba38a..8f9282a7a 100644 --- a/variants/seeed_xiao_s3/variant.h +++ b/variants/seeed_xiao_s3/variant.h @@ -80,5 +80,7 @@ L76K GPS Module Information : https://www.seeedstudio.com/L76K-GNSS-Module-for-S // DIO2 controlls an antenna switch and the TCXO voltage is controlled by DIO3 #define SX126X_DIO2_AS_RF_SWITCH +#define SX126X_RXEN 38 +#define SX126X_TXEN RADIOLIB_NC #define SX126X_DIO3_TCXO_VOLTAGE 1.8 #endif From f81d3b045dd1b7e3ca7870af3da915ff4399ea98 Mon Sep 17 00:00:00 2001 From: Mark Trevor Birss Date: Sun, 8 Dec 2024 12:06:45 +0200 Subject: [PATCH 086/101] Create OpenWRT_One_mikroBUS_sx1262.yaml (#5529) --- bin/config.d/OpenWRT_One_mikroBUS_sx1262.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 bin/config.d/OpenWRT_One_mikroBUS_sx1262.yaml diff --git a/bin/config.d/OpenWRT_One_mikroBUS_sx1262.yaml b/bin/config.d/OpenWRT_One_mikroBUS_sx1262.yaml new file mode 100644 index 000000000..f31411a51 --- /dev/null +++ b/bin/config.d/OpenWRT_One_mikroBUS_sx1262.yaml @@ -0,0 +1,8 @@ +Lora: + Module: sx1262 + IRQ: 10 + Busy: 12 + Reset: 2 + spidev: spidev2.0 + DIO2_AS_RF_SWITCH: true + DIO3_TCXO_VOLTAGE: true From 3ae85e2c829427b3a6a64506afa9b6ecdf3ad081 Mon Sep 17 00:00:00 2001 From: Andrew Yong Date: Mon, 9 Dec 2024 19:38:51 +0800 Subject: [PATCH 087/101] tlora_v2_1_16: Unset BUTTON_PIN and BUTTON_NEED_PULLUP (#5535) Unset BUTTON_PIN and BUTTON_NEED_PULLUP as the board ships without a user button. Devices and users expecting a button on GPIO12 have to set [GPIO for user button](https://meshtastic.org/docs/configuration/radio/device/#gpio-for-user-button) to 12 (or any GPIO pin the momentary switch was connected to) to restore functionality. Signed-off-by: Andrew Yong --- variants/tlora_v2_1_16/variant.h | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/variants/tlora_v2_1_16/variant.h b/variants/tlora_v2_1_16/variant.h index 8bb5ce3b1..48c069ab7 100644 --- a/variants/tlora_v2_1_16/variant.h +++ b/variants/tlora_v2_1_16/variant.h @@ -8,10 +8,7 @@ #define I2C_SDA 21 // I2C pins for this board #define I2C_SCL 22 -#define LED_PIN 25 // If defined we will blink this LED -#define BUTTON_PIN 12 // If defined, this will be used for user button presses, - -#define BUTTON_NEED_PULLUP +#define LED_PIN 25 // If defined we will blink this LED #define USE_RF95 #define LORA_DIO0 26 // a No connect on the SX1262 module From f3850ee73b686a4bb2f5675a73283e9e42ef391d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 9 Dec 2024 06:50:30 -0600 Subject: [PATCH 088/101] [create-pull-request] automated change (#5530) Co-authored-by: thebentern <9000580+thebentern@users.noreply.github.com> --- version.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.properties b/version.properties index 9d03516e4..addcab501 100644 --- a/version.properties +++ b/version.properties @@ -1,4 +1,4 @@ [VERSION] major = 2 minor = 5 -build = 16 +build = 17 From d0e3427ec742223df6338c70b00fcc745bdfc53d Mon Sep 17 00:00:00 2001 From: jake-b <1012393+jake-b@users.noreply.github.com> Date: Mon, 9 Dec 2024 20:46:13 -0500 Subject: [PATCH 089/101] Fix detection for some RadSens hardware versions (#5542) Co-authored-by: Jake-B --- src/detect/ScanI2CTwoWire.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/detect/ScanI2CTwoWire.cpp b/src/detect/ScanI2CTwoWire.cpp index d29e5be8e..551b87d27 100644 --- a/src/detect/ScanI2CTwoWire.cpp +++ b/src/detect/ScanI2CTwoWire.cpp @@ -425,11 +425,14 @@ void ScanI2CTwoWire::scanPort(I2CPort port, uint8_t *address, uint8_t asize) case CGRADSENS_ADDR: // Register 0x00 of the RadSens sensor contains is product identifier 0x7D + // Undocumented, but some devices return a product identifier of 0x7A registerValue = getRegisterValue(ScanI2CTwoWire::RegisterLocation(addr, 0x00), 1); - if (registerValue == 0x7D) { + if (registerValue == 0x7D || registerValue == 0x7A) { type = CGRADSENS; logFoundDevice("ClimateGuard RadSens", (uint8_t)addr.address); break; + } else { + LOG_DEBUG("Unexpected Device ID for RadSense: addr=0x%x id=0x%x", CGRADSENS_ADDR, registerValue); } break; From 0e3dae4fec297b459da157872961fef506b808d0 Mon Sep 17 00:00:00 2001 From: Jonathan Bennett Date: Mon, 9 Dec 2024 21:51:55 -0600 Subject: [PATCH 090/101] Initialize dmac array to nulls (#5538) * Initialize dmac array to nulls * Use std::cout for print before console is init. --- src/platform/portduino/PortduinoGlue.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/platform/portduino/PortduinoGlue.cpp b/src/platform/portduino/PortduinoGlue.cpp index b6a017d9f..50b5c5b7b 100644 --- a/src/platform/portduino/PortduinoGlue.cpp +++ b/src/platform/portduino/PortduinoGlue.cpp @@ -86,7 +86,6 @@ void getMacAddr(uint8_t *dmac) if (optionMac != nullptr && strlen(optionMac) > 0) { if (strlen(optionMac) >= 12) { MAC_from_string(optionMac, dmac); - std::cout << optionMac << std::endl; } else { uint32_t hwId = sscanf(optionMac, "%u", &hwId); dmac[0] = 0x80; @@ -98,7 +97,6 @@ void getMacAddr(uint8_t *dmac) } } else if (settingsStrings[mac_address].length() > 11) { MAC_from_string(settingsStrings[mac_address], dmac); - std::cout << settingsStrings[mac_address] << std::endl; exit; } else { @@ -203,14 +201,14 @@ void portduinoSetup() } } - uint8_t dmac[6]; + uint8_t dmac[6] = {0}; getMacAddr(dmac); if (dmac[0] == 0 && dmac[1] == 0 && dmac[2] == 0 && dmac[3] == 0 && dmac[4] == 0 && dmac[5] == 0) { std::cout << "*** Blank MAC Address not allowed!" << std::endl; std::cout << "Please set a MAC Address in config.yaml using either MACAddress or MACAddressSource." << std::endl; exit(EXIT_FAILURE); } - printBytes("MAC Address: ", dmac, 6); + std::cout << "MAC Address: " << std::hex << +dmac[0] << +dmac[1] << +dmac[2] << +dmac[3] << +dmac[4] << +dmac[5] << std::endl; // Rather important to set this, if not running simulated. randomSeed(time(NULL)); @@ -531,4 +529,4 @@ bool MAC_from_string(std::string mac_str, uint8_t *dmac) } else { return false; } -} \ No newline at end of file +} From 438f627e9b856e20f0b537c5133f8cea5c4e795f Mon Sep 17 00:00:00 2001 From: Mark Trevor Birss Date: Tue, 10 Dec 2024 09:46:50 +0200 Subject: [PATCH 091/101] Update OpenWRT_One_mikroBUS_sx1262.yaml (#5544) --- bin/config.d/OpenWRT_One_mikroBUS_sx1262.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/config.d/OpenWRT_One_mikroBUS_sx1262.yaml b/bin/config.d/OpenWRT_One_mikroBUS_sx1262.yaml index f31411a51..6dc1e870d 100644 --- a/bin/config.d/OpenWRT_One_mikroBUS_sx1262.yaml +++ b/bin/config.d/OpenWRT_One_mikroBUS_sx1262.yaml @@ -2,7 +2,7 @@ Lora: Module: sx1262 IRQ: 10 Busy: 12 - Reset: 2 +# Reset: 2 spidev: spidev2.0 DIO2_AS_RF_SWITCH: true DIO3_TCXO_VOLTAGE: true From cf46e675caf241994c0cf030848bcb2ac561d767 Mon Sep 17 00:00:00 2001 From: Austin Date: Tue, 10 Dec 2024 10:14:52 -0500 Subject: [PATCH 092/101] Add portduino-buildroot variant (#5540) * Add portduino-buildroot variant * Update platform-native for platform-buildroot --- arch/portduino/portduino.ini | 4 ++-- variants/portduino-buildroot/platformio.ini | 10 ++++++++++ variants/portduino-buildroot/variant.h | 5 +++++ 3 files changed, 17 insertions(+), 2 deletions(-) create mode 100644 variants/portduino-buildroot/platformio.ini create mode 100644 variants/portduino-buildroot/variant.h diff --git a/arch/portduino/portduino.ini b/arch/portduino/portduino.ini index 946a1489b..bbafef4da 100644 --- a/arch/portduino/portduino.ini +++ b/arch/portduino/portduino.ini @@ -1,6 +1,6 @@ -; The Portduino based sim environment on top of any host OS, all hardware will be simulated +; The Portduino based 'native' environment. Currently supported on Linux targets with real LoRa hardware (or simulated). [portduino_base] -platform = https://github.com/meshtastic/platform-native.git#7fcee253a928535ff8b142704035b4b982f7e2d2 +platform = https://github.com/meshtastic/platform-native.git#73bd1a21183ca8b00c4ea58bb21315df31a50dff framework = arduino build_src_filter = diff --git a/variants/portduino-buildroot/platformio.ini b/variants/portduino-buildroot/platformio.ini new file mode 100644 index 000000000..8ef183ef3 --- /dev/null +++ b/variants/portduino-buildroot/platformio.ini @@ -0,0 +1,10 @@ +[env:buildroot] +extends = portduino_base +; The pkg-config commands below optionally add link flags. +; the || : is just a "or run the null command" to avoid returning an error code +build_flags = ${portduino_base.build_flags} -O0 -I variants/portduino-buildroot + !pkg-config --libs libulfius --silence-errors || : + !pkg-config --libs openssl --silence-errors || : +board = buildroot +lib_deps = ${portduino_base.lib_deps} +build_src_filter = ${portduino_base.build_src_filter} diff --git a/variants/portduino-buildroot/variant.h b/variants/portduino-buildroot/variant.h new file mode 100644 index 000000000..b7b39d6e8 --- /dev/null +++ b/variants/portduino-buildroot/variant.h @@ -0,0 +1,5 @@ +#define HAS_SCREEN 1 +#define CANNED_MESSAGE_MODULE_ENABLE 1 +#define HAS_GPS 1 +#define MAX_RX_TOPHONE settingsMap[maxtophone] +#define MAX_NUM_NODES settingsMap[maxnodes] \ No newline at end of file From 761a99d2411093f8902d23e513c13ffc429b49e2 Mon Sep 17 00:00:00 2001 From: Austin Date: Tue, 10 Dec 2024 11:09:54 -0500 Subject: [PATCH 093/101] portduino-buildroot: Define c standard (#5547) --- variants/portduino-buildroot/platformio.ini | 1 + 1 file changed, 1 insertion(+) diff --git a/variants/portduino-buildroot/platformio.ini b/variants/portduino-buildroot/platformio.ini index 8ef183ef3..3c8f21537 100644 --- a/variants/portduino-buildroot/platformio.ini +++ b/variants/portduino-buildroot/platformio.ini @@ -3,6 +3,7 @@ extends = portduino_base ; The pkg-config commands below optionally add link flags. ; the || : is just a "or run the null command" to avoid returning an error code build_flags = ${portduino_base.build_flags} -O0 -I variants/portduino-buildroot + -std=c++17 !pkg-config --libs libulfius --silence-errors || : !pkg-config --libs openssl --silence-errors || : board = buildroot From cabeb40c303fb8fc4da2b477c75c7d7a2b9201b9 Mon Sep 17 00:00:00 2001 From: Austin Date: Tue, 10 Dec 2024 14:58:16 -0500 Subject: [PATCH 094/101] Portduino: Move meshtasticd/web out of /usr/share/doc/ (#5548) --- .github/workflows/package_amd64.yml | 17 +++++++++++------ .github/workflows/package_raspbian.yml | 17 +++++++++++------ .github/workflows/package_raspbian_armv7l.yml | 17 +++++++++++------ bin/config-dist.yaml | 2 +- 4 files changed, 34 insertions(+), 19 deletions(-) diff --git a/.github/workflows/package_amd64.yml b/.github/workflows/package_amd64.yml index ce2c85d54..aec3bca30 100644 --- a/.github/workflows/package_amd64.yml +++ b/.github/workflows/package_amd64.yml @@ -47,18 +47,18 @@ jobs: - name: build .debpkg run: | mkdir -p .debpkg/DEBIAN - mkdir -p .debpkg/usr/share/doc/meshtasticd/web + mkdir -p .debpkg/usr/share/meshtasticd/web mkdir -p .debpkg/usr/sbin mkdir -p .debpkg/etc/meshtasticd mkdir -p .debpkg/etc/meshtasticd/config.d mkdir -p .debpkg/etc/meshtasticd/available.d mkdir -p .debpkg/usr/lib/systemd/system/ - tar -xf build.tar -C .debpkg/usr/share/doc/meshtasticd/web + tar -xf build.tar -C .debpkg/usr/share/meshtasticd/web shopt -s dotglob nullglob - if [ -d .debpkg/usr/share/doc/meshtasticd/web/build ]; then mv .debpkg/usr/share/doc/meshtasticd/web/build/* .debpkg/usr/share/doc/meshtasticd/web/; fi - if [ -d .debpkg/usr/share/doc/meshtasticd/web/build ]; then rmdir .debpkg/usr/share/doc/meshtasticd/web/build; fi - if [ -d .debpkg/usr/share/doc/meshtasticd/web/.DS_Store ]; then rm -f .debpkg/usr/share/doc/meshtasticd/web/.DS_Store; fi - gunzip .debpkg/usr/share/doc/meshtasticd/web/ -r + if [ -d .debpkg/usr/share/meshtasticd/web/build ]; then mv .debpkg/usr/share/meshtasticd/web/build/* .debpkg/usr/share/meshtasticd/web/; fi + if [ -d .debpkg/usr/share/meshtasticd/web/build ]; then rmdir .debpkg/usr/share/meshtasticd/web/build; fi + if [ -d .debpkg/usr/share/meshtasticd/web/.DS_Store ]; then rm -f .debpkg/usr/share/meshtasticd/web/.DS_Store; fi + gunzip .debpkg/usr/share/meshtasticd/web/ -r cp release/meshtasticd_linux_x86_64 .debpkg/usr/sbin/meshtasticd cp bin/config-dist.yaml .debpkg/etc/meshtasticd/config.yaml cp bin/config.d/* .debpkg/etc/meshtasticd/available.d/ -r @@ -66,6 +66,11 @@ jobs: cp bin/meshtasticd.service .debpkg/usr/lib/systemd/system/meshtasticd.service echo "/etc/meshtasticd/config.yaml" > .debpkg/DEBIAN/conffiles chmod +x .debpkg/DEBIAN/conffiles + # Transition /usr/share/doc/meshtasticd to /usr/share/meshtasticd + echo "rm -rf /usr/share/doc/meshtasticd" > .debpkg/DEBIAN/preinst + chmod +x .debpkg/DEBIAN/preinst + echo "/usr/share/meshtasticd /usr/share/doc/meshtasticd" > .debpkg/DEBIAN/meshtasticd.links + chmod +x .debpkg/DEBIAN/meshtasticd.links - uses: jiro4989/build-deb-action@v3 with: diff --git a/.github/workflows/package_raspbian.yml b/.github/workflows/package_raspbian.yml index 46039b6ea..b0a4a40d7 100644 --- a/.github/workflows/package_raspbian.yml +++ b/.github/workflows/package_raspbian.yml @@ -47,18 +47,18 @@ jobs: - name: build .debpkg run: | mkdir -p .debpkg/DEBIAN - mkdir -p .debpkg/usr/share/doc/meshtasticd/web + mkdir -p .debpkg/usr/share/meshtasticd/web mkdir -p .debpkg/usr/sbin mkdir -p .debpkg/etc/meshtasticd mkdir -p .debpkg/etc/meshtasticd/config.d mkdir -p .debpkg/etc/meshtasticd/available.d mkdir -p .debpkg/usr/lib/systemd/system/ - tar -xf build.tar -C .debpkg/usr/share/doc/meshtasticd/web + tar -xf build.tar -C .debpkg/usr/share/meshtasticd/web shopt -s dotglob nullglob - if [ -d .debpkg/usr/share/doc/meshtasticd/web/build ]; then mv .debpkg/usr/share/doc/meshtasticd/web/build/* .debpkg/usr/share/doc/meshtasticd/web/; fi - if [ -d .debpkg/usr/share/doc/meshtasticd/web/build ]; then rmdir .debpkg/usr/share/doc/meshtasticd/web/build; fi - if [ -d .debpkg/usr/share/doc/meshtasticd/web/.DS_Store ]; then rm -f .debpkg/usr/share/doc/meshtasticd/web/.DS_Store; fi - gunzip .debpkg/usr/share/doc/meshtasticd/web/ -r + if [ -d .debpkg/usr/share/meshtasticd/web/build ]; then mv .debpkg/usr/share/meshtasticd/web/build/* .debpkg/usr/share/meshtasticd/web/; fi + if [ -d .debpkg/usr/share/meshtasticd/web/build ]; then rmdir .debpkg/usr/share/meshtasticd/web/build; fi + if [ -d .debpkg/usr/share/meshtasticd/web/.DS_Store ]; then rm -f .debpkg/usr/share/meshtasticd/web/.DS_Store; fi + gunzip .debpkg/usr/share/meshtasticd/web/ -r cp release/meshtasticd_linux_aarch64 .debpkg/usr/sbin/meshtasticd cp bin/config-dist.yaml .debpkg/etc/meshtasticd/config.yaml cp bin/config.d/* .debpkg/etc/meshtasticd/available.d/ -r @@ -66,6 +66,11 @@ jobs: cp bin/meshtasticd.service .debpkg/usr/lib/systemd/system/meshtasticd.service echo "/etc/meshtasticd/config.yaml" > .debpkg/DEBIAN/conffiles chmod +x .debpkg/DEBIAN/conffiles + # Transition /usr/share/doc/meshtasticd to /usr/share/meshtasticd + echo "rm -rf /usr/share/doc/meshtasticd" > .debpkg/DEBIAN/preinst + chmod +x .debpkg/DEBIAN/preinst + echo "/usr/share/meshtasticd /usr/share/doc/meshtasticd" > .debpkg/DEBIAN/meshtasticd.links + chmod +x .debpkg/DEBIAN/meshtasticd.links - uses: jiro4989/build-deb-action@v3 with: diff --git a/.github/workflows/package_raspbian_armv7l.yml b/.github/workflows/package_raspbian_armv7l.yml index 2eda103ca..d66b46dc2 100644 --- a/.github/workflows/package_raspbian_armv7l.yml +++ b/.github/workflows/package_raspbian_armv7l.yml @@ -47,18 +47,18 @@ jobs: - name: build .debpkg run: | mkdir -p .debpkg/DEBIAN - mkdir -p .debpkg/usr/share/doc/meshtasticd/web + mkdir -p .debpkg/usr/share/meshtasticd/web mkdir -p .debpkg/usr/sbin mkdir -p .debpkg/etc/meshtasticd mkdir -p .debpkg/etc/meshtasticd/config.d mkdir -p .debpkg/etc/meshtasticd/available.d mkdir -p .debpkg/usr/lib/systemd/system/ - tar -xf build.tar -C .debpkg/usr/share/doc/meshtasticd/web + tar -xf build.tar -C .debpkg/usr/share/meshtasticd/web shopt -s dotglob nullglob - if [ -d .debpkg/usr/share/doc/meshtasticd/web/build ]; then mv .debpkg/usr/share/doc/meshtasticd/web/build/* .debpkg/usr/share/doc/meshtasticd/web/; fi - if [ -d .debpkg/usr/share/doc/meshtasticd/web/build ]; then rmdir .debpkg/usr/share/doc/meshtasticd/web/build; fi - if [ -d .debpkg/usr/share/doc/meshtasticd/web/.DS_Store ]; then rm -f .debpkg/usr/share/doc/meshtasticd/web/.DS_Store; fi - gunzip .debpkg/usr/share/doc/meshtasticd/web/ -r + if [ -d .debpkg/usr/share/meshtasticd/web/build ]; then mv .debpkg/usr/share/meshtasticd/web/build/* .debpkg/usr/share/meshtasticd/web/; fi + if [ -d .debpkg/usr/share/meshtasticd/web/build ]; then rmdir .debpkg/usr/share/meshtasticd/web/build; fi + if [ -d .debpkg/usr/share/meshtasticd/web/.DS_Store ]; then rm -f .debpkg/usr/share/meshtasticd/web/.DS_Store; fi + gunzip .debpkg/usr/share/meshtasticd/web/ -r cp release/meshtasticd_linux_armv7l .debpkg/usr/sbin/meshtasticd cp bin/config-dist.yaml .debpkg/etc/meshtasticd/config.yaml cp bin/config.d/* .debpkg/etc/meshtasticd/available.d/ -r @@ -66,6 +66,11 @@ jobs: cp bin/meshtasticd.service .debpkg/usr/lib/systemd/system/meshtasticd.service echo "/etc/meshtasticd/config.yaml" > .debpkg/DEBIAN/conffiles chmod +x .debpkg/DEBIAN/conffiles + # Transition /usr/share/doc/meshtasticd to /usr/share/meshtasticd + echo "rm -rf /usr/share/doc/meshtasticd" > .debpkg/DEBIAN/preinst + chmod +x .debpkg/DEBIAN/preinst + echo "/usr/share/meshtasticd /usr/share/doc/meshtasticd" > .debpkg/DEBIAN/meshtasticd.links + chmod +x .debpkg/DEBIAN/meshtasticd.links - uses: jiro4989/build-deb-action@v3 with: diff --git a/bin/config-dist.yaml b/bin/config-dist.yaml index cb25b36e7..ec262536f 100644 --- a/bin/config-dist.yaml +++ b/bin/config-dist.yaml @@ -155,7 +155,7 @@ Logging: Webserver: # Port: 443 # Port for Webserver & Webservices -# RootPath: /usr/share/doc/meshtasticd/web # Root Dir of WebServer +# RootPath: /usr/share/meshtasticd/web # Root Dir of WebServer General: MaxNodes: 200 From 7dd362950111fbf6ca134b678ec1975d3b6eb1fd Mon Sep 17 00:00:00 2001 From: Austin Date: Tue, 10 Dec 2024 16:02:38 -0500 Subject: [PATCH 095/101] Portduino: fix transitional symlinks (#5550) --- .github/workflows/package_amd64.yml | 4 ++-- .github/workflows/package_raspbian.yml | 4 ++-- .github/workflows/package_raspbian_armv7l.yml | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/package_amd64.yml b/.github/workflows/package_amd64.yml index aec3bca30..782ef479b 100644 --- a/.github/workflows/package_amd64.yml +++ b/.github/workflows/package_amd64.yml @@ -69,8 +69,8 @@ jobs: # Transition /usr/share/doc/meshtasticd to /usr/share/meshtasticd echo "rm -rf /usr/share/doc/meshtasticd" > .debpkg/DEBIAN/preinst chmod +x .debpkg/DEBIAN/preinst - echo "/usr/share/meshtasticd /usr/share/doc/meshtasticd" > .debpkg/DEBIAN/meshtasticd.links - chmod +x .debpkg/DEBIAN/meshtasticd.links + echo "ln -sf /usr/share/meshtasticd /usr/share/doc/meshtasticd" > .debpkg/DEBIAN/postinst + chmod +x .debpkg/DEBIAN/postinst - uses: jiro4989/build-deb-action@v3 with: diff --git a/.github/workflows/package_raspbian.yml b/.github/workflows/package_raspbian.yml index b0a4a40d7..aef8905f8 100644 --- a/.github/workflows/package_raspbian.yml +++ b/.github/workflows/package_raspbian.yml @@ -69,8 +69,8 @@ jobs: # Transition /usr/share/doc/meshtasticd to /usr/share/meshtasticd echo "rm -rf /usr/share/doc/meshtasticd" > .debpkg/DEBIAN/preinst chmod +x .debpkg/DEBIAN/preinst - echo "/usr/share/meshtasticd /usr/share/doc/meshtasticd" > .debpkg/DEBIAN/meshtasticd.links - chmod +x .debpkg/DEBIAN/meshtasticd.links + echo "ln -sf /usr/share/meshtasticd /usr/share/doc/meshtasticd" > .debpkg/DEBIAN/postinst + chmod +x .debpkg/DEBIAN/postinst - uses: jiro4989/build-deb-action@v3 with: diff --git a/.github/workflows/package_raspbian_armv7l.yml b/.github/workflows/package_raspbian_armv7l.yml index d66b46dc2..ddb84d4a7 100644 --- a/.github/workflows/package_raspbian_armv7l.yml +++ b/.github/workflows/package_raspbian_armv7l.yml @@ -69,8 +69,8 @@ jobs: # Transition /usr/share/doc/meshtasticd to /usr/share/meshtasticd echo "rm -rf /usr/share/doc/meshtasticd" > .debpkg/DEBIAN/preinst chmod +x .debpkg/DEBIAN/preinst - echo "/usr/share/meshtasticd /usr/share/doc/meshtasticd" > .debpkg/DEBIAN/meshtasticd.links - chmod +x .debpkg/DEBIAN/meshtasticd.links + echo "ln -sf /usr/share/meshtasticd /usr/share/doc/meshtasticd" > .debpkg/DEBIAN/postinst + chmod +x .debpkg/DEBIAN/postinst - uses: jiro4989/build-deb-action@v3 with: From 1790407078c4648f5fd15a7e6938e3b2b405cb32 Mon Sep 17 00:00:00 2001 From: Tom Fifield Date: Fri, 13 Dec 2024 02:58:19 +1100 Subject: [PATCH 096/101] Windows Support - Trunk and Platformio (#5397) (#5518) * Add support for GPG * Add usb device support * Add trunk.io to devcontainer * Trunk things * trunk fmt * formatting * fix trivy/DS002, checkov/CKV_DOCKER_3 * hide docker extension popup * fix trivy/DS026, checkov/CKV_DOCKER_2 Co-authored-by: Kalle Lilja <15094562+ThatKalle@users.noreply.github.com> --- .devcontainer/99-platformio-udev.rules | 183 +++++++++++++++++++++++++ .devcontainer/Dockerfile | 17 ++- .devcontainer/devcontainer.json | 13 +- 3 files changed, 210 insertions(+), 3 deletions(-) create mode 100644 .devcontainer/99-platformio-udev.rules diff --git a/.devcontainer/99-platformio-udev.rules b/.devcontainer/99-platformio-udev.rules new file mode 100644 index 000000000..83c7b8731 --- /dev/null +++ b/.devcontainer/99-platformio-udev.rules @@ -0,0 +1,183 @@ +# Copyright (c) 2014-present PlatformIO +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +##################################################################################### +# +# INSTALLATION +# +# Please visit > https://docs.platformio.org/en/latest/core/installation/udev-rules.html +# +##################################################################################### + +# +# Boards +# + +# CP210X USB UART +ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="ea[67][013]", MODE:="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" +ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="80a9", MODE:="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# FT231XS USB UART +ATTRS{idVendor}=="0403", ATTRS{idProduct}=="6015", MODE:="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# Prolific Technology, Inc. PL2303 Serial Port +ATTRS{idVendor}=="067b", ATTRS{idProduct}=="2303", MODE:="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# QinHeng Electronics HL-340 USB-Serial adapter +ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="7523", MODE:="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" +# QinHeng Electronics CH343 USB-Serial adapter +ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="55d3", MODE:="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" +# QinHeng Electronics CH9102 USB-Serial adapter +ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="55d4", MODE:="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# Arduino boards +ATTRS{idVendor}=="2341", ATTRS{idProduct}=="[08][023]*", MODE:="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" +ATTRS{idVendor}=="2a03", ATTRS{idProduct}=="[08][02]*", MODE:="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# Arduino SAM-BA +ATTRS{idVendor}=="03eb", ATTRS{idProduct}=="6124", MODE:="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{MTP_NO_PROBE}="1" + +# Digistump boards +ATTRS{idVendor}=="16d0", ATTRS{idProduct}=="0753", MODE:="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# Maple with DFU +ATTRS{idVendor}=="1eaf", ATTRS{idProduct}=="000[34]", MODE:="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# USBtiny +ATTRS{idProduct}=="0c9f", ATTRS{idVendor}=="1781", MODE:="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# USBasp V2.0 +ATTRS{idVendor}=="16c0", ATTRS{idProduct}=="05dc", MODE:="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# Teensy boards +ATTRS{idVendor}=="16c0", ATTRS{idProduct}=="04[789B]?", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" +ATTRS{idVendor}=="16c0", ATTRS{idProduct}=="04[789A]?", ENV{MTP_NO_PROBE}="1" +SUBSYSTEMS=="usb", ATTRS{idVendor}=="16c0", ATTRS{idProduct}=="04[789ABCD]?", MODE:="0666" +KERNEL=="ttyACM*", ATTRS{idVendor}=="16c0", ATTRS{idProduct}=="04[789B]?", MODE:="0666" + +# TI Stellaris Launchpad +ATTRS{idVendor}=="1cbe", ATTRS{idProduct}=="00fd", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# TI MSP430 Launchpad +ATTRS{idVendor}=="0451", ATTRS{idProduct}=="f432", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# GD32V DFU Bootloader +ATTRS{idVendor}=="28e9", ATTRS{idProduct}=="0189", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# FireBeetle-ESP32 +ATTRS{idVendor}=="1a86", ATTRS{idProduct}=="7522", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# Wio Terminal +ATTRS{idVendor}=="2886", ATTRS{idProduct}=="[08]02d", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# Raspberry Pi Pico +ATTRS{idVendor}=="2e8a", ATTRS{idProduct}=="[01]*", MODE:="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# AIR32F103 +ATTRS{idVendor}=="0d28", ATTRS{idProduct}=="0204", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# STM32 virtual COM port +ATTRS{idVendor}=="0483", ATTRS{idProduct}=="5740", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# +# Debuggers +# + +# Black Magic Probe +SUBSYSTEM=="tty", ATTRS{interface}=="Black Magic GDB Server", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" +SUBSYSTEM=="tty", ATTRS{interface}=="Black Magic UART Port", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# opendous and estick +ATTRS{idVendor}=="03eb", ATTRS{idProduct}=="204f", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# Original FT232/FT245/FT2232/FT232H/FT4232 +ATTRS{idVendor}=="0403", ATTRS{idProduct}=="60[01][104]", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# DISTORTEC JTAG-lock-pick Tiny 2 +ATTRS{idVendor}=="0403", ATTRS{idProduct}=="8220", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# TUMPA, TUMPA Lite +ATTRS{idVendor}=="0403", ATTRS{idProduct}=="8a9[89]", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# XDS100v2 +ATTRS{idVendor}=="0403", ATTRS{idProduct}=="a6d0", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# Xverve Signalyzer Tool (DT-USB-ST), Signalyzer LITE (DT-USB-SLITE) +ATTRS{idVendor}=="0403", ATTRS{idProduct}=="bca[01]", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# TI/Luminary Stellaris Evaluation Board FTDI (several) +ATTRS{idVendor}=="0403", ATTRS{idProduct}=="bcd[9a]", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# egnite Turtelizer 2 +ATTRS{idVendor}=="0403", ATTRS{idProduct}=="bdc8", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# Section5 ICEbear +ATTRS{idVendor}=="0403", ATTRS{idProduct}=="c14[01]", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# Amontec JTAGkey and JTAGkey-tiny +ATTRS{idVendor}=="0403", ATTRS{idProduct}=="cff8", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# TI ICDI +ATTRS{idVendor}=="0451", ATTRS{idProduct}=="c32a", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# STLink probes +ATTRS{idVendor}=="0483", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# Hilscher NXHX Boards +ATTRS{idVendor}=="0640", ATTRS{idProduct}=="0028", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# Hitex probes +ATTRS{idVendor}=="0640", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# Altera USB Blaster +ATTRS{idVendor}=="09fb", ATTRS{idProduct}=="6001", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# Amontec JTAGkey-HiSpeed +ATTRS{idVendor}=="0fbb", ATTRS{idProduct}=="1000", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# SEGGER J-Link +ATTRS{idVendor}=="1366", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# Raisonance RLink +ATTRS{idVendor}=="138e", ATTRS{idProduct}=="9000", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# Debug Board for Neo1973 +ATTRS{idVendor}=="1457", ATTRS{idProduct}=="5118", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# Olimex probes +ATTRS{idVendor}=="15ba", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# USBprog with OpenOCD firmware +ATTRS{idVendor}=="1781", ATTRS{idProduct}=="0c63", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# TI/Luminary Stellaris In-Circuit Debug Interface (ICDI) Board +ATTRS{idVendor}=="1cbe", ATTRS{idProduct}=="00fd", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# Marvell Sheevaplug +ATTRS{idVendor}=="9e88", ATTRS{idProduct}=="9e8f", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# Keil Software, Inc. ULink +ATTRS{idVendor}=="c251", ATTRS{idProduct}=="2710", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# CMSIS-DAP compatible adapters +ATTRS{product}=="*CMSIS-DAP*", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# Atmel AVR Dragon +ATTRS{idVendor}=="03eb", ATTRS{idProduct}=="2107", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# Espressif USB JTAG/serial debug unit +ATTRS{idVendor}=="303a", ATTRS{idProduct}=="1001", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" + +# Zephyr framework USB CDC-ACM +ATTRS{idVendor}=="2fe3", ATTRS{idProduct}=="0100", MODE="0666", ENV{ID_MM_DEVICE_IGNORE}="1", ENV{ID_MM_PORT_IGNORE}="1" \ No newline at end of file diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index c21564491..62f0b7ead 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,6 +1,9 @@ FROM mcr.microsoft.com/devcontainers/cpp:1-debian-12 -# [Optional] Uncomment this section to install additional packages. +USER root + +# trunk-ignore(terrascan/AC_DOCKER_0002): Known terrascan issue +# trunk-ignore(hadolint/DL3008): Use latest version of packages RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ && apt-get -y install --no-install-recommends \ ca-certificates \ @@ -20,6 +23,16 @@ RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \ python3-wheel \ wget \ zip \ + usbutils \ + hwdata \ + gpg \ + gnupg2 \ && apt-get clean && rm -rf /var/lib/apt/lists/* -RUN pipx install platformio==6.1.15 \ No newline at end of file +RUN pipx install platformio==6.1.15 + +COPY 99-platformio-udev.rules /etc/udev/rules.d/99-platformio-udev.rules + +USER vscode + +HEALTHCHECK NONE \ No newline at end of file diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index d83d052b0..bf1c50982 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -13,13 +13,24 @@ }, "customizations": { "vscode": { - "extensions": ["ms-vscode.cpptools", "platformio.platformio-ide"] + "extensions": [ + "ms-vscode.cpptools", + "platformio.platformio-ide", + "Trunk.io" + ], + "unwantedRecommendations": ["ms-azuretools.vscode-docker"], + "settings": { + "extensions.ignoreRecommendations": true + } } }, // Use 'forwardPorts' to make a list of ports inside the container available locally. "forwardPorts": [4403], + // Use "--device=" to make a local device available inside the container. + // "runArgs": ["--device=/dev/ttyACM0"], + // Run commands to prepare the container for use "postCreateCommand": ".devcontainer/setup.sh" } From 03770b799f7821275945ba70896012ec60bfea85 Mon Sep 17 00:00:00 2001 From: Tom Fifield Date: Fri, 13 Dec 2024 03:42:41 +1100 Subject: [PATCH 097/101] Synch minor changes from TFT branch (#5520) * Synch minor changes from TFT branch Includes: * New nordicnrf52 minor version (10.5.0 --> 10.6.0) * Optimisations for T_DECK * preparation for MESH_TAB * add ext notification module to portduino --------- Co-authored-by: mverch67 --- arch/nrf52/nrf52.ini | 3 ++- src/main.cpp | 5 ++--- src/mesh/NodeDB.cpp | 4 ++-- src/modules/Modules.cpp | 6 +++--- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/arch/nrf52/nrf52.ini b/arch/nrf52/nrf52.ini index d75f86306..778be5523 100644 --- a/arch/nrf52/nrf52.ini +++ b/arch/nrf52/nrf52.ini @@ -1,10 +1,11 @@ [nrf52_base] ; Instead of the standard nordicnrf52 platform, we use our fork which has our added variant files -platform = platformio/nordicnrf52@^10.5.0 +platform = platformio/nordicnrf52@^10.6.0 extends = arduino_base platform_packages = ; our custom Git version until they merge our PR framework-arduinoadafruitnrf52 @ https://github.com/geeksville/Adafruit_nRF52_Arduino.git + toolchain-gccarmnoneeabi@~1.90301.0 build_type = debug build_flags = diff --git a/src/main.cpp b/src/main.cpp index 53a662272..2357a00de 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -409,13 +409,13 @@ void setup() digitalWrite(AQ_SET_PIN, HIGH); #endif -#ifdef T_DECK +#if defined(T_DECK) // enable keyboard pinMode(KB_POWERON, OUTPUT); digitalWrite(KB_POWERON, HIGH); // There needs to be a delay after power on, give LILYGO-KEYBOARD some startup time // otherwise keyboard and touch screen will not work - delay(800); + delay(200); #endif // Currently only the tbeam has a PMU @@ -577,7 +577,6 @@ void setup() scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::INA3221, meshtastic_TelemetrySensorType_INA3221); scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::MAX17048, meshtastic_TelemetrySensorType_MAX17048); scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::MCP9808, meshtastic_TelemetrySensorType_MCP9808); - scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::MCP9808, meshtastic_TelemetrySensorType_MCP9808); scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::SHT31, meshtastic_TelemetrySensorType_SHT31); scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::SHTC3, meshtastic_TelemetrySensorType_SHTC3); scannerToSensorsMap(i2cScanner, ScanI2C::DeviceType::LPS22HB, meshtastic_TelemetrySensorType_LPS22); diff --git a/src/mesh/NodeDB.cpp b/src/mesh/NodeDB.cpp index 90b3e0747..6ad1a953d 100644 --- a/src/mesh/NodeDB.cpp +++ b/src/mesh/NodeDB.cpp @@ -541,7 +541,7 @@ void NodeDB::initConfigIntervals() config.display.screen_on_secs = default_screen_on_secs; -#if defined(T_WATCH_S3) || defined(T_DECK) || defined(RAK14014) +#if defined(T_WATCH_S3) || defined(T_DECK) || defined(MESH_TAB) || defined(RAK14014) config.power.is_power_saving = true; config.display.screen_on_secs = 30; config.power.wait_bluetooth_secs = 30; @@ -1422,4 +1422,4 @@ void recordCriticalError(meshtastic_CriticalErrorCode code, uint32_t address, co LOG_ERROR("A critical failure occurred, portduino is exiting"); exit(2); #endif -} \ No newline at end of file +} diff --git a/src/modules/Modules.cpp b/src/modules/Modules.cpp index ad3f0ace4..9baed824c 100644 --- a/src/modules/Modules.cpp +++ b/src/modules/Modules.cpp @@ -74,7 +74,7 @@ #include "modules/StoreForwardModule.h" #endif #endif -#if defined(ARCH_ESP32) || defined(ARCH_NRF52) || defined(ARCH_RP2040) +#if defined(ARCH_ESP32) || defined(ARCH_NRF52) || defined(ARCH_RP2040) || defined(ARCH_PORTDUINO) #if !MESHTASTIC_EXCLUDE_EXTERNALNOTIFICATION #include "modules/ExternalNotificationModule.h" #endif @@ -223,7 +223,7 @@ void setupModules() storeForwardModule = new StoreForwardModule(); #endif #endif -#if defined(ARCH_ESP32) || defined(ARCH_NRF52) || defined(ARCH_RP2040) +#if defined(ARCH_ESP32) || defined(ARCH_NRF52) || defined(ARCH_RP2040) || defined(ARCH_PORTDUINO) #if !MESHTASTIC_EXCLUDE_EXTERNALNOTIFICATION externalNotificationModule = new ExternalNotificationModule(); #endif @@ -245,4 +245,4 @@ void setupModules() // NOTE! This module must be added LAST because it likes to check for replies from other modules and avoid sending extra // acks routingModule = new RoutingModule(); -} \ No newline at end of file +} From 92225eb6c3ac60a12995432a4bfac0ee3641f093 Mon Sep 17 00:00:00 2001 From: Jonathan Bennett Date: Fri, 13 Dec 2024 11:48:27 -0600 Subject: [PATCH 098/101] DIO3_TCXO_VOLTAGE in config.yaml can now take an exact voltage (#5558) --- src/mesh/LR11x0Interface.cpp | 4 +++- src/mesh/SX126xInterface.cpp | 4 +--- src/platform/portduino/PortduinoGlue.cpp | 5 ++++- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/mesh/LR11x0Interface.cpp b/src/mesh/LR11x0Interface.cpp index 30ef8f9af..ce4f912ba 100644 --- a/src/mesh/LR11x0Interface.cpp +++ b/src/mesh/LR11x0Interface.cpp @@ -48,8 +48,10 @@ template bool LR11x0Interface::init() digitalWrite(LR11X0_POWER_EN, HIGH); #endif +#if ARCH_PORTDUINO + float tcxoVoltage = (float)settingsMap[dio3_tcxo_voltage] / 1000; // FIXME: correct logic to default to not using TCXO if no voltage is specified for LR11x0_DIO3_TCXO_VOLTAGE -#if !defined(LR11X0_DIO3_TCXO_VOLTAGE) +#elif !defined(LR11X0_DIO3_TCXO_VOLTAGE) float tcxoVoltage = 0; // "TCXO reference voltage to be set on DIO3. Defaults to 1.6 V, set to 0 to skip." per // https://github.com/jgromes/RadioLib/blob/690a050ebb46e6097c5d00c371e961c1caa3b52e/src/modules/LR11x0/LR11x0.h#L471C26-L471C104 diff --git a/src/mesh/SX126xInterface.cpp b/src/mesh/SX126xInterface.cpp index 002fb41ca..ed0267c5b 100644 --- a/src/mesh/SX126xInterface.cpp +++ b/src/mesh/SX126xInterface.cpp @@ -50,9 +50,7 @@ template bool SX126xInterface::init() #endif #if ARCH_PORTDUINO - float tcxoVoltage = 0; - if (settingsMap[dio3_tcxo_voltage]) - tcxoVoltage = 1.8; + float tcxoVoltage = (float)settingsMap[dio3_tcxo_voltage] / 1000; if (settingsMap[sx126x_ant_sw] != RADIOLIB_NC) { digitalWrite(settingsMap[sx126x_ant_sw], HIGH); pinMode(settingsMap[sx126x_ant_sw], OUTPUT); diff --git a/src/platform/portduino/PortduinoGlue.cpp b/src/platform/portduino/PortduinoGlue.cpp index 50b5c5b7b..fa0c8c502 100644 --- a/src/platform/portduino/PortduinoGlue.cpp +++ b/src/platform/portduino/PortduinoGlue.cpp @@ -365,7 +365,10 @@ bool loadConfig(const char *configPath) settingsMap[use_sx1268] = true; } settingsMap[dio2_as_rf_switch] = yamlConfig["Lora"]["DIO2_AS_RF_SWITCH"].as(false); - settingsMap[dio3_tcxo_voltage] = yamlConfig["Lora"]["DIO3_TCXO_VOLTAGE"].as(false); + settingsMap[dio3_tcxo_voltage] = yamlConfig["Lora"]["DIO3_TCXO_VOLTAGE"].as(0) * 1000; + if (settingsMap[dio3_tcxo_voltage] == 0 && yamlConfig["Lora"]["DIO3_TCXO_VOLTAGE"].as(false)) { + settingsMap[dio3_tcxo_voltage] = 1800; // default millivolts for "true" + } settingsMap[cs] = yamlConfig["Lora"]["CS"].as(RADIOLIB_NC); settingsMap[irq] = yamlConfig["Lora"]["IRQ"].as(RADIOLIB_NC); settingsMap[busy] = yamlConfig["Lora"]["Busy"].as(RADIOLIB_NC); From 332dbaf57376cf93befaf8cf35e244e4ef9bf982 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20G=C3=B6ttgens?= Date: Sat, 14 Dec 2024 10:59:15 +0100 Subject: [PATCH 099/101] Support TLORA_V3.0 (#5563) - Support TLORA_V3.0. Update of the legendary 2.1_1.6.1 with solar charger, TCXO and IPEX connector. - 'extra' some short-lived EOL intermediate boards in that range. If possible use T3S3 instead of all of these! - update trunk to latest version --- .trunk/trunk.yaml | 25 +++++++++++----------- platformio.ini | 1 + variants/tlora_v2_1_16_tcxo/platformio.ini | 1 + variants/tlora_v2_1_18/platformio.ini | 1 + variants/tlora_v3_3_0_tcxo/platformio.ini | 11 ++++++++++ 5 files changed, 27 insertions(+), 12 deletions(-) create mode 100644 variants/tlora_v3_3_0_tcxo/platformio.ini diff --git a/.trunk/trunk.yaml b/.trunk/trunk.yaml index 743f4214d..f2393592c 100644 --- a/.trunk/trunk.yaml +++ b/.trunk/trunk.yaml @@ -4,31 +4,32 @@ cli: plugins: sources: - id: trunk - ref: v1.6.4 + ref: v1.6.6 uri: https://github.com/trunk-io/plugins lint: enabled: - - trufflehog@3.83.6 + - prettier@3.4.2 + - trufflehog@3.86.1 - yamllint@1.35.1 - - bandit@1.7.10 - - checkov@3.2.287 + - bandit@1.8.0 + - checkov@3.2.334 - terrascan@1.19.9 - - trivy@0.56.2 + - trivy@0.58.0 #- trufflehog@3.63.2-rc0 - taplo@0.9.3 - - ruff@0.7.3 + - ruff@0.8.3 - isort@5.13.2 - - markdownlint@0.42.0 - - oxipng@9.1.2 + - markdownlint@0.43.0 + - oxipng@9.1.3 - svgo@3.3.2 - actionlint@1.7.4 - flake8@7.1.1 - - hadolint@2.12.0 + - hadolint@2.12.1-beta - shfmt@3.6.0 - shellcheck@0.10.0 - black@24.10.0 - git-diff-check - - gitleaks@8.21.1 + - gitleaks@8.21.2 - clang-format@16.0.3 #- prettier@3.3.3 ignore: @@ -39,11 +40,11 @@ runtimes: enabled: - python@3.10.8 - go@1.21.0 - - node@18.12.1 + - node@18.20.5 actions: disabled: - trunk-announce enabled: - trunk-fmt-pre-commit - trunk-check-pre-push - - trunk-upgrade-available \ No newline at end of file + - trunk-upgrade-available diff --git a/platformio.ini b/platformio.ini index cc08b33a0..08d21665f 100644 --- a/platformio.ini +++ b/platformio.ini @@ -16,6 +16,7 @@ default_envs = tbeam ;default_envs = tlora-v2 ;default_envs = tlora-v2-1-1_6 ;default_envs = tlora-v2-1-1_6-tcxo +;default_envs = tlora-v3-3-0-tcxo ;default_envs = tlora-t3s3-v1 ;default_envs = t-echo ;default_envs = canaryone diff --git a/variants/tlora_v2_1_16_tcxo/platformio.ini b/variants/tlora_v2_1_16_tcxo/platformio.ini index e54c1a920..538fd81b0 100644 --- a/variants/tlora_v2_1_16_tcxo/platformio.ini +++ b/variants/tlora_v2_1_16_tcxo/platformio.ini @@ -1,5 +1,6 @@ [env:tlora-v2-1-1_6-tcxo] extends = esp32_base +board_level = extra board = ttgo-lora32-v21 build_flags = ${esp32_base.build_flags} diff --git a/variants/tlora_v2_1_18/platformio.ini b/variants/tlora_v2_1_18/platformio.ini index 36d6a3157..48a001ced 100644 --- a/variants/tlora_v2_1_18/platformio.ini +++ b/variants/tlora_v2_1_18/platformio.ini @@ -1,5 +1,6 @@ [env:tlora-v2-1-1_8] extends = esp32_base +board_level = extra board = ttgo-lora32-v21 build_flags = diff --git a/variants/tlora_v3_3_0_tcxo/platformio.ini b/variants/tlora_v3_3_0_tcxo/platformio.ini new file mode 100644 index 000000000..4066d64b0 --- /dev/null +++ b/variants/tlora_v3_3_0_tcxo/platformio.ini @@ -0,0 +1,11 @@ +[env:tlora-v3-3-0-tcxo] +extends = esp32_base +board = ttgo-lora32-v21 +board_level = extra +build_flags = + ${esp32_base.build_flags} + -D TLORA_V2_1_16 + -I variants/tlora_v2_1_16 + -D GPS_POWER_TOGGLE ; comment this line to disable triple press function on the user button to turn off gps entirely. + -D LORA_TCXO_GPIO=12 + -D BUTTON_PIN=0 \ No newline at end of file From c3f89a6db8feeb304b0969841db2c4ffba53a9c9 Mon Sep 17 00:00:00 2001 From: Mark Trevor Birss Date: Sat, 14 Dec 2024 12:46:35 +0200 Subject: [PATCH 100/101] Create OpenWRT-One-mikroBUS-LR-IOT-CLICK.yaml (#5564) --- bin/config.d/OpenWRT-One-mikroBUS-LR-IOT-CLICK.yaml | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 bin/config.d/OpenWRT-One-mikroBUS-LR-IOT-CLICK.yaml diff --git a/bin/config.d/OpenWRT-One-mikroBUS-LR-IOT-CLICK.yaml b/bin/config.d/OpenWRT-One-mikroBUS-LR-IOT-CLICK.yaml new file mode 100644 index 000000000..ca5b27ebc --- /dev/null +++ b/bin/config.d/OpenWRT-One-mikroBUS-LR-IOT-CLICK.yaml @@ -0,0 +1,9 @@ +## https://www.mikroe.com/lr-iot-click +Lora: + Module: lr1110 # OpenWRT ONE mikroBUS with LR-IOT-CLICK +# CS: 25 + IRQ: 10 + Busy: 12 +# Reset: 2 + spidev: spidev2.0 + DIO3_TCXO_VOLTAGE: 1.6 From 44cf6d388ebd9d284e490c150cc568f3199fba0f Mon Sep 17 00:00:00 2001 From: GUVWAF <78759985+GUVWAF@users.noreply.github.com> Date: Sat, 14 Dec 2024 11:55:32 +0100 Subject: [PATCH 101/101] Portduino: fix setting hwId via argument (#5565) --- src/platform/portduino/PortduinoGlue.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/platform/portduino/PortduinoGlue.cpp b/src/platform/portduino/PortduinoGlue.cpp index fa0c8c502..750cc1630 100644 --- a/src/platform/portduino/PortduinoGlue.cpp +++ b/src/platform/portduino/PortduinoGlue.cpp @@ -87,7 +87,8 @@ void getMacAddr(uint8_t *dmac) if (strlen(optionMac) >= 12) { MAC_from_string(optionMac, dmac); } else { - uint32_t hwId = sscanf(optionMac, "%u", &hwId); + uint32_t hwId; + sscanf(optionMac, "%u", &hwId); dmac[0] = 0x80; dmac[1] = 0; dmac[2] = hwId >> 24; @@ -532,4 +533,4 @@ bool MAC_from_string(std::string mac_str, uint8_t *dmac) } else { return false; } -} +} \ No newline at end of file