From 5938cbe6141a97f001ecc620a2e516ad62d1040e Mon Sep 17 00:00:00 2001 From: mikecarper Date: Tue, 25 Aug 2026 18:37:17 -0700 Subject: [PATCH] feat: complete Cascade Indicator companion support Add native-resolution Indicator UI, touch navigation, SD-backed pixel and emoji fonts, LoRa radio support, dual-slot WiFi Companion provisioning, and mesh clock fallback. Harden radio recovery and build defaults, normalize ESP32 setup-AP protocols, and document/test the operator workflows. --- build.sh | 119 +++- docs/WiFi.md | 25 +- docs/cli_build_matrix.md | 9 +- docs/cli_commands.md | 11 +- examples/companion_radio/AbstractUITask.h | 16 +- examples/companion_radio/MyMesh.cpp | 62 +- examples/companion_radio/MyMesh.h | 25 +- examples/companion_radio/main.cpp | 4 +- examples/companion_radio/ui-new/UITask.cpp | 322 +++++++++-- examples/companion_radio/ui-new/UITask.h | 25 +- examples/companion_radio/ui-orig/UITask.cpp | 6 +- examples/companion_radio/ui-orig/UITask.h | 4 +- examples/companion_radio/ui-tiny/UITask.cpp | 6 +- examples/companion_radio/ui-tiny/UITask.h | 4 +- src/Dispatcher.h | 3 + src/helpers/MeshClockSync.cpp | 18 +- src/helpers/WiFiSetupPortal.cpp | 11 +- src/helpers/esp32/ESPNOWRadio.cpp | 4 + src/helpers/esp32/WebConfigServer.cpp | 24 +- src/helpers/ota/OtaTargets.h | 20 +- src/helpers/radiolib/RadioLibWrappers.cpp | 48 +- src/helpers/radiolib/RadioLibWrappers.h | 6 +- .../sensors/EnvironmentSensorManager.cpp | 7 +- src/helpers/ui/ColorEmojiAtlas.h | 123 ++++ src/helpers/ui/DisplayDriver.h | 37 +- src/helpers/ui/EmojiFontMap.h | 178 ++++++ src/helpers/ui/LGFXDisplay.cpp | 541 +++++++++++++++++- src/helpers/ui/LGFXDisplay.h | 50 +- src/helpers/ui/TouchInput.h | 135 +++++ .../test_color_emoji_atlas.cpp | 93 +++ .../test_display_driver.cpp | 83 +++ .../test_emoji_font_map.cpp | 131 +++++ test/test_touch_input/test_touch_input.cpp | 181 ++++++ tools/sensecap_indicator_font/OFL-1.1.txt | 94 +++ tools/sensecap_indicator_font/README.md | 35 ++ .../sensecap_indicator_font/generate_font.py | 459 +++++++++++++++ .../sensecap_indicator_font/requirements.txt | 2 + tools/sensecap_indicator_rp2040/README.md | 33 ++ .../sensecap_indicator_rp2040/platformio.ini | 13 + tools/sensecap_indicator_rp2040/src/main.cpp | 385 +++++++++++++ .../sensecap_indicator_rp2040/upload_font.py | 96 ++++ .../IndicatorFontClient.cpp | 133 +++++ .../IndicatorFontClient.h | 9 + .../IndicatorRadioHal.cpp | 166 ++++++ .../IndicatorRadioHal.h | 52 ++ .../IndicatorSX1262Wrapper.h | 19 + .../IndicatorTouch.h | 91 +++ variants/sensecap_indicator-espnow/README.md | 102 ++++ .../SCIndicatorDisplay.h | 137 ++++- .../dual_ota_2560k_preserve_spiffs.csv | 10 + .../sensecap_indicator-espnow/platformio.ini | 101 +++- .../sensecap_indicator-espnow/sd/ui-font.vlw | Bin 0 -> 1302608 bytes .../sd/ui-font.vlw.json | 37 ++ variants/sensecap_indicator-espnow/target.cpp | 36 +- variants/sensecap_indicator-espnow/target.h | 19 +- 55 files changed, 4185 insertions(+), 175 deletions(-) create mode 100644 src/helpers/ui/ColorEmojiAtlas.h create mode 100644 src/helpers/ui/EmojiFontMap.h create mode 100644 src/helpers/ui/TouchInput.h create mode 100644 test/test_color_emoji_atlas/test_color_emoji_atlas.cpp create mode 100644 test/test_display_driver/test_display_driver.cpp create mode 100644 test/test_emoji_font_map/test_emoji_font_map.cpp create mode 100644 test/test_touch_input/test_touch_input.cpp create mode 100644 tools/sensecap_indicator_font/OFL-1.1.txt create mode 100644 tools/sensecap_indicator_font/README.md create mode 100644 tools/sensecap_indicator_font/generate_font.py create mode 100644 tools/sensecap_indicator_font/requirements.txt create mode 100644 tools/sensecap_indicator_rp2040/README.md create mode 100644 tools/sensecap_indicator_rp2040/platformio.ini create mode 100644 tools/sensecap_indicator_rp2040/src/main.cpp create mode 100644 tools/sensecap_indicator_rp2040/upload_font.py create mode 100644 variants/sensecap_indicator-espnow/IndicatorFontClient.cpp create mode 100644 variants/sensecap_indicator-espnow/IndicatorFontClient.h create mode 100644 variants/sensecap_indicator-espnow/IndicatorRadioHal.cpp create mode 100644 variants/sensecap_indicator-espnow/IndicatorRadioHal.h create mode 100644 variants/sensecap_indicator-espnow/IndicatorSX1262Wrapper.h create mode 100644 variants/sensecap_indicator-espnow/IndicatorTouch.h create mode 100644 variants/sensecap_indicator-espnow/README.md create mode 100644 variants/sensecap_indicator-espnow/dual_ota_2560k_preserve_spiffs.csv create mode 100644 variants/sensecap_indicator-espnow/sd/ui-font.vlw create mode 100644 variants/sensecap_indicator-espnow/sd/ui-font.vlw.json diff --git a/build.sh b/build.sh index 48032e03..a826f6a3 100755 --- a/build.sh +++ b/build.sh @@ -23,12 +23,17 @@ FIRMWARE_FILENAME_INFIX="" ESP32_FULL_BUILD=0 SINGLE_TARGET_FULL_BUILD=0 RADIO_SETTINGS_API_URL="https://api.meshcore.nz/api/v1/config" -RADIO_SETTING_TITLE="" -RADIO_FREQ_OVERRIDE="" -RADIO_BW_OVERRIDE="" -RADIO_SF_OVERRIDE="" -RADIO_CR_OVERRIDE="" -FIRMWARE_PROFILE_OVERRIDE="${FIRMWARE_PROFILE_OVERRIDE:-}" +USA_CASCADIA_RADIO_TITLE="USA Cascadia" +USA_CASCADIA_FALLBACK_FREQ="910.525" +USA_CASCADIA_FALLBACK_BW="62.5" +USA_CASCADIA_FALLBACK_SF="7" +USA_CASCADIA_FALLBACK_CR="5" +RADIO_SETTING_TITLE="$USA_CASCADIA_RADIO_TITLE" +RADIO_FREQ_OVERRIDE="$USA_CASCADIA_FALLBACK_FREQ" +RADIO_BW_OVERRIDE="$USA_CASCADIA_FALLBACK_BW" +RADIO_SF_OVERRIDE="$USA_CASCADIA_FALLBACK_SF" +RADIO_CR_OVERRIDE="$USA_CASCADIA_FALLBACK_CR" +FIRMWARE_PROFILE_OVERRIDE="${FIRMWARE_PROFILE_OVERRIDE:-cascade}" BATCH_BUILD_MODE=0 OPTION3_BUILD_WORKERS="${OPTION3_BUILD_WORKERS:-2}" OPTION3_PIO_JOBS="${OPTION3_PIO_JOBS:-8}" @@ -101,8 +106,8 @@ Commands: Options: --firmware-version : Firmware version to embed. - --radio-preset : Use the numbered radio choice from the interactive menu (1 keeps target defaults). - --profile : Select the firmware settings profile. + --radio-preset : Override the USA Cascadia radio default. Stable names are usa-cascadia and target; legacy menu numbers remain accepted. + --profile : Override the default Cascade firmware settings profile. --skip-kiss|--include-kiss: Exclude (default) or include KISS modem targets in bulk builds. --clean|--resume: Clean output or resume existing Option 3/FULL-only artifacts. @@ -115,6 +120,11 @@ FULL-everything profile for supported ESP32 Option 1 targets, debug options, radio settings, firmware profile, and firmware version $ bash build.sh +Builds default to the live USA/Canada preset by name and the Cascade firmware +profile. If the preset service is offline, the radio fallback is 910.525 MHz / +BW62.5 / SF7 / CR5. To intentionally use a target's own defaults instead: +$ bash build.sh build-firmware RAK_4631_repeater --radio-preset target --profile default + Build all firmwares for device targets containing the string "RAK_4631" $ bash build.sh build-matching-firmwares @@ -672,11 +682,23 @@ clear_firmware_profile_overrides() { apply_cli_radio_preset() { local selection=$1 - local preset_output row + local preset_output row title description freq bw sf cr local -a preset_rows=() + case "${selection,,}" in + usa|usa-canada|usa-cascadia|cascadia) + resolve_usa_cascadia_radio_default + return 0 + ;; + default|target|target-defaults) + clear_radio_overrides + echo "Using target default radio settings." + return 0 + ;; + esac + if ! [[ "$selection" =~ ^[0-9]+$ ]] || [ "$selection" -lt 1 ]; then - echo "Invalid --radio-preset value: ${selection}" + echo "Invalid --radio-preset value: ${selection} (use usa-cascadia, target, or a legacy menu number)" return 1 fi clear_radio_overrides @@ -698,7 +720,7 @@ apply_cli_radio_preset() { row=${preset_rows[$((selection - 2))]} IFS=$'\t' read -r title description freq bw sf cr <<< "$row" set_radio_overrides "$title" "$freq" "$bw" "$sf" "$cr" - echo "Using radio setting ${selection}: ${RADIO_SETTING_TITLE} (${RADIO_FREQ_OVERRIDE}MHz / SF${RADIO_SF_OVERRIDE} / BW${RADIO_BW_OVERRIDE} / CR${RADIO_CR_OVERRIDE})" + echo "Using legacy numbered radio setting ${selection}: ${RADIO_SETTING_TITLE} (${RADIO_FREQ_OVERRIDE}MHz / SF${RADIO_SF_OVERRIDE} / BW${RADIO_BW_OVERRIDE} / CR${RADIO_CR_OVERRIDE})" } parse_cli_options() { @@ -819,6 +841,43 @@ for entry in entries: PY } +is_usa_cascadia_radio_title() { + local title=${1,,} + + [[ "$title" == usa*canada* ]] +} + +set_usa_cascadia_radio_fallback() { + set_radio_overrides \ + "$USA_CASCADIA_RADIO_TITLE" \ + "$USA_CASCADIA_FALLBACK_FREQ" \ + "$USA_CASCADIA_FALLBACK_BW" \ + "$USA_CASCADIA_FALLBACK_SF" \ + "$USA_CASCADIA_FALLBACK_CR" +} + +resolve_usa_cascadia_radio_default() { + local preset_output row title description freq bw sf cr + + set_usa_cascadia_radio_fallback + if ! preset_output=$(fetch_suggested_radio_settings) || [ -z "$preset_output" ]; then + echo "USA Cascadia preset lookup unavailable; using offline fallback (${RADIO_FREQ_OVERRIDE}MHz / SF${RADIO_SF_OVERRIDE} / BW${RADIO_BW_OVERRIDE} / CR${RADIO_CR_OVERRIDE})." + return 0 + fi + + while IFS= read -r row; do + [ -n "$row" ] || continue + IFS=$'\t' read -r title description freq bw sf cr <<< "$row" + if is_usa_cascadia_radio_title "$title"; then + set_radio_overrides "$USA_CASCADIA_RADIO_TITLE" "$freq" "$bw" "$sf" "$cr" + echo "Resolved USA Cascadia by preset name '${title}': ${RADIO_FREQ_OVERRIDE}MHz / SF${RADIO_SF_OVERRIDE} / BW${RADIO_BW_OVERRIDE} / CR${RADIO_CR_OVERRIDE}." + return 0 + fi + done <<< "$preset_output" + + echo "USA/Canada preset not found; using offline USA Cascadia fallback (${RADIO_FREQ_OVERRIDE}MHz / SF${RADIO_SF_OVERRIDE} / BW${RADIO_BW_OVERRIDE} / CR${RADIO_CR_OVERRIDE})." +} + is_valid_custom_radio_bandwidth() { python3 - "$1" <<'PY' import sys @@ -883,7 +942,15 @@ prompt_for_custom_radio_setting() { prompt_for_radio_build_settings() { local -a preset_rows=() local -a fetched_preset_rows=() - local -a options=("Keep target defaults (no radio override)") + local default_title=$RADIO_SETTING_TITLE + local default_freq=$RADIO_FREQ_OVERRIDE + local default_bw=$RADIO_BW_OVERRIDE + local default_sf=$RADIO_SF_OVERRIDE + local default_cr=$RADIO_CR_OVERRIDE + local -a options=( + "USA Cascadia (default): ${default_freq} MHz / SF${default_sf} / BW${default_bw} / CR${default_cr}" + "Keep target defaults (no radio override)" + ) local row local title local description @@ -896,8 +963,6 @@ prompt_for_radio_build_settings() { local custom_index local preset_output - clear_radio_overrides - if preset_output=$(fetch_suggested_radio_settings); then if [ -n "$preset_output" ]; then mapfile -t fetched_preset_rows <<< "$preset_output" @@ -906,6 +971,10 @@ prompt_for_radio_build_settings() { if [ -z "$row" ]; then continue fi + IFS=$'\t' read -r title description freq bw sf cr <<< "$row" + if is_usa_cascadia_radio_title "$title"; then + continue + fi preset_rows+=("$row") done else @@ -934,6 +1003,13 @@ prompt_for_radio_build_settings() { choice_index=$MENU_CHOICE if [ "$choice_index" -eq 1 ]; then + set_radio_overrides "$default_title" "$default_freq" "$default_bw" "$default_sf" "$default_cr" + echo "Using radio setting: ${RADIO_SETTING_TITLE} (${RADIO_FREQ_OVERRIDE}MHz / SF${RADIO_SF_OVERRIDE} / BW${RADIO_BW_OVERRIDE} / CR${RADIO_CR_OVERRIDE})" + return 0 + fi + + if [ "$choice_index" -eq 2 ]; then + clear_radio_overrides echo "Using target default radio settings." return 0 fi @@ -944,7 +1020,7 @@ prompt_for_radio_build_settings() { return 0 fi - preset_index=$((choice_index - 2)) + preset_index=$((choice_index - 3)) if [ "$preset_index" -ge 0 ] && [ "$preset_index" -lt "${#preset_rows[@]}" ]; then IFS=$'\t' read -r title description freq bw sf cr <<< "${preset_rows[$preset_index]}" set_radio_overrides "$title" "$freq" "$bw" "$sf" "$cr" @@ -956,12 +1032,10 @@ prompt_for_radio_build_settings() { prompt_for_firmware_profile_settings() { local -a options=( + "Cascade (default): power saving + RXPS on / WiFi power save=min / path.hash.mode=2 / loop.detect=minimal / cad=on / rxdelay=2 / agc.reset.interval=8 / advert.interval=0 / flood.advert.interval=83 / multi.acks=1 / companion.manual.add=1 / companion.autoadd=0" "Keep target defaults" - "Cascade: power saving + RXPS on / WiFi power save=min / path.hash.mode=2 / loop.detect=minimal / cad=on / rxdelay=2 / agc.reset.interval=8 / advert.interval=0 / flood.advert.interval=83 / multi.acks=1 / companion.manual.add=1 / companion.autoadd=0" ) - clear_firmware_profile_overrides - echo "Set firmware profile options:" while true; do print_numbered_menu "${options[@]}" @@ -973,12 +1047,13 @@ prompt_for_firmware_profile_settings() { case "$MENU_CHOICE" in 1) - echo "Using target default firmware profile settings." + set_firmware_profile_override "cascade" + echo "Using firmware profile: Cascade" return 0 ;; 2) - set_firmware_profile_override "cascade" - echo "Using firmware profile: Cascade" + clear_firmware_profile_overrides + echo "Using target default firmware profile settings." return 0 ;; esac @@ -4092,6 +4167,8 @@ main() { if ! apply_cli_radio_preset "$RADIO_PRESET_SELECTION"; then exit 1 fi + else + resolve_usa_cascadia_radio_default fi if [ $# -eq 0 ]; then diff --git a/docs/WiFi.md b/docs/WiFi.md index ed3062a6..088b76cc 100644 --- a/docs/WiFi.md +++ b/docs/WiFi.md @@ -419,6 +419,16 @@ receives their final reply. into a selected target; it does not change that target into another firmware role. +This fork defaults every `build.sh` target to the USA Cascadia radio preset and +the Cascade firmware profile. The script resolves the live `USA/Canada` entry +by name, so its changing number in the downloaded menu does not affect builds. +If the preset service is unavailable, it falls back to +`910.525 MHz / BW62.5 / SF7 / CR5`. Use +`--radio-preset target --profile default` only when a build intentionally needs +the target's original radio and profile defaults. `--radio-preset usa-cascadia` +is the stable explicit name; legacy numbered choices remain accepted but their +meaning can change when the service reorders or adds presets. + | Build profile | WiFi/MQTT behavior | |---|---| | Standard | Uses the selected target's role. Ordinary legacy-slot ESP32 repeater/room-server artifacts omit WebConfig when needed to fit. ESP32 MQTT observer and ESP-NOW bridge targets are automatically promoted to FULL; WiFi-companion targets keep their companion partition profile. | @@ -461,7 +471,7 @@ Fresh Cascade-profile builds default to `min`; target-default builds use highest power use. `min` and `max` reduce power but may add latency or reduce reliability on busy nodes. A saved operator setting takes precedence on an upgrade. ESP32 WiFi Companions expose the same values in their WebConfig WiFi -card. Full Companion also accepts the text commands from its USB terminal and +card and USB text terminal. Full Companion also accepts the text commands from TCP port 5002. The normal binary Companion protocol can read or write the setting over USB, BLE, or TCP port 5000 without entering terminal mode. Full Companion rejects `none` because its simultaneous BLE transport requires WiFi @@ -475,9 +485,9 @@ WiFi only, not LoRa transmit power. `get wifi.status`, `get wifi.ssid`, `get wifi.powersave`, and `get wifi.cli` are available on MQTT observers and on FULL non-MQTT repeater/room-server -builds with WebConfig. ESP32 WiFi Companions expose `wifi.powersave` through -their role-specific interfaces described above; they do not expose the full -infrastructure WiFi CLI family. +builds with WebConfig. ESP32 WiFi Companions with WebConfig expose those +commands, credential setters, and `start webconfig [ap]` through their USB text +terminal; Full Companion additionally exposes that terminal on TCP port 5002. MQTT commands such as `get mqtt.status` and `set mqtt1.preset ...` still require an MQTT observer target. Unknown settings return `Error: unknown setting: `. Older firmware that used the discontinued compact CLI can instead @@ -518,5 +528,8 @@ Common causes are: - the wrong firmware role or an older compact-CLI build without WebConfig. For a WiFi companion, find its station IP in the router, connect the client to -TCP port 5000, and use the setup AP if it cannot join the saved network. MQTT -diagnostics apply only to a `wifi_mqtt` companion target. +TCP port 5000, and use the open `MeshCore-Setup-XXXX` AP at +`http://192.168.4.1/` if it cannot join the saved network. Current firmware +normalizes both ESP32 WiFi interfaces to standard b/g/n before advertising the +setup AP, including after an ESP-NOW image used its long-range protocol mode. +MQTT diagnostics apply only to a `wifi_mqtt` companion target. diff --git a/docs/cli_build_matrix.md b/docs/cli_build_matrix.md index 5c9013f0..9307c1ab 100644 --- a/docs/cli_build_matrix.md +++ b/docs/cli_build_matrix.md @@ -126,10 +126,11 @@ does not exist on that target: - WebConfig and the `wifi.ssid`, `wifi.status`, `wifi.powersave`, and `wifi.cli` command family require an ESP32 WebConfig build. FULL standalone repeater and room-server builds support the corresponding WiFi setters and status - commands. ESP32 WiFi Companion exposes `wifi.powersave` in its WebConfig - form and binary protocol; Full Companion exposes its complete role-specific - text terminal over USB and TCP port 5002, including WiFi credentials, - connection status, WebConfig, CLI-tab, and power-save controls. + commands. ESP32 WiFi Companions with WebConfig expose WiFi credentials, + connection status, WebConfig, CLI-tab, and power-save controls from their USB + text terminal as well as power saving through WebConfig and the binary + protocol. Full Companion additionally exposes its complete role-specific + text terminal on TCP port 5002. - MQTT commands require an MQTT observer target. - `discover.scopes` requires an MQTT observer with compiled neighbor support; it does not independently require PSRAM or the FULL parser. diff --git a/docs/cli_commands.md b/docs/cli_commands.md index 15b6a232..961a9fda 100644 --- a/docs/cli_commands.md +++ b/docs/cli_commands.md @@ -252,11 +252,12 @@ take effect on the next connection. `get wifi.pwd` is intentionally unavailable so the standalone password is never returned by the CLI. ESP32 WiFi Companion WebConfig exposes the same `wifi.powersave` values in its -WiFi card. Full Companion exposes the same role-specific text terminal over -USB and TCP port 5002, including the standalone `wifi.ssid`, `wifi.status`, -`wifi.powersave`, `wifi.cli`, and WebConfig command families. Credential -writes reply before restarting the WiFi station, so a TCP client should expect -to reconnect at the new address; USB password input is masked. Binary +WiFi card. Every ESP32 WiFi Companion with WebConfig exposes the standalone +`wifi.ssid`, `wifi.status`, `wifi.powersave`, `wifi.cli`, and WebConfig command +families through its USB text terminal. Full Companion exposes the same +role-specific terminal on TCP port 5002. Credential writes reply before +restarting the WiFi station, so a TCP client should expect to reconnect at the +new address; USB password input is masked. Binary Companion clients can use command bytes `0x46` and `0x47` over USB, BLE, or TCP port 5000 without the terminal-start token. WiFi-only Companions accept all three modes; Full Companion rejects diff --git a/examples/companion_radio/AbstractUITask.h b/examples/companion_radio/AbstractUITask.h index fe158628..415b41a8 100644 --- a/examples/companion_radio/AbstractUITask.h +++ b/examples/companion_radio/AbstractUITask.h @@ -13,6 +13,10 @@ #include "NodePrefs.h" +#ifndef UI_USB_AUTO_OFF_MULTIPLIER + #define UI_USB_AUTO_OFF_MULTIPLIER 5UL +#endif + enum class UIEventType { none, contactMessage, @@ -35,11 +39,14 @@ protected: bool isDisplayAutoOffDue(unsigned long configured_deadline, unsigned long configured_timeout_millis) const { unsigned long deadline = configured_deadline; +#if UI_USB_AUTO_OFF_MULTIPLIER > 1 if (_board->isUsbHostConnected()) { // The configured deadline already includes the first timeout period. - // Add four more periods for a total of 5x while attached to a computer. - deadline += configured_timeout_millis * 4UL; + // Add the remaining periods while attached to a computer. + deadline += configured_timeout_millis + * (UI_USB_AUTO_OFF_MULTIPLIER - 1UL); } +#endif return static_cast(millis() - deadline) > 0; } @@ -59,7 +66,10 @@ public: void enableBluetooth() { _interfaceManager->enableBluetooth(); } void disableBluetooth() { _interfaceManager->disableBluetooth(); } virtual void msgRead(int msgcount) = 0; - virtual void newMsg(uint8_t path_len, const char* from_name, const char* text, int msgcount) = 0; + virtual void newMsg(uint8_t path_len, const char* from_name, + const char* text, int msgcount, + int channel_idx = -1, + const char* channel_name = nullptr) = 0; virtual void notify(UIEventType t = UIEventType::none) = 0; virtual void loop() = 0; }; diff --git a/examples/companion_radio/MyMesh.cpp b/examples/companion_radio/MyMesh.cpp index b7a44c37..88354562 100644 --- a/examples/companion_radio/MyMesh.cpp +++ b/examples/companion_radio/MyMesh.cpp @@ -847,9 +847,26 @@ bool MyMesh::filterRecvFloodPacket(mesh::Packet* packet) { } bool MyMesh::allowPacketForward(const mesh::Packet* packet) { - return _prefs.isRepeatEn(); + if (!_prefs.isRepeatEn()) return false; +#ifdef COMPANION_MESH_CLOCK_SYNC + _clock_sync.observeAcceptedFlood(packet); +#endif + return true; } +#ifdef COMPANION_MESH_CLOCK_SYNC +void MyMesh::onAdvertRecv(mesh::Packet* packet, const mesh::Identity& id, + uint32_t timestamp, const uint8_t* app_data, + size_t app_data_len) { + BaseChatMesh::onAdvertRecv(packet, id, timestamp, app_data, app_data_len); + _clock_sync.observeVerifiedAdvert(packet, id, timestamp); +} + +void MyMesh::onGroupPacketRecv(mesh::Packet* packet) { + _clock_sync.observeGroupPacket(packet); +} +#endif + bool MyMesh::allowFloodRetry(const mesh::Packet* packet) const { if (packet == NULL) return false; // A companion may retry its own advert once, using the core's deliberately @@ -982,7 +999,13 @@ void MyMesh::onChannelMessageRecv(const mesh::GroupChannel &channel, mesh::Packe if (getChannel(channel_idx, channel_details)) { channel_name = channel_details.name; } - if (_ui) _ui->newMsg(path_len, channel_name, text, offline_queue_len); + char channel_label[64]; + snprintf(channel_label, sizeof(channel_label), "Ch %u %s", + (unsigned int)channel_idx, channel_name); + if (_ui) { + _ui->newMsg(path_len, channel_label, text, offline_queue_len, + channel_idx, channel_name); + } #endif if (pkt->isRouteFlood() && is_emergency_channel) { @@ -1357,6 +1380,10 @@ void MyMesh::onSendTimeout() { MyMesh::MyMesh(mesh::Radio &radio, mesh::RNG &rng, mesh::RTCClock &rtc, SimpleMeshTables &tables, DataStore& store, AbstractUITask* ui) : BaseChatMesh(radio, *new ArduinoMillis(), rng, rtc, *new StaticPoolPacketManager(16), tables), +#ifdef COMPANION_MESH_CLOCK_SYNC + _clock_sync(radio, _clock_sync_millis, rtc, _clock_sync_acl, sensors, + _prefs.airtime_factor), +#endif _serial(NULL), telemetry(MAX_PACKET_PAYLOAD - 4), _store(&store), _ui(ui), _iter(0) { _iter_started = false; _cli_rescue = false; @@ -1606,6 +1633,12 @@ void MyMesh::begin(bool has_display, bool radio_available) { _store->saveChannels(this); } +#ifdef COMPANION_MESH_CLOCK_SYNC + // Fixed fallback policy for this Companion build. A successful host time + // update below suppresses mesh correction for the remainder of the boot. + _clock_sync.begin(nullptr); +#endif + configureRadioFromPrefs(); #if defined(WITH_MQTT_BRIDGE) && defined(ESP32_PLATFORM) && defined(WIFI_SSID) @@ -1808,9 +1841,10 @@ void MyMesh::scheduleNormalRadio(char* reply, size_t reply_size) { _temp_radio_failures = 0; snprintf(reply, reply_size, "OK - normal radio restore scheduled"); } +#endif -bool MyMesh::handleFullOtaCommand(const char* command, char* reply, - size_t reply_size) { +bool MyMesh::handleLocalControlCommand(const char* command, char* reply, + size_t reply_size) { if (!command || !reply || reply_size == 0) return false; while (*command == ' ') command++; @@ -1971,6 +2005,7 @@ bool MyMesh::handleFullOtaCommand(const char* command, char* reply, } #endif +#if defined(COMPANION_RADIO_FULL) if (strcmp(command, "tempradio") == 0) { if (_temp_radio_set_at) { snprintf(reply, reply_size, "TempRadio pending: %.3f,%.2f,%u,%u", @@ -2021,10 +2056,12 @@ bool MyMesh::handleFullOtaCommand(const char* command, char* reply, snprintf(reply, reply_size, "%s", ota_reply); return true; } +#endif return false; } +#if defined(COMPANION_RADIO_FULL) void MyMesh::serviceTempRadio() { const unsigned long now = _ms->getMillis(); const bool retry_ready = !_temp_radio_retry_at @@ -2964,6 +3001,9 @@ void MyMesh::handleCmdFrame(size_t len) { uint32_t curr = getRTCClock()->getCurrentTime(); if (secs >= curr) { getRTCClock()->setCurrentTime(secs); +#ifdef COMPANION_MESH_CLOCK_SYNC + _clock_sync.onManualClockSet(); +#endif writeOKFrame(); } else { writeErrFrame(ERR_CODE_ILLEGAL_ARG); @@ -4753,13 +4793,11 @@ void MyMesh::handleTerminalCommand(char* command) { if (*command == 0) return; mesh::cli::normalizeCommandVerb(command); -#if defined(COMPANION_RADIO_FULL) - char full_reply[160]; - if (handleFullOtaCommand(command, full_reply, sizeof(full_reply))) { - terminalOutput().printf(" %s\r\n", full_reply); + char local_reply[160]; + if (handleLocalControlCommand(command, local_reply, sizeof(local_reply))) { + terminalOutput().printf(" %s\r\n", local_reply); return; } -#endif mesh::cli::TerminalChannelMessage channel_message; const mesh::cli::TerminalChannelCommandMatch channel_match = @@ -4869,6 +4907,9 @@ void MyMesh::handleTerminalCommand(char* command) { uint32_t current = getRTCClock()->getCurrentTime(); if (timestamp >= current) { getRTCClock()->setCurrentTime(timestamp); +#ifdef COMPANION_MESH_CLOCK_SYNC + _clock_sync.onManualClockSet(); +#endif terminalOutput().print(" OK - clock set\r\n"); } else { terminalOutput().print(" ERROR: clock cannot go backwards\r\n"); @@ -5518,6 +5559,9 @@ void MyMesh::loop() { serviceTempRadio(); #endif BaseChatMesh::loop(); +#ifdef COMPANION_MESH_CLOCK_SYNC + _clock_sync.loop(); +#endif #ifdef ENABLE_USB_INTERFACE serviceTerminalLogin(); serviceTerminalCommand(); diff --git a/examples/companion_radio/MyMesh.h b/examples/companion_radio/MyMesh.h index 7a98e91d..b895a311 100644 --- a/examples/companion_radio/MyMesh.h +++ b/examples/companion_radio/MyMesh.h @@ -47,6 +47,11 @@ #include #include +#ifdef COMPANION_MESH_CLOCK_SYNC +#include +#include +#endif + /* ---------------------------------- CONFIGURATION ------------------------------------- */ #ifndef LORA_FREQ @@ -171,11 +176,10 @@ public: #endif #endif -#if defined(COMPANION_RADIO_FULL) - // Local-only control surface shared by the USB terminal and WiFi port 5002. - // Supports bounded TempRadio windows plus the serve-only `ota ...` CLI. - bool handleFullOtaCommand(const char* command, char* reply, size_t reply_size); -#endif + // Local control shared by every USB terminal. ESP32 WiFi companions expose + // setup/status commands here; Full builds add TempRadio and OTA commands. + bool handleLocalControlCommand(const char* command, char* reply, + size_t reply_size); int getRecentlyHeard(AdvertPath dest[], int max_num); @@ -200,6 +204,12 @@ protected: bool filterRecvFloodPacket(mesh::Packet* packet) override; bool allowPacketForward(const mesh::Packet* packet) override; bool allowFloodRetry(const mesh::Packet* packet) const override; +#ifdef COMPANION_MESH_CLOCK_SYNC + void onAdvertRecv(mesh::Packet* packet, const mesh::Identity& id, + uint32_t timestamp, const uint8_t* app_data, + size_t app_data_len) override; + void onGroupPacketRecv(mesh::Packet* packet) override; +#endif bool sendFloodScoped(const TransportKey& scope, mesh::Packet* pkt, uint32_t delay_millis); bool sendFloodScoped(const ContactInfo& recipient, mesh::Packet* pkt, uint32_t delay_millis=0) override; @@ -362,6 +372,11 @@ private: DataStore* _store; CompanionNodePrefs _prefs; +#ifdef COMPANION_MESH_CLOCK_SYNC + ArduinoMillis _clock_sync_millis; + ClientACL _clock_sync_acl; + mesh::MeshClockSync _clock_sync; +#endif #if defined(WITH_MQTT_BRIDGE) && defined(ESP32_PLATFORM) && defined(WIFI_SSID) MQTTPrefs _mqtt_prefs; MQTTBridge* _mqtt_bridge; diff --git a/examples/companion_radio/main.cpp b/examples/companion_radio/main.cpp index 9f537376..a697bc04 100644 --- a/examples/companion_radio/main.cpp +++ b/examples/companion_radio/main.cpp @@ -370,7 +370,7 @@ static void resetUsbMotaMode() { static void leaveUsbMotaMode(bool acknowledge) { char reply[160] = {0}; - the_mesh.handleFullOtaCommand("ota folder off", reply, sizeof(reply)); + the_mesh.handleLocalControlCommand("ota folder off", reply, sizeof(reply)); if (acknowledge) { Serial.print("\r\n"); Serial.print(reply); @@ -388,7 +388,7 @@ static void enterUsbMotaMode() { usb_mota_disconnect_armed = isUsbTerminalDataConnected(); char reply[160] = {0}; - if (!the_mesh.handleFullOtaCommand("ota folder on", reply, sizeof(reply)) + if (!the_mesh.handleLocalControlCommand("ota folder on", reply, sizeof(reply)) || strncmp(reply, "ERR", 3) == 0) { Serial.print("\r\n"); Serial.print(reply[0] ? reply : "ERR could not enter mOTA seeder mode"); diff --git a/examples/companion_radio/ui-new/UITask.cpp b/examples/companion_radio/ui-new/UITask.cpp index bf78fbbf..407b7072 100644 --- a/examples/companion_radio/ui-new/UITask.cpp +++ b/examples/companion_radio/ui-new/UITask.cpp @@ -18,6 +18,9 @@ #ifndef USB_MESSAGE_PREVIEW_MILLIS #define USB_MESSAGE_PREVIEW_MILLIS 15000UL #endif +#ifndef UI_RADIO_REFRESH_MILLIS + #define UI_RADIO_REFRESH_MILLIS 2000UL +#endif #ifndef BLE_PAIRING_DISPLAY_MILLIS #define BLE_PAIRING_DISPLAY_MILLIS 120000UL #endif @@ -126,7 +129,7 @@ class HomeScreen : public UIScreen { AdvertPath recent[UI_RECENT_LIST_SIZE]; - void renderBatteryIndicator(DisplayDriver& display, uint16_t batteryMilliVolts) { + int renderBatteryIndicator(DisplayDriver& display, uint16_t batteryMilliVolts) { // Convert millivolts to percentage #ifndef BATT_MIN_MILLIVOLTS #define BATT_MIN_MILLIVOLTS 3000 @@ -136,14 +139,19 @@ class HomeScreen : public UIScreen { #endif const int minMilliVolts = BATT_MIN_MILLIVOLTS; const int maxMilliVolts = BATT_MAX_MILLIVOLTS; - int batteryPercentage = ((batteryMilliVolts - minMilliVolts) * 100) / (maxMilliVolts - minMilliVolts); + const bool showBattery = batteryMilliVolts != 0; + int batteryPercentage = showBattery + ? ((batteryMilliVolts - minMilliVolts) * 100) / (maxMilliVolts - minMilliVolts) + : 0; if (batteryPercentage < 0) batteryPercentage = 0; // Clamp to 0% if (batteryPercentage > 100) batteryPercentage = 100; // Clamp to 100% // battery icon int iconWidth = 24; int iconHeight = 10; - int iconX = display.width() - iconWidth - 5; // Position the icon near the top-right corner + int iconX = showBattery + ? display.width() - iconWidth - 5 + : display.width() - 5; int iconY = 0; display.setColor(UIColor::title_txt); @@ -178,25 +186,28 @@ class HomeScreen : public UIScreen { #ifdef PIN_BUZZER if (muted) statusWidth += 9; #endif - display.setCursor(iconX - statusWidth - uptimeWidth - spaceWidth, iconY); + int statusStartX = iconX - statusWidth - uptimeWidth - spaceWidth; + display.setCursor(statusStartX, iconY); display.print(uptime); - // battery outline - display.drawRect(iconX, iconY, iconWidth, iconHeight); + if (showBattery) { + // battery outline + display.drawRect(iconX, iconY, iconWidth, iconHeight); - // battery "cap" - display.fillRect(iconX + iconWidth, iconY + (iconHeight / 4), 3, iconHeight / 2); + // battery "cap" + display.fillRect(iconX + iconWidth, iconY + (iconHeight / 4), 3, iconHeight / 2); - // fill the battery based on the percentage - int fillWidth = (batteryPercentage * (iconWidth - 4)) / 100; - display.fillRect(iconX + 2, iconY + 2, fillWidth, iconHeight - 4); + // fill the battery based on the percentage + int fillWidth = (batteryPercentage * (iconWidth - 4)) / 100; + display.fillRect(iconX + 2, iconY + 2, fillWidth, iconHeight - 4); + } // Show external power beside the battery. Most boards have no // charge-complete signal, so use a high percentage band for the plug. if (charging) { static constexpr int BATT_FULL_PCT = 95; const uint8_t* symbol = - batteryPercentage >= BATT_FULL_PCT ? plug_icon : charging_icon; + !showBattery || batteryPercentage >= BATT_FULL_PCT ? plug_icon : charging_icon; display.setColor(UIColor::title_txt); display.drawXbm(iconX - 9, iconY + 1, symbol, 8, 8); } @@ -208,6 +219,8 @@ class HomeScreen : public UIScreen { display.drawXbm(iconX - (charging ? 18 : 9), iconY + 1, muted_icon, 8, 8); } #endif + + return statusStartX; } CayenneLPP sensors_lpp; @@ -255,16 +268,18 @@ public: display.setColor(UIColor::title_bkg); display.fillRect(0, 0, display.width(), 12); char tmp[80]; - // node name + // status indicators display.setTextSize(1); display.setColor(UIColor::title_txt); + int statusStartX = renderBatteryIndicator(display, _task->getBattMilliVolts()); + + // node name char filtered_name[sizeof(_node_prefs->node_name)]; display.translateUTF8ToBlocks(filtered_name, _node_prefs->node_name, sizeof(filtered_name)); - display.setCursor(0, 2); - display.print(filtered_name); - - // battery voltage - renderBatteryIndicator(display, _task->getBattMilliVolts()); + int availableNameWidth = statusStartX - 2; + if (availableNameWidth > 0) { + display.drawTextEllipsized(0, 2, availableNameWidth, filtered_name); + } // curr page indicator if (UIColor::title_bkg == UIColor::window_bkg) { @@ -285,8 +300,12 @@ public: if (_page == HomePage::FIRST) { display.setColor(UIColor::primary_txt); display.setTextSize(2); - sprintf(tmp, "MSG: %d", _task->getMsgCount()); + sprintf(tmp, "INBOX: %d", _task->getPreviewCount()); display.drawTextCentered(display.width() / 2, 22, tmp); + display.setTextSize(1); + display.setColor(UIColor::secondary_txt); + display.drawTextCentered(display.width() / 2, 43, + "tap center: inbox"); #ifdef UI_SHOW_CLOCK display.setTextSize(3); @@ -371,7 +390,12 @@ public: sprintf(tmp, "TX: %ddBm", _node_prefs->tx_power_dbm); display.print(tmp); display.setCursor(0, 53); - sprintf(tmp, "Noise floor: %d", radio_driver.getNoiseFloor()); + float noise_floor = radio_driver.getNoiseFloorDbm(); + if (noise_floor == 0.0f) { + strcpy(tmp, "Noise floor: measuring"); + } else { + snprintf(tmp, sizeof(tmp), "Noise floor: %.1f", noise_floor); + } display.print(tmp); } else if (_page == HomePage::BLUETOOTH) { display.setColor(UIColor::corp_blue); @@ -522,7 +546,7 @@ public: } #endif } - return 5000; // next render after 5000 ms + return _page == HomePage::RADIO ? UI_RADIO_REFRESH_MILLIS : 5000; } bool handleInput(char c) override { @@ -545,6 +569,10 @@ public: } return true; } + if (c == KEY_ENTER && _page == HomePage::FIRST) { + _task->showMessages(); + return true; + } if (c == KEY_ENTER && _page == HomePage::ADVERT) { _task->notify(UIEventType::ack); if (the_mesh.advert()) { @@ -585,42 +613,184 @@ class MsgPreviewScreen : public UIScreen { UITask* _task; mesh::RTCClock* _rtc; + static constexpr int CHANNEL_FILTER_ALL = -2; + static constexpr int CHANNEL_FILTER_DIRECT = -1; + struct MsgEntry { uint32_t timestamp; + int channel_idx; + char channel_name[32]; char origin[62]; char msg[UI_MSG_PREVIEW_SIZE]; }; #define MAX_UNREAD_MSGS 32 int num_unread; + int view_offset; + int channel_filter; int head = MAX_UNREAD_MSGS - 1; // index of latest unread message MsgEntry unread[MAX_UNREAD_MSGS]; -public: - MsgPreviewScreen(UITask* task, mesh::RTCClock* rtc) : _task(task), _rtc(rtc) { num_unread = 0; } + bool matchesFilter(const MsgEntry& entry) const { + return channel_filter == CHANNEL_FILTER_ALL + || entry.channel_idx == channel_filter; + } - void addPreview(uint8_t path_len, const char* from_name, const char* msg) { + int filteredCount() const { + int count = 0; + for (int age = 0; age < num_unread; ++age) { + int index = (head + MAX_UNREAD_MSGS - age) % MAX_UNREAD_MSGS; + if (matchesFilter(unread[index])) ++count; + } + return count; + } + + const MsgEntry* filteredEntry(int offset) const { + int match = 0; + for (int age = 0; age < num_unread; ++age) { + int index = (head + MAX_UNREAD_MSGS - age) % MAX_UNREAD_MSGS; + if (!matchesFilter(unread[index])) continue; + if (match++ == offset) return &unread[index]; + } + return nullptr; + } + + int buildChannelFilters(int* filters, int capacity) const { + int count = 0; + if (count < capacity) filters[count++] = CHANNEL_FILTER_ALL; + for (int channel_idx = 0; + channel_idx < MAX_GROUP_CHANNELS && count < capacity; + ++channel_idx) { + ChannelDetails details; + if (the_mesh.getChannel(channel_idx, details) + && details.name[0] != 0) { + filters[count++] = channel_idx; + } + } + if (count < capacity) filters[count++] = CHANNEL_FILTER_DIRECT; + return count; + } + + void cycleChannelFilter(int direction) { + int filters[MAX_GROUP_CHANNELS + 2]; + int count = buildChannelFilters( + filters, sizeof(filters) / sizeof(filters[0])); + if (count == 0) return; + + int selected = 0; + while (selected < count && filters[selected] != channel_filter) { + ++selected; + } + if (selected == count) selected = 0; + selected = (selected + direction + count) % count; + channel_filter = filters[selected]; + view_offset = 0; + } + + void channelFilterLabel(char* label, size_t size) const { + if (channel_filter == CHANNEL_FILTER_ALL) { + StrHelper::strncpy(label, "All channels", size); + return; + } + if (channel_filter == CHANNEL_FILTER_DIRECT) { + StrHelper::strncpy(label, "Direct", size); + return; + } + + ChannelDetails details; + if (the_mesh.getChannel(channel_filter, details) + && details.name[0] != 0) { + snprintf(label, size, "Ch %d %s", channel_filter, details.name); + return; + } + for (int age = 0; age < num_unread; ++age) { + int index = (head + MAX_UNREAD_MSGS - age) % MAX_UNREAD_MSGS; + if (unread[index].channel_idx == channel_filter + && unread[index].channel_name[0] != 0) { + snprintf(label, size, "Ch %d %s", channel_filter, + unread[index].channel_name); + return; + } + } + snprintf(label, size, "Ch %d", channel_filter); + } + + void renderChannelFilter(DisplayDriver& display) const { + const int bar_height = 24; + const int bar_y = display.height() - bar_height; + display.setColor(UIColor::window_bkg); + display.fillRect(0, bar_y, display.width(), bar_height); + display.setColor(UIColor::corp_blue); + display.drawRect(0, bar_y, display.width(), 1); + + char channel[48]; + channelFilterLabel(channel, sizeof(channel)); + display.setTextSize(1); + const int text_y = bar_y + 8; + display.setCursor(8, text_y); + display.print("<"); + display.drawTextCentered(display.width() / 2, text_y, channel); + display.setCursor(display.width() - display.getTextWidth(">") - 8, + text_y); + display.print(">"); + } + +public: + MsgPreviewScreen(UITask* task, mesh::RTCClock* rtc) + : _task(task), _rtc(rtc), num_unread(0), view_offset(0), + channel_filter(CHANNEL_FILTER_ALL) {} + + bool hasMessages() const { return num_unread > 0; } + int messageCount() const { return num_unread; } + + void clear() { + num_unread = 0; + view_offset = 0; + channel_filter = CHANNEL_FILTER_ALL; + } + + void addPreview(uint8_t path_len, const char* from_name, const char* msg, + int channel_idx, const char* channel_name) { head = (head + 1) % MAX_UNREAD_MSGS; if (num_unread < MAX_UNREAD_MSGS) num_unread++; + view_offset = 0; + channel_filter = channel_idx; auto p = &unread[head]; p->timestamp = _rtc->getCurrentTime(); + p->channel_idx = channel_idx; + StrHelper::strncpy(p->channel_name, + channel_name == nullptr ? "" : channel_name, + sizeof(p->channel_name)); if (path_len == 0xFF) { - sprintf(p->origin, "(D) %s:", from_name); + snprintf(p->origin, sizeof(p->origin), "%s [direct]:", from_name); } else { - sprintf(p->origin, "(%d) %s:", (uint32_t) path_len, from_name); + snprintf(p->origin, sizeof(p->origin), "%s [%uh]:", from_name, + (unsigned int)path_len); } StrHelper::strncpy(p->msg, msg, sizeof(p->msg)); } int render(DisplayDriver& display) override { - char tmp[16]; + char tmp[24]; + int filtered_count = filteredCount(); + if (view_offset >= filtered_count) view_offset = 0; display.setCursor(0, 0); display.setTextSize(1); display.setColor(UIColor::corp_blue); - sprintf(tmp, "Unread: %d", num_unread); + snprintf(tmp, sizeof(tmp), "Message %d/%d", + filtered_count == 0 ? 0 : view_offset + 1, filtered_count); display.print(tmp); - auto p = &unread[head]; + const MsgEntry* p = filteredEntry(view_offset); + + if (p == nullptr) { + display.drawRect(0, 11, display.width(), 1); + display.setColor(UIColor::secondary_txt); + display.drawTextCentered(display.width() / 2, 40, + "No buffered messages"); + renderChannelFilter(display); + return 5000; + } int secs = _rtc->getCurrentTime() - p->timestamp; if (secs < 60) { @@ -647,6 +817,8 @@ public: display.translateUTF8ToBlocks(filtered_msg, p->msg, sizeof(filtered_msg)); display.printWordWrap(filtered_msg, display.width()); + renderChannelFilter(display); + #if AUTO_OFF_MILLIS==0 // probably e-ink return 10000; // 10 s #else @@ -656,15 +828,22 @@ public: bool handleInput(char c) override { if (c == KEY_NEXT || c == KEY_RIGHT) { - head = (head + MAX_UNREAD_MSGS - 1) % MAX_UNREAD_MSGS; - num_unread--; - if (num_unread == 0) { - _task->gotoHomeScreen(); - } + if (view_offset + 1 < filteredCount()) ++view_offset; + return true; + } + if (c == KEY_PREV || c == KEY_LEFT) { + if (view_offset > 0) --view_offset; + return true; + } + if (c == KEY_DOWN) { + cycleChannelFilter(1); + return true; + } + if (c == KEY_UP) { + cycleChannelFilter(-1); return true; } if (c == KEY_ENTER) { - num_unread = 0; // clear unread queue _task->gotoHomeScreen(); return true; } @@ -727,6 +906,14 @@ void UITask::showAlert(const char* text, int duration_millis) { _alert_expiry = millis() + duration_millis; } +void UITask::showMessages() { + setCurrScreen(msg_preview); +} + +int UITask::getPreviewCount() const { + return static_cast(msg_preview)->messageCount(); +} + void UITask::notify(UIEventType t) { #if defined(PIN_BUZZER) switch(t){ @@ -763,14 +950,20 @@ void UITask::msgRead(int msgcount) { _deferred_msg_preview = false; const bool holding_usb_preview = curr == msg_preview && _msg_preview_until != 0 && static_cast(millis() - _msg_preview_until) < 0; - if (!holding_usb_preview) gotoHomeScreen(); + if (!holding_usb_preview) { + static_cast(msg_preview)->clear(); + gotoHomeScreen(); + } } } -void UITask::newMsg(uint8_t path_len, const char* from_name, const char* text, int msgcount) { +void UITask::newMsg(uint8_t path_len, const char* from_name, const char* text, + int msgcount, int channel_idx, + const char* channel_name) { _msgcount = msgcount; - ((MsgPreviewScreen *) msg_preview)->addPreview(path_len, from_name, text); + ((MsgPreviewScreen *)msg_preview) + ->addPreview(path_len, from_name, text, channel_idx, channel_name); if (isPairingScreenActive()) { // Keep the PIN visible, but retain the preview so it can be shown after // pairing completes or the pairing display window expires. @@ -781,7 +974,8 @@ void UITask::newMsg(uint8_t path_len, const char* from_name, const char* text, i // A connected app drains the offline queue almost immediately, which calls // msgRead(0). While attached to a computer, retain the actual message screen - // for 15 seconds even though the app has already consumed the message. + // for the configured preview interval even though the app has already + // consumed the message. _msg_preview_until = _board->isUsbHostConnected() ? millis() + USB_MESSAGE_PREVIEW_MILLIS : 0; @@ -955,11 +1149,17 @@ void UITask::loop() { if (ev == BUTTON_EVENT_CLICK) { c = checkDisplayOn(KEY_NEXT); } else if (ev == BUTTON_EVENT_LONG_PRESS) { - c = handleLongPress(KEY_ENTER); + c = (_display != NULL && !_display->isOn()) + ? checkDisplayOn(KEY_ENTER) + : handleLongPress(KEY_ENTER); } else if (ev == BUTTON_EVENT_DOUBLE_CLICK) { - c = handleDoubleClick(KEY_PREV); + c = (_display != NULL && !_display->isOn()) + ? checkDisplayOn(KEY_ENTER) + : handleDoubleClick(KEY_PREV); } else if (ev == BUTTON_EVENT_TRIPLE_CLICK) { - c = handleTripleClick(KEY_SELECT); + c = (_display != NULL && !_display->isOn()) + ? checkDisplayOn(KEY_ENTER) + : handleTripleClick(KEY_SELECT); } #endif #endif @@ -988,6 +1188,39 @@ void UITask::loop() { _analogue_pin_read_millis = millis(); } #endif +#ifdef HAS_TOUCH + if (_display != NULL + && (int32_t)(millis() - next_touch_check) >= 0) { + next_touch_check = millis() + 25; + int touch_x = -1; + int touch_y = -1; + const bool touched = _display->getTouch(&touch_x, &touch_y); + const mesh::ui::TouchAction action = touch_input.update( + touched, touch_x, touch_y, _display->width(), _display->height(), + curr == msg_preview); + if (c == 0) { + switch (action) { + case mesh::ui::TouchAction::Previous: + c = checkDisplayOn(KEY_PREV); + break; + case mesh::ui::TouchAction::Next: + c = checkDisplayOn(KEY_NEXT); + break; + case mesh::ui::TouchAction::Select: + c = checkDisplayOn(KEY_ENTER); + break; + case mesh::ui::TouchAction::VerticalPrevious: + c = checkDisplayOn(KEY_UP); + break; + case mesh::ui::TouchAction::VerticalNext: + c = checkDisplayOn(KEY_DOWN); + break; + case mesh::ui::TouchAction::None: + break; + } + } + } +#endif #if defined(BACKLIGHT_BTN) if (millis() > next_backlight_btn_check) { bool touch_state = digitalRead(PIN_BUTTON2); @@ -1021,10 +1254,11 @@ void UITask::loop() { if (curr) curr->poll(); - if (curr == msg_preview && _msgcount == 0 && _msg_preview_until != 0 + if (_msgcount == 0 && _msg_preview_until != 0 && static_cast(millis() - _msg_preview_until) >= 0) { _msg_preview_until = 0; - gotoHomeScreen(); + static_cast(msg_preview)->clear(); + if (curr == msg_preview) gotoHomeScreen(); } if (_display != NULL && _display->isOn()) { diff --git a/examples/companion_radio/ui-new/UITask.h b/examples/companion_radio/ui-new/UITask.h index efcda4f6..cb899896 100644 --- a/examples/companion_radio/ui-new/UITask.h +++ b/examples/companion_radio/ui-new/UITask.h @@ -7,6 +7,9 @@ #include #include #include +#ifdef HAS_TOUCH + #include +#endif #ifndef LED_STATE_ON #define LED_STATE_ON 1 @@ -41,6 +44,22 @@ class UITask : public AbstractUITask { int _msgcount; unsigned long ui_started_at, next_batt_chck; int next_backlight_btn_check = 0; +#ifdef HAS_TOUCH + #ifndef TOUCH_CENTER_ZONE_PERCENT + #define TOUCH_CENTER_ZONE_PERCENT 34 + #endif + #if defined(TOUCH_REVERSE_SWIPE) \ + && defined(TOUCH_SEPARATE_VERTICAL_SWIPES) + mesh::ui::TouchInput touch_input{true, true, TOUCH_CENTER_ZONE_PERCENT}; + #elif defined(TOUCH_REVERSE_SWIPE) + mesh::ui::TouchInput touch_input{true, false, TOUCH_CENTER_ZONE_PERCENT}; + #elif defined(TOUCH_SEPARATE_VERTICAL_SWIPES) + mesh::ui::TouchInput touch_input{false, true, TOUCH_CENTER_ZONE_PERCENT}; + #else + mesh::ui::TouchInput touch_input{false, false, TOUCH_CENTER_ZONE_PERCENT}; + #endif + unsigned long next_touch_check = 0; +#endif #ifdef PIN_STATUS_LED int led_state = 0; int next_led_change = 0; @@ -83,8 +102,10 @@ public: void serviceWiFiToggleButton(); void gotoHomeScreen() { setCurrScreen(home); } + void showMessages(); void showAlert(const char* text, int duration_millis); int getMsgCount() const { return _msgcount; } + int getPreviewCount() const; bool hasDisplay() const { return _display != NULL; } bool isButtonPressed() const; @@ -103,7 +124,9 @@ public: // from AbstractUITask void msgRead(int msgcount) override; - void newMsg(uint8_t path_len, const char* from_name, const char* text, int msgcount) override; + void newMsg(uint8_t path_len, const char* from_name, const char* text, + int msgcount, int channel_idx = -1, + const char* channel_name = nullptr) override; void notify(UIEventType t = UIEventType::none) override; void loop() override; diff --git a/examples/companion_radio/ui-orig/UITask.cpp b/examples/companion_radio/ui-orig/UITask.cpp index 86e67d1b..a0e0e8c2 100644 --- a/examples/companion_radio/ui-orig/UITask.cpp +++ b/examples/companion_radio/ui-orig/UITask.cpp @@ -156,7 +156,11 @@ void UITask::clearMsgPreview() { _need_refresh = true; } -void UITask::newMsg(uint8_t path_len, const char* from_name, const char* text, int msgcount) { +void UITask::newMsg(uint8_t path_len, const char* from_name, const char* text, + int msgcount, int channel_idx, + const char* channel_name) { + (void)channel_idx; + (void)channel_name; _msgcount = msgcount; #ifdef HAS_DRV2605 diff --git a/examples/companion_radio/ui-orig/UITask.h b/examples/companion_radio/ui-orig/UITask.h index d99048fa..d336f98e 100644 --- a/examples/companion_radio/ui-orig/UITask.h +++ b/examples/companion_radio/ui-orig/UITask.h @@ -78,7 +78,9 @@ public: // from AbstractUITask void msgRead(int msgcount) override; - void newMsg(uint8_t path_len, const char* from_name, const char* text, int msgcount) override; + void newMsg(uint8_t path_len, const char* from_name, const char* text, + int msgcount, int channel_idx = -1, + const char* channel_name = nullptr) override; void notify(UIEventType t = UIEventType::none) override; void loop() override; diff --git a/examples/companion_radio/ui-tiny/UITask.cpp b/examples/companion_radio/ui-tiny/UITask.cpp index 6207e0f0..ca3ee49e 100644 --- a/examples/companion_radio/ui-tiny/UITask.cpp +++ b/examples/companion_radio/ui-tiny/UITask.cpp @@ -515,7 +515,11 @@ void UITask::msgRead(int msgcount) { } } -void UITask::newMsg(uint8_t path_len, const char* from_name, const char* text, int msgcount) { +void UITask::newMsg(uint8_t path_len, const char* from_name, const char* text, + int msgcount, int channel_idx, + const char* channel_name) { + (void)channel_idx; + (void)channel_name; _msgcount = msgcount; if (_display != NULL) { diff --git a/examples/companion_radio/ui-tiny/UITask.h b/examples/companion_radio/ui-tiny/UITask.h index aeb3a90e..a4a49753 100644 --- a/examples/companion_radio/ui-tiny/UITask.h +++ b/examples/companion_radio/ui-tiny/UITask.h @@ -106,7 +106,9 @@ public: // from AbstractUITask void msgRead(int msgcount) override; - void newMsg(uint8_t path_len, const char* from_name, const char* text, int msgcount) override; + void newMsg(uint8_t path_len, const char* from_name, const char* text, + int msgcount, int channel_idx = -1, + const char* channel_name = nullptr) override; void notify(UIEventType t = UIEventType::none) override; void loop() override; diff --git a/src/Dispatcher.h b/src/Dispatcher.h index 73a4a1c3..a5230154 100644 --- a/src/Dispatcher.h +++ b/src/Dispatcher.h @@ -94,6 +94,9 @@ public: } virtual int getNoiseFloor() const { return 0; } + virtual float getNoiseFloorDbm() const { + return static_cast(getNoiseFloor()); + } virtual void triggerNoiseFloorCalibrate(int threshold) { } diff --git a/src/helpers/MeshClockSync.cpp b/src/helpers/MeshClockSync.cpp index 92dbc2b8..e2a9cd84 100644 --- a/src/helpers/MeshClockSync.cpp +++ b/src/helpers/MeshClockSync.cpp @@ -19,14 +19,22 @@ #ifndef FIRMWARE_BUILD_EPOCH #define FIRMWARE_BUILD_EPOCH 0UL #endif +#ifndef MESH_CLOCK_SYNC_REQUIRED_SAMPLES_DEFAULT + #define MESH_CLOCK_SYNC_REQUIRED_SAMPLES_DEFAULT 9 +#endif +#ifndef MESH_CLOCK_SYNC_STARTUP_DELAY_MILLIS + #define MESH_CLOCK_SYNC_STARTUP_DELAY_MILLIS (30ULL * 60ULL * 1000ULL) +#endif namespace { constexpr char PREFS_FILE[] = "/clock_sync"; constexpr uint8_t REQUIRED_SAMPLES_MIN = 3; constexpr uint8_t REQUIRED_SAMPLES_MAX = 16; -constexpr uint8_t REQUIRED_SAMPLES_DEFAULT = 9; -constexpr uint64_t STARTUP_DELAY_MILLIS = 30ULL * 60ULL * 1000ULL; +constexpr uint8_t REQUIRED_SAMPLES_DEFAULT = + MESH_CLOCK_SYNC_REQUIRED_SAMPLES_DEFAULT; +constexpr uint64_t STARTUP_DELAY_MILLIS = + MESH_CLOCK_SYNC_STARTUP_DELAY_MILLIS; constexpr uint64_t RETRY_INTERVAL_MILLIS = 30ULL * 60ULL * 1000ULL; constexpr uint64_t RESYNC_INTERVAL_MILLIS = 7ULL * 24ULL * 60ULL * 60ULL * 1000ULL; constexpr uint32_t SAMPLE_MAX_AGE_MILLIS = 2UL * 60UL * 60UL * 1000UL; @@ -35,6 +43,12 @@ constexpr uint32_t DRIFT_MIN_SECONDS = 30UL; constexpr uint32_t DRIFT_MAX_SECONDS = 86400UL; constexpr uint16_t VALID_YEARS = 10; +static_assert(REQUIRED_SAMPLES_DEFAULT >= REQUIRED_SAMPLES_MIN + && REQUIRED_SAMPLES_DEFAULT <= REQUIRED_SAMPLES_MAX, + "mesh clock-sync sample default is outside the supported range"); +static_assert(STARTUP_DELAY_MILLIS > 0, + "mesh clock-sync startup delay must be positive"); + // Public-channel AES key, zero-padded to the shared-secret buffer width used // by Utils::MACThenDecrypt(). const uint8_t PUBLIC_CHANNEL_SECRET[PUB_KEY_SIZE] = { diff --git a/src/helpers/WiFiSetupPortal.cpp b/src/helpers/WiFiSetupPortal.cpp index 9e3a47bf..17d71c3b 100644 --- a/src/helpers/WiFiSetupPortal.cpp +++ b/src/helpers/WiFiSetupPortal.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include @@ -296,7 +297,15 @@ bool WiFiSetupPortal::begin(const char* ap_name, SaveCallback save_callback, voi WiFi.mode(WIFI_AP_STA); if (!WiFi.softAPConfig(SETUP_IP, SETUP_IP, SETUP_MASK) - || !WiFi.softAP(impl->ap_name, nullptr)) { + || !WiFi.softAP(impl->ap_name, nullptr) + || esp_wifi_set_protocol( + WIFI_IF_AP, + WIFI_PROTOCOL_11B | WIFI_PROTOCOL_11G | WIFI_PROTOCOL_11N) + != ESP_OK + || esp_wifi_set_protocol( + WIFI_IF_STA, + WIFI_PROTOCOL_11B | WIFI_PROTOCOL_11G | WIFI_PROTOCOL_11N) + != ESP_OK) { WiFi.softAPdisconnect(true); return false; } diff --git a/src/helpers/esp32/ESPNOWRadio.cpp b/src/helpers/esp32/ESPNOWRadio.cpp index f264c887..415dae24 100644 --- a/src/helpers/esp32/ESPNOWRadio.cpp +++ b/src/helpers/esp32/ESPNOWRadio.cpp @@ -42,6 +42,10 @@ static void OnDataRecv(const uint8_t *mac, const uint8_t *data, int len) { void ESPNOWRadio::init() { // Set device as a Wi-Fi Station + // ESP-NOW's LR protocol is local to this radio transport. Keeping WiFi + // driver writes in RAM prevents a later conventional WiFi image from + // inheriting the proprietary protocol bit through NVS. + WiFi.persistent(false); WiFi.mode(WIFI_STA); // Long Range mode esp_wifi_set_protocol(WIFI_IF_STA, WIFI_PROTOCOL_LR); diff --git a/src/helpers/esp32/WebConfigServer.cpp b/src/helpers/esp32/WebConfigServer.cpp index 12338775..4d0e8356 100644 --- a/src/helpers/esp32/WebConfigServer.cpp +++ b/src/helpers/esp32/WebConfigServer.cpp @@ -603,7 +603,22 @@ bool WebConfigServer::startSetupMode(char reply[]) { #else ap_ok = WiFi.softAP(_ap_ssid); #endif - if (ap_ok) break; + if (ap_ok) { + // ESP-NOW can leave the persistent AP protocol mask with the proprietary + // LR bit set. The driver then reports a healthy SoftAP, but ordinary + // phones and laptops cannot discover its beacon. A WiFi companion must + // advertise using the interoperable 2.4 GHz protocol set. + const esp_err_t ap_protocol_result = esp_wifi_set_protocol( + WIFI_IF_AP, + WIFI_PROTOCOL_11B | WIFI_PROTOCOL_11G | WIFI_PROTOCOL_11N); + const esp_err_t sta_protocol_result = esp_wifi_set_protocol( + WIFI_IF_STA, + WIFI_PROTOCOL_11B | WIFI_PROTOCOL_11G | WIFI_PROTOCOL_11N); + if (ap_protocol_result == ESP_OK && sta_protocol_result == ESP_OK) break; + Serial.printf("WebConfig protocol reset failed: AP=%d STA=%d\n", + (int)ap_protocol_result, (int)sta_protocol_result); + ap_ok = false; + } Serial.printf( "WebConfig AP attempt %u failed: mode_ok=%d disconnect_ok=%d mode=%d heap=%u largest=%u\n", @@ -677,6 +692,13 @@ bool WebConfigServer::startAutoMode(char reply[]) { } WiFi.mode(WIFI_STA); + if (esp_wifi_set_protocol( + WIFI_IF_STA, + WIFI_PROTOCOL_11B | WIFI_PROTOCOL_11G | WIFI_PROTOCOL_11N) + != ESP_OK) { + strcpy(reply, "Err: failed to reset WiFi station protocol"); + return false; + } WiFi.setAutoReconnect(true); _retry_saved_wifi_in_setup = false; _setup_reconnect_in_progress = false; diff --git a/src/helpers/ota/OtaTargets.h b/src/helpers/ota/OtaTargets.h index db40036b..722e751a 100644 --- a/src/helpers/ota/OtaTargets.h +++ b/src/helpers/ota/OtaTargets.h @@ -2,7 +2,7 @@ #include // AUTO-GENERATED by tools/mota/gen_targets.py - do not edit by hand. -// 577 OTA-capable build targets. Maps target_id (= sha2-256:4 of the target name, LE uint32) +// 594 OTA-capable build targets. Maps target_id (= sha2-256:4 of the target name, LE uint32) // to the human-readable env name, so a node/tool can name a target seen over the air WITHOUT // transmitting the string in the .mota / LoRa protocol. Regenerate when the OTA env set changes. // Size-constrained receivers can set OTA_TARGET_NAME_TABLE=0. They still match targets by ID; @@ -68,6 +68,7 @@ inline const char* ota_target_env_name(uint32_t target_id) { { 0xb12e6e01, "Heltec_E290_room_server" }, { 0xf6f835ec, "Heltec_mesh_solar_repeater" }, { 0x7fab017f, "heltec_rc32_companion_radio_ble" }, + { 0x9e23928a, "heltec_rc32_companion_radio_full" }, { 0xf310a4d1, "heltec_rc32_companion_radio_usb" }, { 0xdd5953ec, "heltec_rc32_companion_radio_wifi" }, { 0x97574bc2, "heltec_rc32_kiss_modem" }, @@ -77,6 +78,7 @@ inline const char* ota_target_env_name(uint32_t target_id) { { 0x57f69746, "heltec_rc32_sensor" }, { 0xbc05d6a7, "heltec_rc32_terminal_chat" }, { 0x5bad80f1, "heltec_rc32_without_display_companion_radio_ble" }, + { 0xb4f727a8, "heltec_rc32_without_display_companion_radio_full" }, { 0x112d34c4, "heltec_rc32_without_display_companion_radio_usb" }, { 0xf10a26df, "heltec_rc32_without_display_companion_radio_wifi" }, { 0xc5409ced, "heltec_rc32_without_display_repeater" }, @@ -120,6 +122,7 @@ inline const char* ota_target_env_name(uint32_t target_id) { { 0xa3e8d8ce, "heltec_tracker_v1_1_room_server_observer_mqtt" }, { 0xb16009a0, "heltec_tracker_v2_companion_radio_ble_femoff" }, { 0xdc780e80, "heltec_tracker_v2_companion_radio_ble_femon" }, + { 0x28b8007c, "heltec_tracker_v2_companion_radio_full_femon" }, { 0x4aa63180, "heltec_tracker_v2_companion_radio_usb_femoff" }, { 0x6fddcbf1, "heltec_tracker_v2_companion_radio_usb_femon" }, { 0xf4fb5484, "heltec_tracker_v2_companion_radio_wifi_femoff" }, @@ -155,13 +158,16 @@ inline const char* ota_target_env_name(uint32_t target_id) { { 0xceeddfaf, "Heltec_v3_room_server_observer_mqtt" }, { 0x21519537, "Heltec_v3_sensor" }, { 0x382bb181, "Heltec_v3_terminal_chat" }, + { 0xad1bcd63, "heltec_v4_2_v4_3_companion_radio_full_femon" }, { 0x5a2980e6, "heltec_v4_3_companion_radio_ble_femoff" }, { 0x90581c83, "heltec_v4_3_companion_radio_ble_ps_femoff" }, + { 0x90a6a854, "heltec_v4_3_companion_radio_full_femoff" }, { 0x356df17c, "heltec_v4_3_companion_radio_usb_femoff" }, { 0x99a084fc, "heltec_v4_3_companion_radio_wifi_femoff" }, { 0x64c9dfc9, "heltec_v4_3_companion_radio_wifi_mqtt_femoff" }, { 0x2a2ffc92, "heltec_v4_3_expansionkit_tft_companion_radio_ble_femoff" }, { 0x2c13b8e9, "heltec_v4_3_tft_companion_radio_ble_femoff" }, + { 0x1ee7d867, "heltec_v4_3_tft_companion_radio_full_femoff" }, { 0xb016979a, "heltec_v4_3_tft_companion_radio_usb_femoff" }, { 0xb49b6b55, "heltec_v4_3_tft_companion_radio_wifi_femoff" }, { 0x01d8f124, "heltec_v4_companion_radio_ble" }, @@ -181,6 +187,7 @@ inline const char* ota_target_env_name(uint32_t target_id) { { 0xf75feb3e, "heltec_v4_kiss_modem" }, { 0xbc9cdc70, "heltec_v4_r8_companion_radio_ble" }, { 0x19e31fc6, "heltec_v4_r8_companion_radio_ble_ps" }, + { 0xa01b330e, "heltec_v4_r8_companion_radio_full" }, { 0x36c78d86, "heltec_v4_r8_companion_radio_usb" }, { 0xdf722326, "heltec_v4_r8_companion_radio_wifi" }, { 0xfa901c87, "heltec_v4_r8_kiss_modem" }, @@ -189,6 +196,7 @@ inline const char* ota_target_env_name(uint32_t target_id) { { 0xb4cb035a, "heltec_v4_r8_sensor" }, { 0xbb429dde, "heltec_v4_r8_terminal_chat" }, { 0x883e3edc, "heltec_v4_r8_tft_companion_radio_ble" }, + { 0x4a9d1c6c, "heltec_v4_r8_tft_companion_radio_full" }, { 0xa0965a6b, "heltec_v4_r8_tft_companion_radio_usb" }, { 0x59ea25fa, "heltec_v4_r8_tft_companion_radio_wifi" }, { 0x1758bdb9, "heltec_v4_r8_tft_kiss_modem" }, @@ -204,6 +212,7 @@ inline const char* ota_target_env_name(uint32_t target_id) { { 0x0b6847ed, "heltec_v4_sensor" }, { 0xab3e1ad3, "heltec_v4_terminal_chat" }, { 0x04a8b763, "heltec_v4_tft_companion_radio_ble_femon" }, + { 0xc456437e, "heltec_v4_tft_companion_radio_full_femon" }, { 0xb3ecafca, "heltec_v4_tft_companion_radio_usb_femon" }, { 0xf3afcde6, "heltec_v4_tft_companion_radio_wifi_femon" }, { 0x87513d56, "heltec_v4_tft_repeater" }, @@ -311,6 +320,7 @@ inline const char* ota_target_env_name(uint32_t target_id) { { 0x07907102, "LilyGo_T_Impulse_Plus_repeater" }, { 0x3898ea56, "LilyGo_TBeam_1W_companion_radio_ble" }, { 0x2fb7e218, "LilyGo_TBeam_1W_companion_radio_ble_ps" }, + { 0x8c61d4c8, "LilyGo_TBeam_1W_companion_radio_full" }, { 0x4f722e70, "LilyGo_TBeam_1W_companion_radio_usb" }, { 0x694eed25, "LilyGo_TBeam_1W_companion_radio_wifi" }, { 0x85b8b9d7, "LilyGo_TBeam_1W_kiss_modem" }, @@ -364,6 +374,7 @@ inline const char* ota_target_env_name(uint32_t target_id) { { 0xd45277ff, "Meshimi_companion_radio_ble_" }, { 0x2cad9a9d, "Meshimi_repeater_" }, { 0x02a4a8c1, "meshnology_w12_companion_radio_ble" }, + { 0x4a709348, "meshnology_w12_companion_radio_full" }, { 0x35d960bd, "meshnology_w12_companion_radio_usb" }, { 0x62977023, "meshnology_w12_companion_radio_wifi" }, { 0x17a7ed8c, "meshnology_w12_kiss_modem" }, @@ -376,6 +387,7 @@ inline const char* ota_target_env_name(uint32_t target_id) { { 0x11b131e7, "Minewsemi_me25ls01_repeater_lora_ota_no_external_sensors" }, { 0xf8259880, "Nano_G2_Ultra_repeater" }, { 0x063f1f00, "nibble_screen_connect_companion_radio_ble_" }, + { 0x70d71f92, "nibble_screen_connect_companion_radio_full_" }, { 0xa8a79da5, "nibble_screen_connect_companion_radio_usb_" }, { 0xc0d3815b, "nibble_screen_connect_companion_radio_wifi_" }, { 0x966ac88e, "nibble_screen_connect_kiss_modem_" }, @@ -384,6 +396,7 @@ inline const char* ota_target_env_name(uint32_t target_id) { { 0xc42cc90d, "nibble_screen_connect_room_server_" }, { 0xc24791c3, "nibble_screen_connect_terminal_chat_" }, { 0x15e11067, "nibble_zero_connect_companion_radio_ble_" }, + { 0x2dbb2669, "nibble_zero_connect_companion_radio_full_" }, { 0x90799c32, "nibble_zero_connect_companion_radio_usb_" }, { 0x881a6a48, "nibble_zero_connect_companion_radio_wifi_" }, { 0xf26af51c, "nibble_zero_connect_repeater_" }, @@ -408,6 +421,7 @@ inline const char* ota_target_env_name(uint32_t target_id) { { 0x4d0b1601, "R1Neo_sensor" }, { 0xab2ac09e, "R1Neo_terminal_chat" }, { 0xa17fc4f7, "RAK_3112_companion_radio_ble" }, + { 0xe4b2bd22, "RAK_3112_companion_radio_full" }, { 0x90c4eb3f, "RAK_3112_companion_radio_usb" }, { 0x19d9ce91, "RAK_3112_companion_radio_wifi" }, { 0x121cc72f, "RAK_3112_kiss_modem" }, @@ -438,6 +452,8 @@ inline const char* ota_target_env_name(uint32_t target_id) { { 0x51fa1a49, "RAK_WisMesh_Tag_sensor" }, { 0xdb73638b, "SenseCap_Solar_repeater" }, { 0xd904c2d5, "SenseCapIndicator-ESPNow_comp_radio_usb" }, + { 0x620569f4, "SenseCapIndicator-LoRa_comp_radio_usb" }, + { 0x08483f6b, "SenseCapIndicator-LoRa_comp_radio_usb_wifi" }, { 0x0db48f35, "solarxiao_30S_companion_radio_ble" }, { 0x20532f6c, "solarxiao_30S_companion_radio_usb" }, { 0x293ced32, "solarxiao_30S_kiss_modem" }, @@ -455,6 +471,7 @@ inline const char* ota_target_env_name(uint32_t target_id) { { 0xf2128c81, "Station_G2_repeater" }, { 0x1b34e7b4, "Station_G2_repeater_bridge_espnow" }, { 0x8e549407, "Station_G3_ESP32_companion_radio_ble" }, + { 0x6ca142f4, "Station_G3_ESP32_companion_radio_full" }, { 0x1deac038, "Station_G3_ESP32_companion_radio_usb" }, { 0x2a2f303b, "Station_G3_ESP32_companion_radio_wifi" }, { 0x0ba4453d, "Station_G3_ESP32_kiss_modem" }, @@ -584,6 +601,7 @@ inline const char* ota_target_env_name(uint32_t target_id) { { 0x60f5fdc2, "Xiao_S3_sensor" }, { 0xe8f79d22, "Xiao_S3_WIO_companion_radio_ble" }, { 0xb97bbb15, "Xiao_S3_WIO_companion_radio_ble_ps" }, + { 0xd466590c, "Xiao_S3_WIO_companion_radio_full" }, { 0x9f27be15, "Xiao_S3_WIO_companion_radio_serial" }, { 0x396fecc7, "Xiao_S3_WIO_companion_radio_usb" }, { 0xf94e3407, "Xiao_S3_WIO_companion_radio_wifi" }, diff --git a/src/helpers/radiolib/RadioLibWrappers.cpp b/src/helpers/radiolib/RadioLibWrappers.cpp index cac7ca37..899649c8 100644 --- a/src/helpers/radiolib/RadioLibWrappers.cpp +++ b/src/helpers/radiolib/RadioLibWrappers.cpp @@ -62,6 +62,7 @@ void RadioLibWrapper::begin() { } _noise_floor = 0; + _noise_floor_centi_dbm = 0; _noise_floor_valid = false; _threshold = 0; _cad_enabled = false; @@ -71,7 +72,7 @@ void RadioLibWrapper::begin() { // start average out some samples _num_floor_samples = 0; - _floor_sample_sum = 0; + _floor_sample_sum_centi_dbm = 0; _nf_calib_active = false; _nf_last_calib = 0; _nf_sample_from = 0; @@ -232,7 +233,7 @@ void RadioLibWrapper::recalibrateNoiseFloor() { _nf_refresh_requested = true; _nf_last_calib = 0; _num_floor_samples = 0; - _floor_sample_sum = 0; + _floor_sample_sum_centi_dbm = 0; const unsigned long now = millis(); _nf_sample_from = now + NF_CALIB_SETTLE_MS; @@ -251,7 +252,7 @@ void RadioLibWrapper::requestNoiseFloorRefresh() { if (_nf_refresh_requested) return; _nf_refresh_requested = true; _num_floor_samples = 0; - _floor_sample_sum = 0; + _floor_sample_sum_centi_dbm = 0; _nf_calib_deadline = 0; // starts when continuous RX is actually available } @@ -425,7 +426,7 @@ void RadioLibWrapper::noiseFloorCalibCheck(unsigned long now) { _nf_calib_deadline = now + NF_CALIB_TIMEOUT_MS; _nf_sample_from = now + NF_CALIB_SETTLE_MS; _num_floor_samples = 0; // start a fresh batch for this window - _floor_sample_sum = 0; + _floor_sample_sum_centi_dbm = 0; if (!isPacketPendingOrReceiving()) { requestRestartRecv(); // startReceiveMode() selects continuous RX } @@ -463,22 +464,29 @@ void RadioLibWrapper::loop() { _nf_calib_deadline = now + NF_CONTINUOUS_TIMEOUT_MS; } if (_nf_refresh_requested && _num_floor_samples >= NUM_NOISE_FLOOR_SAMPLES - && _floor_sample_sum != 0) { - int16_t sampled_floor = _floor_sample_sum / NUM_NOISE_FLOOR_SAMPLES; - if (sampled_floor < -120) { - sampled_floor = -120; // clamp to lower bound of -120dBi + && _floor_sample_sum_centi_dbm != 0) { + int32_t sampled_floor_centi_dbm = + _floor_sample_sum_centi_dbm / NUM_NOISE_FLOOR_SAMPLES; + if (sampled_floor_centi_dbm < -12000) { + sampled_floor_centi_dbm = -12000; } if (_noise_floor_valid) { // Favor the fresh high-rate batch while retaining a small amount of - // history: 25% previous floor + 75% newly sampled floor. Round the - // negative dBm result to the nearest integer instead of toward zero. - int32_t weighted_floor = (int32_t)_noise_floor + 3L * sampled_floor; - _noise_floor = weighted_floor < 0 ? (weighted_floor - 2) / 4 - : (weighted_floor + 2) / 4; + // history: 25% previous floor + 75% newly sampled floor. + int32_t weighted_floor = _noise_floor_centi_dbm + + 3L * sampled_floor_centi_dbm; + _noise_floor_centi_dbm = weighted_floor < 0 + ? (weighted_floor - 2) / 4 + : (weighted_floor + 2) / 4; } else { - _noise_floor = sampled_floor; + _noise_floor_centi_dbm = sampled_floor_centi_dbm; } - _floor_sample_sum = 0; + // Preserve the existing whole-dB API and wire formats while exposing the + // fractional 64-sample mean to local displays. + _noise_floor = _noise_floor_centi_dbm < 0 + ? (_noise_floor_centi_dbm - 50) / 100 + : (_noise_floor_centi_dbm + 50) / 100; + _floor_sample_sum_centi_dbm = 0; _noise_floor_valid = true; _nf_refresh_requested = false; _nf_last_calib = now; @@ -503,7 +511,7 @@ void RadioLibWrapper::loop() { _nf_last_calib = now; _nf_calib_deadline = 0; _num_floor_samples = 0; - _floor_sample_sum = 0; + _floor_sample_sum_centi_dbm = 0; } if (_nf_refresh_requested && state == STATE_RX @@ -516,13 +524,15 @@ void RadioLibWrapper::loop() { if (!_rx_ps_armed && !(_nf_sample_from != 0 && (long)(now - _nf_sample_from) < 0) && !isReceivingPacket()) { - int rssi = getCurrentRSSI(); - if (!_noise_floor_valid || rssi < _noise_floor + SAMPLING_THRESHOLD) { + float rssi = getCurrentRSSI(); + if (!_noise_floor_valid + || rssi < getNoiseFloorDbm() + SAMPLING_THRESHOLD) { // With no valid baseline (startup, AGC reset, or gain change), seed // unconditionally. Otherwise reject likely traffic above the current // floor plus the sampling margin. _num_floor_samples++; - _floor_sample_sum += rssi; + _floor_sample_sum_centi_dbm += + static_cast(rssi * 100.0f); } } } diff --git a/src/helpers/radiolib/RadioLibWrappers.h b/src/helpers/radiolib/RadioLibWrappers.h index 549853ae..f011159d 100644 --- a/src/helpers/radiolib/RadioLibWrappers.h +++ b/src/helpers/radiolib/RadioLibWrappers.h @@ -30,12 +30,13 @@ protected: mesh::MainBoard* _board; uint32_t n_recv, n_sent, n_recv_errors; int16_t _noise_floor, _threshold; + int32_t _noise_floor_centi_dbm; float _last_rssi, _last_snr; bool _cad_enabled; bool _noise_floor_valid; bool _nf_refresh_requested; uint16_t _num_floor_samples; - int32_t _floor_sample_sum; + int32_t _floor_sample_sum_centi_dbm; unsigned long last_recv_millis; unsigned long last_radio_interrupt_millis; // updated on any ISR event, even CRC errors bool _rx_ps_enabled; @@ -203,6 +204,9 @@ public: virtual int16_t performChannelScan(); int getNoiseFloor() const override { return _noise_floor; } + float getNoiseFloorDbm() const override { + return _noise_floor_centi_dbm / 100.0f; + } void triggerNoiseFloorCalibrate(int threshold) override; void recalibrateNoiseFloor() override; void setCADEnabled(bool enable) override { _cad_enabled = enable; } diff --git a/src/helpers/sensors/EnvironmentSensorManager.cpp b/src/helpers/sensors/EnvironmentSensorManager.cpp index 98fca471..651989b2 100644 --- a/src/helpers/sensors/EnvironmentSensorManager.cpp +++ b/src/helpers/sensors/EnvironmentSensorManager.cpp @@ -691,12 +691,17 @@ bool EnvironmentSensorManager::begin() { MESH_DEBUG_PRINTLN("Second I2C initialized on pins SDA: %d SCL: %d", ENV_PIN_SDA, ENV_PIN_SCL); #endif + _active_sensor_count = 0; + // Avoid touching a shared I2C bus when no environmental drivers were built. + if (SENSOR_TABLE_SIZE == 0) { + return true; + } + // Scan the I2C bus before touching any sensor library. bool detected[128] = {}; scanI2CBus(TELEM_WIRE, detected); // Walk the sensor table and initialize only detected devices. - _active_sensor_count = 0; for (size_t i = 0; i < SENSOR_TABLE_SIZE && _active_sensor_count < MAX_ACTIVE_SENSORS; i++) { const SensorDef& def = SENSOR_TABLE[i]; // One static driver instance per type: an alternate address is a fallback, not a second device. diff --git a/src/helpers/ui/ColorEmojiAtlas.h b/src/helpers/ui/ColorEmojiAtlas.h new file mode 100644 index 00000000..c8bf8760 --- /dev/null +++ b/src/helpers/ui/ColorEmojiAtlas.h @@ -0,0 +1,123 @@ +#pragma once + +#include +#include +#include + +namespace mesh { +namespace ui { + +class ColorEmojiAtlas { + static constexpr size_t FOOTER_SIZE = 40; + static constexpr size_t ATLAS_HEADER_SIZE = 12; + static constexpr uint16_t FIRST_EMOJI = 0xE000; + + const uint8_t* _pixels = nullptr; + uint16_t _count = 0; + uint16_t _stride = 0; + uint8_t _width = 0; + uint8_t _height = 0; + uint8_t _transparent = 0; + uint8_t _text_scale = 1; + + static uint16_t read16(const uint8_t* p) { + return (uint16_t)p[0] | ((uint16_t)p[1] << 8); + } + + static uint32_t read32(const uint8_t* p) { + return (uint32_t)p[0] + | ((uint32_t)p[1] << 8) + | ((uint32_t)p[2] << 16) + | ((uint32_t)p[3] << 24); + } + + static uint32_t crc32(const uint8_t* data, size_t size) { + uint32_t crc = 0xFFFFFFFFUL; + for (size_t i = 0; i < size; ++i) { + crc ^= data[i]; + for (uint8_t bit = 0; bit < 8; ++bit) { + crc = (crc >> 1) ^ (0xEDB88320UL & (0U - (crc & 1U))); + } + } + return ~crc; + } + +public: + void reset() { + _pixels = nullptr; + _count = 0; + _stride = 0; + _width = 0; + _height = 0; + _transparent = 0; + _text_scale = 1; + } + + bool begin(const uint8_t* font_data, size_t font_size) { + reset(); + if (font_data == nullptr || font_size < FOOTER_SIZE) return false; + + const uint8_t* footer = font_data + font_size - FOOTER_SIZE; + static const uint8_t FOOTER_MAGIC[8] = { + 'M', 'C', 'E', 'M', 'A', 'P', '2', 0 + }; + if (memcmp(footer, FOOTER_MAGIC, sizeof(FOOTER_MAGIC)) != 0) { + return false; + } + + uint32_t atlas_offset = read32(footer + 20); + uint32_t atlas_size = read32(footer + 24); + uint32_t atlas_crc = read32(footer + 28); + if (atlas_offset > font_size - FOOTER_SIZE + || atlas_size > font_size - FOOTER_SIZE - atlas_offset + || atlas_size < ATLAS_HEADER_SIZE) { + return false; + } + + const uint8_t* atlas = font_data + atlas_offset; + if (crc32(atlas, atlas_size) != atlas_crc + || memcmp(atlas, "CE01", 4) != 0) { + return false; + } + + uint16_t count = read16(atlas + 4); + uint8_t width = atlas[6]; + uint8_t height = atlas[7]; + uint8_t transparent = atlas[8]; + uint8_t text_scale = atlas[9]; + uint16_t stride = read16(atlas + 10); + if (count == 0 || width == 0 || height == 0 + || width > 64 || height > 64 + || text_scale == 0 || text_scale > 8 + || stride != (uint16_t)width * height + || (size_t)count * stride != atlas_size - ATLAS_HEADER_SIZE) { + return false; + } + + _pixels = atlas + ATLAS_HEADER_SIZE; + _count = count; + _stride = stride; + _width = width; + _height = height; + _transparent = transparent; + _text_scale = text_scale; + return true; + } + + bool isReady() const { return _pixels != nullptr; } + uint8_t width() const { return _width; } + uint8_t height() const { return _height; } + uint8_t transparent() const { return _transparent; } + uint8_t textScale() const { return _text_scale; } + uint16_t count() const { return _count; } + + const uint8_t* glyph(uint16_t mapped_codepoint) const { + if (!isReady() || mapped_codepoint < FIRST_EMOJI) return nullptr; + uint16_t index = mapped_codepoint - FIRST_EMOJI; + if (index >= _count) return nullptr; + return _pixels + (size_t)index * _stride; + } +}; + +} // namespace ui +} // namespace mesh diff --git a/src/helpers/ui/DisplayDriver.h b/src/helpers/ui/DisplayDriver.h index 05f8f152..47f59210 100644 --- a/src/helpers/ui/DisplayDriver.h +++ b/src/helpers/ui/DisplayDriver.h @@ -15,6 +15,14 @@ class DisplayDriver { int _w, _h; protected: DisplayDriver(int w, int h) { _w = w; _h = h; } + + static size_t trimLastUTF8Codepoint(char* str, size_t length) { + if (length == 0) return 0; + size_t start = length - 1; + while (start > 0 && ((uint8_t)str[start] & 0xC0) == 0x80) --start; + str[start] = 0; + return start; + } public: //enum Color { DARK=0, LIGHT, RED, GREEN, BLUE, YELLOW, ORANGE }; // on b/w screen, colors will be !=0 synonym of light @@ -37,6 +45,11 @@ public: virtual void drawRect(int x, int y, int w, int h) = 0; virtual void drawXbm(int x, int y, const uint8_t* bits, int w, int h) = 0; virtual uint16_t getTextWidth(const char* str) = 0; + virtual bool getTouch(int* x, int* y) { + (void)x; + (void)y; + return false; + } virtual void drawTextCentered(int mid_x, int y, const char* str) { // helper method (override to optimise) int w = getTextWidth(str); setCursor(mid_x - w/2, y); @@ -72,9 +85,16 @@ public: virtual void drawTextEllipsized(int x, int y, int max_width, const char* str) { char temp_str[256]; // reasonable buffer size size_t len = strlen(str); - if (len >= sizeof(temp_str)) len = sizeof(temp_str) - 1; + if (len >= sizeof(temp_str)) { + len = sizeof(temp_str) - 1; + // If the fixed buffer cuts through a UTF-8 sequence, omit that whole + // codepoint instead of passing malformed text to the display driver. + while (len > 0 && ((uint8_t)str[len] & 0xC0) == 0x80) --len; + } memcpy(temp_str, str, len); temp_str[len] = 0; + + if (max_width <= 0) return; if (getTextWidth(temp_str) <= max_width) { setCursor(x, y); @@ -95,12 +115,19 @@ public: } int ellipsis_width = getTextWidth(ellipsis); - int str_len = strlen(temp_str); + size_t ellipsis_len = strlen(ellipsis); + size_t str_len = strlen(temp_str); - while (str_len > 0 && getTextWidth(temp_str) > max_width - ellipsis_width) { - temp_str[--str_len] = 0; + while (str_len > 0 + && (getTextWidth(temp_str) > max_width - ellipsis_width + || str_len + ellipsis_len >= sizeof(temp_str))) { + str_len = trimLastUTF8Codepoint(temp_str, str_len); + } + if (ellipsis_width <= max_width) { + memcpy(temp_str + str_len, ellipsis, ellipsis_len + 1); + } else { + temp_str[0] = 0; } - strcat(temp_str, ellipsis); setCursor(x, y); print(temp_str); diff --git a/src/helpers/ui/EmojiFontMap.h b/src/helpers/ui/EmojiFontMap.h new file mode 100644 index 00000000..529df818 --- /dev/null +++ b/src/helpers/ui/EmojiFontMap.h @@ -0,0 +1,178 @@ +#pragma once + +#include +#include +#include + +namespace mesh { +namespace ui { + +class EmojiFontMap { + static constexpr size_t MAP_HEADER_SIZE = 12; + static constexpr size_t NODE_SIZE = 6; + static constexpr size_t EDGE_SIZE = 3; + static constexpr size_t FOOTER_V1_SIZE = 24; + static constexpr size_t FOOTER_V2_SIZE = 40; + + const uint8_t* _nodes = nullptr; + const uint8_t* _edges = nullptr; + uint16_t _node_count = 0; + uint16_t _edge_count = 0; + + static uint16_t read16(const uint8_t* p) { + return (uint16_t)p[0] | ((uint16_t)p[1] << 8); + } + + static uint32_t read32(const uint8_t* p) { + return (uint32_t)p[0] + | ((uint32_t)p[1] << 8) + | ((uint32_t)p[2] << 16) + | ((uint32_t)p[3] << 24); + } + + static uint32_t crc32(const uint8_t* data, size_t size) { + uint32_t crc = 0xFFFFFFFFUL; + for (size_t i = 0; i < size; ++i) { + crc ^= data[i]; + for (uint8_t bit = 0; bit < 8; ++bit) { + crc = (crc >> 1) ^ (0xEDB88320UL & (0U - (crc & 1U))); + } + } + return ~crc; + } + + const uint8_t* node(uint16_t index) const { + return _nodes + (size_t)index * NODE_SIZE; + } + + const uint8_t* edge(uint16_t index) const { + return _edges + (size_t)index * EDGE_SIZE; + } + + bool findChild(uint16_t node_index, uint8_t value, + uint16_t& child) const { + const uint8_t* current = node(node_index); + uint16_t first = read16(current); + uint16_t count = read16(current + 2); + uint16_t low = 0; + uint16_t high = count; + while (low < high) { + uint16_t middle = low + (high - low) / 2; + const uint8_t* candidate = edge(first + middle); + if (candidate[0] < value) { + low = middle + 1; + } else { + high = middle; + } + } + if (low >= count) return false; + const uint8_t* match = edge(first + low); + if (match[0] != value) return false; + child = read16(match + 1); + return child < _node_count; + } + +public: + void reset() { + _nodes = nullptr; + _edges = nullptr; + _node_count = 0; + _edge_count = 0; + } + + bool begin(const uint8_t* font_data, size_t font_size) { + reset(); + if (font_data == nullptr || font_size < FOOTER_V1_SIZE) return false; + + static const uint8_t FOOTER_V1_MAGIC[8] = { + 'M', 'C', 'E', 'M', 'A', 'P', '1', 0 + }; + static const uint8_t FOOTER_V2_MAGIC[8] = { + 'M', 'C', 'E', 'M', 'A', 'P', '2', 0 + }; + size_t footer_size = FOOTER_V1_SIZE; + const uint8_t* footer = font_data + font_size - footer_size; + if (font_size >= FOOTER_V2_SIZE + && memcmp(font_data + font_size - FOOTER_V2_SIZE, + FOOTER_V2_MAGIC, sizeof(FOOTER_V2_MAGIC)) == 0) { + footer_size = FOOTER_V2_SIZE; + footer = font_data + font_size - footer_size; + } else if (memcmp(footer, FOOTER_V1_MAGIC, + sizeof(FOOTER_V1_MAGIC)) != 0) { + return false; + } + + uint32_t map_offset = read32(footer + 8); + uint32_t map_size = read32(footer + 12); + uint32_t map_crc = read32(footer + 16); + if (map_offset > font_size - footer_size + || map_size > font_size - footer_size - map_offset + || map_size < MAP_HEADER_SIZE) { + return false; + } + + const uint8_t* map = font_data + map_offset; + if (crc32(map, map_size) != map_crc + || memcmp(map, "EM01", 4) != 0) { + return false; + } + + uint16_t node_count = read16(map + 4); + uint16_t edge_count = read16(map + 6); + size_t expected_size = MAP_HEADER_SIZE + + (size_t)node_count * NODE_SIZE + + (size_t)edge_count * EDGE_SIZE; + if (node_count == 0 || expected_size != map_size) return false; + + const uint8_t* nodes = map + MAP_HEADER_SIZE; + const uint8_t* edges = nodes + (size_t)node_count * NODE_SIZE; + for (uint16_t i = 0; i < node_count; ++i) { + const uint8_t* current = nodes + (size_t)i * NODE_SIZE; + uint16_t first = read16(current); + uint16_t count = read16(current + 2); + uint16_t output = read16(current + 4); + if (first > edge_count || count > edge_count - first) return false; + if (output != 0 && (output < 0xE000 || output > 0xF8FF)) return false; + int previous = -1; + for (uint16_t j = 0; j < count; ++j) { + const uint8_t* current_edge = edges + (size_t)(first + j) * EDGE_SIZE; + if (current_edge[0] <= previous + || read16(current_edge + 1) >= node_count) { + return false; + } + previous = current_edge[0]; + } + } + + _nodes = nodes; + _edges = edges; + _node_count = node_count; + _edge_count = edge_count; + return true; + } + + bool isReady() const { return _nodes != nullptr; } + + size_t longestMatch(const uint8_t* text, size_t length, + uint16_t& mapped_codepoint) const { + mapped_codepoint = 0; + if (!isReady() || text == nullptr || length == 0) return 0; + + uint16_t node_index = 0; + size_t best_length = 0; + for (size_t i = 0; i < length; ++i) { + uint16_t child; + if (!findChild(node_index, text[i], child)) break; + node_index = child; + uint16_t output = read16(node(node_index) + 4); + if (output != 0) { + mapped_codepoint = output; + best_length = i + 1; + } + } + return best_length; + } +}; + +} // namespace ui +} // namespace mesh diff --git a/src/helpers/ui/LGFXDisplay.cpp b/src/helpers/ui/LGFXDisplay.cpp index 7bdd52a2..152b469d 100644 --- a/src/helpers/ui/LGFXDisplay.cpp +++ b/src/helpers/ui/LGFXDisplay.cpp @@ -1,5 +1,108 @@ #include "LGFXDisplay.h" +#ifndef DISPLAY_ROTATION + #define DISPLAY_ROTATION 1 +#endif +#ifndef DISPLAY_BRIGHTNESS + #define DISPLAY_BRIGHTNESS 64 +#endif + +namespace { + +uint32_t readBigEndian32(const uint8_t* data) { + return ((uint32_t)data[0] << 24) + | ((uint32_t)data[1] << 16) + | ((uint32_t)data[2] << 8) + | (uint32_t)data[3]; +} + +uint32_t readLittleEndian32(const uint8_t* data) { + return (uint32_t)data[0] + | ((uint32_t)data[1] << 8) + | ((uint32_t)data[2] << 16) + | ((uint32_t)data[3] << 24); +} + +bool validateVlw(const uint8_t* data, size_t size) { + static const size_t HEADER_SIZE = 24; + static const size_t RECORD_SIZE = 28; + static const size_t FOOTER_V1_SIZE = 24; + static const size_t FOOTER_V2_SIZE = 40; + static const uint8_t FOOTER_V1_MAGIC[8] = { + 'M', 'C', 'E', 'M', 'A', 'P', '1', 0 + }; + static const uint8_t FOOTER_V2_MAGIC[8] = { + 'M', 'C', 'E', 'M', 'A', 'P', '2', 0 + }; + if (data == nullptr || size < HEADER_SIZE + FOOTER_V1_SIZE) { + return false; + } + + size_t footer_size = FOOTER_V1_SIZE; + const uint8_t* footer = data + size - footer_size; + if (size >= HEADER_SIZE + FOOTER_V2_SIZE + && memcmp(data + size - FOOTER_V2_SIZE, FOOTER_V2_MAGIC, + sizeof(FOOTER_V2_MAGIC)) == 0) { + footer_size = FOOTER_V2_SIZE; + footer = data + size - footer_size; + } else if (memcmp(footer, FOOTER_V1_MAGIC, + sizeof(FOOTER_V1_MAGIC)) != 0) { + return false; + } + + uint32_t glyph_count = readBigEndian32(data); + uint32_t map_offset = readLittleEndian32(footer + 8); + if (glyph_count == 0 || glyph_count > 10000 + || map_offset < HEADER_SIZE + || map_offset > size - footer_size + || glyph_count > (map_offset - HEADER_SIZE) / RECORD_SIZE) { + return false; + } + + size_t bitmap_offset = HEADER_SIZE + (size_t)glyph_count * RECORD_SIZE; + uint32_t previous_codepoint = 0; + for (uint32_t i = 0; i < glyph_count; ++i) { + const uint8_t* record = data + HEADER_SIZE + (size_t)i * RECORD_SIZE; + uint32_t codepoint = readBigEndian32(record); + uint32_t height = readBigEndian32(record + 4); + uint32_t width = readBigEndian32(record + 8); + uint32_t advance = readBigEndian32(record + 12); + if ((i != 0 && codepoint <= previous_codepoint) + || codepoint > 0xFFFF + || width > 64 + || height > 64 + || advance > 64 + || width > SIZE_MAX / (height == 0 ? 1 : height) + || bitmap_offset > map_offset + || width * height > map_offset - bitmap_offset) { + return false; + } + previous_codepoint = codepoint; + bitmap_offset += width * height; + } + return bitmap_offset == map_offset; +} + +LGFXDisplay* activeEmojiDisplay = nullptr; + +static const uint32_t UI_PALETTE[16] = { + 0x000000, 0xFFFFFF, 0x0000FF, 0x929292, + 0xFFAA00, 0x00FFFF, 0x0000D6, 0xE53935, + 0x43A047, 0x1E88E5, 0x8E24AA, 0xFDD835, + 0x6D4C41, 0x00ACC1, 0xF06292, 0xFF00FF, +}; + +static constexpr uint8_t TRANSPARENT_EMOJI_PALETTE_INDEX = 15; +static constexpr uint32_t TRANSPARENT_EMOJI_COLOR = 0xFF00FF; + +bool isSequence(const uint8_t* text, size_t remaining, + const uint8_t* sequence, size_t sequence_size) { + return remaining >= sequence_size + && memcmp(text, sequence, sequence_size) == 0; +} + +} // namespace + // Color scheme ColorVal UIColor::window_bkg = 0xFFFF; ColorVal UIColor::title_bkg = 0x001F; @@ -12,31 +115,44 @@ ColorVal UIColor::popup_txt = 0x0000; ColorVal UIColor::corp_blue = 0x001A; bool LGFXDisplay::begin() { - turnOn(); - display->init(); - display->setRotation(1); - display->setBrightness(64); + if (!display->init()) return false; + _isOn = true; + display->setRotation(DISPLAY_ROTATION); + display->setBrightness(DISPLAY_BRIGHTNESS); display->setColorDepth(8); display->setTextColor(TFT_WHITE); - buffer.setColorDepth(8); - buffer.setPsram(true); - buffer.createSprite(width(), height()); + buffer.setColorDepth(UI_BUFFER_COLOR_DEPTH); + // The RGB scanout framebuffer must live in PSRAM. Keep this much smaller + // logical UI sprite in internal DMA-capable RAM so page redraws do not + // compete with scanout and permanently shift the panel after an underflow. + buffer.setPsram(false); + if (buffer.createSprite(width() * UI_COORD_SCALE, + height() * UI_COORD_SCALE) == nullptr) { + return false; + } + configurePalette(); return true; } void LGFXDisplay::turnOn() { -// display->wakeup(); if (!_isOn) { - display->wakeup(); + // Keep the panel initialized while blanked so touch remains available as + // a wake source. Restoring brightness is sufficient for RGB panels. + display->setBrightness(DISPLAY_BRIGHTNESS); +#ifdef HAS_TOUCH + if (display->touch() != nullptr) display->touch()->wakeup(); +#endif } _isOn = true; } void LGFXDisplay::turnOff() { if (_isOn) { - display->sleep(); + // Do not use LGFX sleep here: a sleeping touch controller cannot provide + // the event that wakes a touch-capable UI. Blank only the backlight. + display->setBrightness(0); } _isOn = false; } @@ -44,68 +160,433 @@ void LGFXDisplay::turnOff() { void LGFXDisplay::clear() { // display->clearDisplay(); buffer.clearDisplay(); + _presentedEmojiOverlayCount = 0; + _hasLastFrame = false; } void LGFXDisplay::startFrame(ColorVal bkg) { // display->startWrite(); // display->getScanLine(); - _color = bkg; + _emojiOverlayCount = 0; + _hasTransparentEmojiPixels = false; + _color = renderColor(bkg); + buffer.setBaseColor(_color); buffer.fillScreen(_color); - buffer.setTextColor(_color = UIColor::primary_txt); + setColor(UIColor::primary_txt); } void LGFXDisplay::setTextSize(int sz) { - buffer.setTextSize(sz); + int scaled = (sz * UI_COORD_SCALE + _fontNativeScale / 2) + / _fontNativeScale; + if (scaled < 1) scaled = 1; + buffer.setTextSize(scaled); } void LGFXDisplay::setColor(ColorVal c) { - buffer.setTextColor(_color = c); + _color = renderColor(c); + // Every frame starts from a freshly cleared canvas, so transparent glyph + // backgrounds are both sufficient and unambiguous. In particular, + // primary_txt and popup_txt are both black and cannot be distinguished by + // their RGB565 value alone. + buffer.setTextColor(_color); } void LGFXDisplay::setCursor(int x, int y) { - buffer.setCursor(x, y); + buffer.setCursor(x * UI_COORD_SCALE, y * UI_COORD_SCALE); } void LGFXDisplay::print(const char* str) { - buffer.println(str); + String mapped = mapText(str); + buffer.println(mapped.c_str()); // Serial.println(str); } void LGFXDisplay::fillRect(int x, int y, int w, int h) { - buffer.fillRect(x, y, w, h, _color); + buffer.fillRect(x * UI_COORD_SCALE, y * UI_COORD_SCALE, + w * UI_COORD_SCALE, h * UI_COORD_SCALE, _color); } void LGFXDisplay::drawRect(int x, int y, int w, int h) { - buffer.drawRect(x, y, w, h, _color); + if (w <= 0 || h <= 0) return; + if (UI_COORD_SCALE == 1) { + buffer.drawRect(x, y, w, h, _color); + return; + } + int left = x * UI_COORD_SCALE; + int top = y * UI_COORD_SCALE; + int scaled_width = w * UI_COORD_SCALE; + int scaled_height = h * UI_COORD_SCALE; + buffer.fillRect(left, top, scaled_width, UI_COORD_SCALE, _color); + buffer.fillRect(left, top + scaled_height - UI_COORD_SCALE, + scaled_width, UI_COORD_SCALE, _color); + buffer.fillRect(left, top, UI_COORD_SCALE, scaled_height, _color); + buffer.fillRect(left + scaled_width - UI_COORD_SCALE, top, + UI_COORD_SCALE, scaled_height, _color); } void LGFXDisplay::drawXbm(int x, int y, const uint8_t* bits, int w, int h) { - buffer.drawBitmap(x, y, bits, w, h, _color); + if (UI_COORD_SCALE == 1) { + buffer.drawBitmap(x, y, bits, w, h, _color); + return; + } + const int row_bytes = (w + 7) / 8; + for (int row = 0; row < h; ++row) { + int column = 0; + while (column < w) { + while (column < w + && !(bits[row * row_bytes + column / 8] + & (0x80 >> (column & 7)))) { + ++column; + } + int first = column; + while (column < w + && (bits[row * row_bytes + column / 8] + & (0x80 >> (column & 7)))) { + ++column; + } + if (first != column) { + buffer.fillRect((x + first) * UI_COORD_SCALE, + (y + row) * UI_COORD_SCALE, + (column - first) * UI_COORD_SCALE, + UI_COORD_SCALE, _color); + } + } + } } uint16_t LGFXDisplay::getTextWidth(const char* str) { - return buffer.textWidth(str); + String mapped = mapText(str); + return (buffer.textWidth(mapped.c_str()) + UI_COORD_SCALE - 1) + / UI_COORD_SCALE; +} + +void LGFXDisplay::translateUTF8ToBlocks(char* dest, const char* src, + size_t dest_size) { + if (!_emojiMap.isReady()) { + DisplayDriver::translateUTF8ToBlocks(dest, src, dest_size); + return; + } + if (dest_size == 0) return; + + size_t output = 0; + for (size_t input = 0; src[input] != 0 && output + 1 < dest_size;) { + uint8_t first = (uint8_t)src[input]; + size_t length = 1; + if (first >= 0xC2 && first <= 0xDF) { + length = 2; + } else if (first >= 0xE0 && first <= 0xEF) { + length = 3; + } else if (first >= 0xF0 && first <= 0xF4) { + length = 4; + } else if (first < 32 || first > 126) { + ++input; + continue; + } + bool valid = true; + for (size_t i = 1; i < length; ++i) { + if (src[input + i] == 0 + || ((uint8_t)src[input + i] & 0xC0) != 0x80) { + valid = false; + break; + } + } + if (!valid || output + length >= dest_size) break; + memcpy(dest + output, src + input, length); + output += length; + input += length; + } + dest[output] = 0; } void LGFXDisplay::endFrame() { + uint32_t hash = frameHash(); + if (_hasLastFrame && hash == _lastFrameHash) return; + _lastFrameHash = hash; + _hasLastFrame = true; + display->startWrite(); if (UI_ZOOM != 1) { - buffer.pushRotateZoom(display, display->width()/2, display->height()/2 , 0, UI_ZOOM, UI_ZOOM); + if (_hasTransparentEmojiPixels) { + buffer.pushRotateZoom(display, display->width() / 2, + display->height() / 2, 0, UI_ZOOM, UI_ZOOM, + TRANSPARENT_EMOJI_COLOR); + } else { + buffer.pushRotateZoom(display, display->width() / 2, + display->height() / 2, 0, UI_ZOOM, UI_ZOOM); + } } else { - buffer.pushSprite(display, 0, 0); + if (_hasTransparentEmojiPixels) { + buffer.pushSprite(display, 0, 0, TRANSPARENT_EMOJI_COLOR); + } else { + buffer.pushSprite(display, 0, 0); + } + } + if (_emojiAtlas.isReady()) { + const float source_x = (_emojiAtlas.width() - 1) * 0.5f; + const float source_y = (_emojiAtlas.height() - 1) * 0.5f; + for (size_t i = 0; i < _emojiOverlayCount; ++i) { + const EmojiOverlay& overlay = _emojiOverlays[i]; + const uint8_t* pixels = _emojiAtlas.glyph(overlay.codepoint); + if (pixels == nullptr) continue; + float size = overlay.size * UI_ZOOM; + float zoom_x = size / _emojiAtlas.width(); + float zoom_y = size / _emojiAtlas.height(); + float x = overlay.x * UI_ZOOM + (size - 1) * 0.5f; + float y = overlay.y * UI_ZOOM + (size - 1) * 0.5f; + display->pushImageRotateZoom( + x, y, source_x, source_y, 0, zoom_x, zoom_y, + _emojiAtlas.width(), _emojiAtlas.height(), + reinterpret_cast(pixels), + lgfx::rgb332_t(_emojiAtlas.transparent())); + } } display->endWrite(); + + _presentedEmojiOverlayCount = _emojiOverlayCount; + memcpy(_presentedEmojiOverlays, _emojiOverlays, + _emojiOverlayCount * sizeof(EmojiOverlay)); } -bool LGFXDisplay::getTouch(int *x, int *y) { - lgfx::v1::touch_point_t point; - display->getTouch(&point); - if (UI_ZOOM != 1) { - *x = point.x / UI_ZOOM; - *y = point.y / UI_ZOOM; +bool LGFXDisplay::getTouch(int* x, int* y) { + lgfx::v1::touch_point_t point = {}; + if (display->getTouch(&point) == 0) return false; + if (UI_ZOOM * UI_COORD_SCALE != 1) { + *x = point.x / (UI_ZOOM * UI_COORD_SCALE); + *y = point.y / (UI_ZOOM * UI_COORD_SCALE); } else { *x = point.x; *y = point.y; } - return (*x >= 0) && (*y >= 0); -} \ No newline at end of file + return *x >= 0 && *x < width() && *y >= 0 && *y < height(); +} + +bool LGFXDisplay::installRuntimeFont(uint8_t* data, size_t size) { + mesh::ui::EmojiFontMap map; + mesh::ui::ColorEmojiAtlas atlas; + if (!validateVlw(data, size) + || !map.begin(data, size) + || !buffer.loadFont(data)) { + free(data); + return false; + } + + if (_fontData != nullptr) free(_fontData); + _fontData = data; + _fontDataSize = size; + _emojiMap = map; + if (atlas.begin(data, size)) { + _emojiAtlas = atlas; + _fontNativeScale = atlas.textScale(); + activeEmojiDisplay = this; + buffer.setEmojiCallback(drawEmoji); + } else { + _emojiAtlas.reset(); + _fontNativeScale = 1; + buffer.setEmojiCallback(nullptr); + if (activeEmojiDisplay == this) activeEmojiDisplay = nullptr; + } + return true; +} + +uint32_t LGFXDisplay::renderColor(ColorVal color) const { +#if UI_BUFFER_COLOR_DEPTH < 8 + if (color == UIColor::primary_txt) return 0; + if (color == UIColor::window_bkg || color == UIColor::title_txt) return 1; + if (color == UIColor::title_bkg) return 2; + if (color == UIColor::secondary_txt) return 3; + if (color == UIColor::warning_txt) return 4; + if (color == UIColor::popup_bkg) return 5; + if (color == UIColor::popup_txt) return 0; + if (color == UIColor::corp_blue) return 6; + return color & 0x0F; +#else + return color; +#endif +} + +void LGFXDisplay::configurePalette() { +#if UI_BUFFER_COLOR_DEPTH < 8 + buffer.createPalette(UI_PALETTE, + sizeof(UI_PALETTE) / sizeof(UI_PALETTE[0])); +#endif +} + +uint32_t LGFXDisplay::frameHash() const { + const uint8_t* data = static_cast(buffer.getBuffer()); + size_t length = buffer.bufferLength(); + uint32_t hash = 2166136261UL; + for (size_t i = 0; i < length; ++i) { + hash = (hash ^ data[i]) * 16777619UL; + } + for (size_t i = 0; i < _emojiOverlayCount; ++i) { + const EmojiOverlay& overlay = _emojiOverlays[i]; + const uint16_t values[] = { + overlay.codepoint, + static_cast(overlay.x), + static_cast(overlay.y), + overlay.size, + }; + for (uint16_t value : values) { + hash = (hash ^ static_cast(value)) * 16777619UL; + hash = (hash ^ static_cast(value >> 8)) * 16777619UL; + } + } + return hash; +} + +bool LGFXDisplay::wasEmojiPresented(const EmojiOverlay& overlay) const { + for (size_t i = 0; i < _presentedEmojiOverlayCount; ++i) { + const EmojiOverlay& presented = _presentedEmojiOverlays[i]; + if (presented.codepoint == overlay.codepoint + && presented.x == overlay.x + && presented.y == overlay.y + && presented.size == overlay.size) { + return true; + } + } + return false; +} + +void LGFXDisplay::drawEmojiMask(int32_t x, int32_t y, int32_t size, + const uint8_t* pixels) { +#if UI_BUFFER_COLOR_DEPTH < 8 + if (pixels == nullptr || size <= 0) return; + const int source_width = _emojiAtlas.width(); + const int source_height = _emojiAtlas.height(); + const uint8_t transparent = _emojiAtlas.transparent(); + for (int source_y = 0; source_y < source_height; ++source_y) { + int top = y + source_y * size / source_height; + int bottom = y + (source_y + 1) * size / source_height; + for (int source_x = 0; source_x < source_width; ++source_x) { + if (pixels[source_y * source_width + source_x] == transparent) continue; + int left = x + source_x * size / source_width; + int right = x + (source_x + 1) * size / source_width; + buffer.fillRect(left, top, right - left, bottom - top, + TRANSPARENT_EMOJI_PALETTE_INDEX); + } + } + _hasTransparentEmojiPixels = true; +#else + (void)x; + (void)y; + (void)size; + (void)pixels; +#endif +} + +void LGFXDisplay::drawEmojiUnderlay(int32_t x, int32_t y, int32_t size, + const uint8_t* pixels) { +#if UI_BUFFER_COLOR_DEPTH < 8 + if (pixels == nullptr || size <= 0) return; + const int source_width = _emojiAtlas.width(); + const int source_height = _emojiAtlas.height(); + const uint8_t transparent = _emojiAtlas.transparent(); + for (int source_y = 0; source_y < source_height; ++source_y) { + int top = y + source_y * size / source_height; + int bottom = y + (source_y + 1) * size / source_height; + for (int source_x = 0; source_x < source_width; ++source_x) { + uint8_t color = pixels[source_y * source_width + source_x]; + if (color == transparent) continue; + int red = ((color >> 5) & 7) * 255 / 7; + int green = ((color >> 2) & 7) * 255 / 7; + int blue = (color & 3) * 255 / 3; + int best_index = 0; + uint32_t best_distance = UINT32_MAX; + // The final palette entry is reserved as the transparent color used to + // preserve an unchanged full-color emoji in the panel framebuffer. + for (int index = 0; index < TRANSPARENT_EMOJI_PALETTE_INDEX; ++index) { + int delta_red = red - (int)((UI_PALETTE[index] >> 16) & 0xFF); + int delta_green = green - (int)((UI_PALETTE[index] >> 8) & 0xFF); + int delta_blue = blue - (int)(UI_PALETTE[index] & 0xFF); + uint32_t distance = delta_red * delta_red + + delta_green * delta_green + delta_blue * delta_blue; + if (distance < best_distance) { + best_distance = distance; + best_index = index; + } + } + int left = x + source_x * size / source_width; + int right = x + (source_x + 1) * size / source_width; + buffer.fillRect(left, top, right - left, bottom - top, best_index); + } + } +#else + (void)x; + (void)y; + (void)size; + (void)pixels; +#endif +} + +int32_t LGFXDisplay::queueEmoji(lgfx::v1::LGFXBase* gfx, + int32_t x, int32_t y, + uint32_t codepoint, + int32_t font_height) { + if (gfx != &buffer || codepoint > 0xFFFF || font_height <= 0 + || _emojiAtlas.glyph((uint16_t)codepoint) == nullptr) { + return 0; + } + if (_emojiOverlayCount >= MAX_EMOJI_OVERLAYS) return font_height; + + EmojiOverlay& overlay = _emojiOverlays[_emojiOverlayCount++]; + overlay.codepoint = (uint16_t)codepoint; + overlay.x = x; + overlay.y = y; + overlay.size = (uint16_t)font_height; + const uint8_t* pixels = _emojiAtlas.glyph(overlay.codepoint); + if (wasEmojiPresented(overlay)) { + // Do not overwrite an unchanged full-color emoji with the indexed canvas + // during periodic message-age redraws. The following direct overlay is + // then idempotent instead of visibly blinking once per second. + drawEmojiMask(x, y, font_height, pixels); + } else { + drawEmojiUnderlay(x, y, font_height, pixels); + } + return font_height; +} + +int32_t LGFXDisplay::drawEmoji(lgfx::v1::LGFXBase* gfx, + int32_t x, int32_t y, + uint32_t codepoint, + int32_t font_height) { + if (activeEmojiDisplay == nullptr) return 0; + return activeEmojiDisplay->queueEmoji(gfx, x, y, codepoint, font_height); +} + +String LGFXDisplay::mapText(const char* str) const { + if (str == nullptr || !_emojiMap.isReady()) return String(str == nullptr ? "" : str); + + const uint8_t* text = (const uint8_t*)str; + size_t length = strlen(str); + String mapped; + mapped.reserve(length + 8); + static const uint8_t VS15[] = {0xEF, 0xB8, 0x8E}; + static const uint8_t VS16[] = {0xEF, 0xB8, 0x8F}; + static const uint8_t ZWJ[] = {0xE2, 0x80, 0x8D}; + + for (size_t offset = 0; offset < length;) { + uint16_t codepoint; + size_t match = _emojiMap.longestMatch(text + offset, length - offset, codepoint); + if (match != 0) { + mapped += (char)(0xE0 | (codepoint >> 12)); + mapped += (char)(0x80 | ((codepoint >> 6) & 0x3F)); + mapped += (char)(0x80 | (codepoint & 0x3F)); + offset += match; + continue; + } + if (text[offset] == ' ') { + mapped += (char)0xC2; + mapped += (char)0xA0; + ++offset; + continue; + } + if (isSequence(text + offset, length - offset, VS15, sizeof(VS15)) + || isSequence(text + offset, length - offset, VS16, sizeof(VS16)) + || isSequence(text + offset, length - offset, ZWJ, sizeof(ZWJ))) { + offset += 3; + continue; + } + mapped += (char)text[offset++]; + } + return mapped; +} diff --git a/src/helpers/ui/LGFXDisplay.h b/src/helpers/ui/LGFXDisplay.h index a2d660b2..a1291841 100644 --- a/src/helpers/ui/LGFXDisplay.h +++ b/src/helpers/ui/LGFXDisplay.h @@ -1,6 +1,8 @@ #pragma once #include +#include +#include #define LGFX_USE_V1 #include @@ -8,6 +10,12 @@ #ifndef UI_ZOOM #define UI_ZOOM 1 #endif +#ifndef UI_COORD_SCALE + #define UI_COORD_SCALE 1 +#endif +#ifndef UI_BUFFER_COLOR_DEPTH + #define UI_BUFFER_COLOR_DEPTH 8 +#endif class LGFXDisplay : public DisplayDriver { protected: @@ -16,10 +24,45 @@ protected: bool _isOn = false; int _color = TFT_WHITE; + uint8_t* _fontData = nullptr; + size_t _fontDataSize = 0; + mesh::ui::EmojiFontMap _emojiMap; + mesh::ui::ColorEmojiAtlas _emojiAtlas; + uint8_t _fontNativeScale = 1; + + struct EmojiOverlay { + uint16_t codepoint; + int16_t x; + int16_t y; + uint16_t size; + }; + static constexpr size_t MAX_EMOJI_OVERLAYS = 64; + EmojiOverlay _emojiOverlays[MAX_EMOJI_OVERLAYS]; + size_t _emojiOverlayCount = 0; + EmojiOverlay _presentedEmojiOverlays[MAX_EMOJI_OVERLAYS]; + size_t _presentedEmojiOverlayCount = 0; + bool _hasTransparentEmojiPixels = false; + uint32_t _lastFrameHash = 0; + bool _hasLastFrame = false; + + String mapText(const char* str) const; + uint32_t renderColor(ColorVal color) const; + void configurePalette(); + uint32_t frameHash() const; + bool wasEmojiPresented(const EmojiOverlay& overlay) const; + void drawEmojiMask(int32_t x, int32_t y, int32_t size, + const uint8_t* pixels); + void drawEmojiUnderlay(int32_t x, int32_t y, int32_t size, + const uint8_t* pixels); + int32_t queueEmoji(lgfx::v1::LGFXBase* gfx, int32_t x, int32_t y, + uint32_t codepoint, int32_t font_height); + static int32_t drawEmoji(lgfx::v1::LGFXBase* gfx, int32_t x, int32_t y, + uint32_t codepoint, int32_t font_height); public: LGFXDisplay(int w, int h, LGFX_Device &disp) - : DisplayDriver(w/UI_ZOOM, h/UI_ZOOM), display(&disp) {} + : DisplayDriver(w/(UI_ZOOM*UI_COORD_SCALE), + h/(UI_ZOOM*UI_COORD_SCALE)), display(&disp) {} bool begin(); bool isOn() override { return _isOn; } void turnOn() override; @@ -34,6 +77,9 @@ public: void drawRect(int x, int y, int w, int h) override; void drawXbm(int x, int y, const uint8_t* bits, int w, int h) override; uint16_t getTextWidth(const char* str) override; + void translateUTF8ToBlocks(char* dest, const char* src, + size_t dest_size) override; void endFrame() override; - virtual bool getTouch(int *x, int *y); + bool getTouch(int* x, int* y) override; + bool installRuntimeFont(uint8_t* data, size_t size); }; diff --git a/src/helpers/ui/TouchInput.h b/src/helpers/ui/TouchInput.h new file mode 100644 index 00000000..207733ab --- /dev/null +++ b/src/helpers/ui/TouchInput.h @@ -0,0 +1,135 @@ +#pragma once + +#include + +namespace mesh { +namespace ui { + +enum class TouchAction : uint8_t { + None, + Previous, + Next, + Select, + VerticalPrevious, + VerticalNext, +}; + +// Converts one-finger touch samples into the three actions understood by the +// button-oriented companion UI. An action is emitted only after release so a +// drag cannot activate the page under the user's finger. +class TouchInput { + bool _active = false; + bool _reverse_swipes; + bool _separate_vertical_swipes; + uint8_t _center_zone_percent; + uint8_t _touch_samples = 0; + uint8_t _release_samples = 0; + int _start_x = 0; + int _start_y = 0; + int _last_x = 0; + int _last_y = 0; + + static int magnitude(int value) { return value < 0 ? -value : value; } + + TouchAction swipeAction(bool negative_direction) const { + const bool next = negative_direction != _reverse_swipes; + return next ? TouchAction::Next : TouchAction::Previous; + } + + TouchAction verticalSwipeAction(bool negative_direction) const { + if (!_separate_vertical_swipes) return swipeAction(negative_direction); + const bool next = negative_direction != _reverse_swipes; + return next ? TouchAction::VerticalNext + : TouchAction::VerticalPrevious; + } + +public: + explicit TouchInput(bool reverse_swipes = false, + bool separate_vertical_swipes = false, + uint8_t center_zone_percent = 34) + : _reverse_swipes(reverse_swipes), + _separate_vertical_swipes(separate_vertical_swipes), + _center_zone_percent(center_zone_percent > 100 + ? 100 + : center_zone_percent) {} + + TouchAction update(bool touched, int x, int y, int width, int height, + bool bottom_selector = false) { + if (touched) { + _release_samples = 0; + if (!_active) { + _active = true; + _start_x = x; + _start_y = y; + _touch_samples = 0; + } + if (_touch_samples != UINT8_MAX) ++_touch_samples; + _last_x = x; + _last_y = y; + return TouchAction::None; + } + + if (!_active) return TouchAction::None; + // A moving FT5x06-family controller can briefly report no points between + // two valid samples. Require a stable release so that gap cannot split one + // swipe into a swipe followed by an endpoint tap. + if (++_release_samples < 2) return TouchAction::None; + _active = false; + _release_samples = 0; + + // A contact seen only once has no measurable direction. Ignoring it is + // safer than treating the endpoint of a fast swipe as an opposite tap. + if (_touch_samples < 2 || width <= 0 || height <= 0) { + return TouchAction::None; + } + + const int dx = _last_x - _start_x; + const int dy = _last_y - _start_y; + const int abs_dx = magnitude(dx); + const int abs_dy = magnitude(dy); + const int horizontal_threshold = width / 8 > 8 ? width / 8 : 8; + const int vertical_threshold = height / 8 > 8 ? height / 8 : 8; + + if (abs_dx >= abs_dy && abs_dx >= horizontal_threshold) { + return swipeAction(dx < 0); + } + if (abs_dy > abs_dx && abs_dy >= vertical_threshold) { + return verticalSwipeAction(dy < 0); + } + + // Message screens may reserve the otherwise empty ends of their bottom + // status bar as forgiving arrow buttons. Keep the label in the middle + // inert so an imprecise arrow tap cannot accidentally close the screen. + if (bottom_selector && _separate_vertical_swipes + && _start_y >= (height * 3) / 4) { + if (_start_x < width / 4) { + return TouchAction::VerticalPrevious; + } + if (_start_x >= (width * 3) / 4) { + return TouchAction::VerticalNext; + } + return TouchAction::None; + } + + // Taps use three broad zones so every companion action remains available: + // left = previous, center = select, right = next. + // Use the initial position for a tap. If a short swipe falls just below + // the movement threshold, its endpoint may be in the opposite tap zone on + // displays whose touch X axis is inverted. + const int side_percent = (100 - _center_zone_percent) / 2; + const int center_left = (width * side_percent) / 100; + const int center_right = width - center_left; + if (_start_x < center_left) return TouchAction::Previous; + if (_start_x >= center_right) return TouchAction::Next; + return TouchAction::Select; + } + + void reset() { + _active = false; + _touch_samples = 0; + _release_samples = 0; + } +}; + +} // namespace ui +} // namespace mesh diff --git a/test/test_color_emoji_atlas/test_color_emoji_atlas.cpp b/test/test_color_emoji_atlas/test_color_emoji_atlas.cpp new file mode 100644 index 00000000..3fa2519b --- /dev/null +++ b/test/test_color_emoji_atlas/test_color_emoji_atlas.cpp @@ -0,0 +1,93 @@ +#include + +#include + +#include +#include + +using mesh::ui::ColorEmojiAtlas; + +namespace { + +void append16(std::vector& data, uint16_t value) { + data.push_back((uint8_t)value); + data.push_back((uint8_t)(value >> 8)); +} + +void append32(std::vector& data, uint32_t value) { + data.push_back((uint8_t)value); + data.push_back((uint8_t)(value >> 8)); + data.push_back((uint8_t)(value >> 16)); + data.push_back((uint8_t)(value >> 24)); +} + +uint32_t crc32(const uint8_t* data, size_t size) { + uint32_t crc = 0xFFFFFFFFUL; + for (size_t i = 0; i < size; ++i) { + crc ^= data[i]; + for (uint8_t bit = 0; bit < 8; ++bit) { + crc = (crc >> 1) ^ (0xEDB88320UL & (0U - (crc & 1U))); + } + } + return ~crc; +} + +std::vector sampleFont() { + std::vector font(24, 0x55); + const uint32_t map_offset = font.size(); + std::vector map = { + 'E', 'M', '0', '1', 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, + }; + font.insert(font.end(), map.begin(), map.end()); + + const uint32_t atlas_offset = font.size(); + std::vector atlas = { + 'C', 'E', '0', '1', + 2, 0, 2, 2, 0xE3, 3, 4, 0, + 1, 2, 3, 4, + 5, 6, 7, 8, + }; + font.insert(font.end(), atlas.begin(), atlas.end()); + + font.insert(font.end(), {'M', 'C', 'E', 'M', 'A', 'P', '2', 0}); + append32(font, map_offset); + append32(font, map.size()); + append32(font, crc32(map.data(), map.size())); + append32(font, atlas_offset); + append32(font, atlas.size()); + append32(font, crc32(atlas.data(), atlas.size())); + append32(font, 0); + append32(font, 0); + return font; +} + +} // namespace + +TEST(ColorEmojiAtlas, ReadsGlyphsAndMetrics) { + std::vector font = sampleFont(); + ColorEmojiAtlas atlas; + ASSERT_TRUE(atlas.begin(font.data(), font.size())); + EXPECT_EQ(2, atlas.width()); + EXPECT_EQ(2, atlas.height()); + EXPECT_EQ(3, atlas.textScale()); + EXPECT_EQ(0xE3, atlas.transparent()); + ASSERT_NE(nullptr, atlas.glyph(0xE000)); + EXPECT_EQ(1, atlas.glyph(0xE000)[0]); + EXPECT_EQ(8, atlas.glyph(0xE001)[3]); + EXPECT_EQ(nullptr, atlas.glyph(0xDFFF)); + EXPECT_EQ(nullptr, atlas.glyph(0xE002)); +} + +TEST(ColorEmojiAtlas, RejectsCorruptAtlas) { + std::vector font = sampleFont(); + font[50] ^= 0x80; + ColorEmojiAtlas atlas; + EXPECT_FALSE(atlas.begin(font.data(), font.size())); + EXPECT_FALSE(atlas.isReady()); +} + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/test/test_display_driver/test_display_driver.cpp b/test/test_display_driver/test_display_driver.cpp new file mode 100644 index 00000000..1d88f0f2 --- /dev/null +++ b/test/test_display_driver/test_display_driver.cpp @@ -0,0 +1,83 @@ +#include + +#include + +#include + +namespace { + +bool isValidUTF8(const char* text) { + for (size_t offset = 0; text[offset] != 0;) { + uint8_t first = (uint8_t)text[offset]; + size_t length = 1; + if (first >= 0xC2 && first <= 0xDF) { + length = 2; + } else if (first >= 0xE0 && first <= 0xEF) { + length = 3; + } else if (first >= 0xF0 && first <= 0xF4) { + length = 4; + } else if (first >= 0x80) { + return false; + } + for (size_t i = 1; i < length; ++i) { + if (text[offset + i] == 0 + || ((uint8_t)text[offset + i] & 0xC0) != 0x80) { + return false; + } + } + offset += length; + } + return true; +} + +class TestDisplay : public DisplayDriver { +public: + std::string printed; + + TestDisplay() : DisplayDriver(100, 100) {} + + bool isOn() override { return true; } + void turnOn() override {} + void turnOff() override {} + void clear() override {} + void startFrame(ColorVal) override {} + void setTextSize(int) override {} + void setColor(ColorVal) override {} + void setCursor(int, int) override {} + void print(const char* str) override { printed = str; } + void fillRect(int, int, int, int) override {} + void drawRect(int, int, int, int) override {} + void drawXbm(int, int, const uint8_t*, int, int) override {} + uint16_t getTextWidth(const char* str) override { + uint16_t width = 0; + for (size_t i = 0; str[i] != 0; ++i) { + if (((uint8_t)str[i] & 0xC0) != 0x80) ++width; + } + return width; + } + void endFrame() override {} +}; + +} // namespace + +TEST(DisplayDriver, EllipsizesOnlyAtUTF8CodepointBoundaries) { + TestDisplay display; + display.drawTextEllipsized(0, 0, 5, "AB\xF0\x9F\x98\x80" "CDE"); + EXPECT_EQ("AB...", display.printed); + EXPECT_TRUE(isValidUTF8(display.printed.c_str())); +} + +TEST(DisplayDriver, FixedBufferDoesNotSplitUTF8Codepoint) { + TestDisplay display; + std::string text(254, 'A'); + text += "\xF0\x9F\x98\x80"; + text += 'B'; + display.drawTextEllipsized(0, 0, 255, text.c_str()); + EXPECT_EQ(std::string(254, 'A'), display.printed); + EXPECT_TRUE(isValidUTF8(display.printed.c_str())); +} + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/test/test_emoji_font_map/test_emoji_font_map.cpp b/test/test_emoji_font_map/test_emoji_font_map.cpp new file mode 100644 index 00000000..36c16959 --- /dev/null +++ b/test/test_emoji_font_map/test_emoji_font_map.cpp @@ -0,0 +1,131 @@ +#include + +#include + +#include +#include +#include + +using mesh::ui::EmojiFontMap; + +namespace { + +void append16(std::vector& data, uint16_t value) { + data.push_back((uint8_t)value); + data.push_back((uint8_t)(value >> 8)); +} + +void append32(std::vector& data, uint32_t value) { + data.push_back((uint8_t)value); + data.push_back((uint8_t)(value >> 8)); + data.push_back((uint8_t)(value >> 16)); + data.push_back((uint8_t)(value >> 24)); +} + +uint32_t crc32(const uint8_t* data, size_t size) { + uint32_t crc = 0xFFFFFFFFUL; + for (size_t i = 0; i < size; ++i) { + crc ^= data[i]; + for (uint8_t bit = 0; bit < 8; ++bit) { + crc = (crc >> 1) ^ (0xEDB88320UL & (0U - (crc & 1U))); + } + } + return ~crc; +} + +std::vector sampleFont() { + std::vector font(32, 0x55); + const uint32_t map_offset = font.size(); + std::vector map; + map.insert(map.end(), {'E', 'M', '0', '1'}); + append16(map, 6); // nodes + append16(map, 5); // edges + append32(map, 0); + + // Root: F0 -> 1 + append16(map, 0); append16(map, 1); append16(map, 0); + // F0: 9F -> 2 + append16(map, 1); append16(map, 1); append16(map, 0); + // F0 9F: 98 -> 3 + append16(map, 2); append16(map, 1); append16(map, 0); + // F0 9F 98: 80 -> 4 + append16(map, 3); append16(map, 1); append16(map, 0); + // Grinning face, also prefix of the test sequence below. + append16(map, 4); append16(map, 1); append16(map, 0xE000); + // Grinning face followed by '!'. + append16(map, 5); append16(map, 0); append16(map, 0xE001); + + map.push_back(0xF0); append16(map, 1); + map.push_back(0x9F); append16(map, 2); + map.push_back(0x98); append16(map, 3); + map.push_back(0x80); append16(map, 4); + map.push_back('!'); append16(map, 5); + + font.insert(font.end(), map.begin(), map.end()); + font.insert(font.end(), {'M', 'C', 'E', 'M', 'A', 'P', '1', 0}); + append32(font, map_offset); + append32(font, map.size()); + append32(font, crc32(map.data(), map.size())); + append32(font, 0); + return font; +} + +std::vector sampleVersion2Font() { + std::vector font = sampleFont(); + font.resize(font.size() - 24); + const uint32_t map_offset = 32; + const uint32_t map_size = font.size() - map_offset; + const uint32_t map_crc = crc32(font.data() + map_offset, map_size); + font.insert(font.end(), {'M', 'C', 'E', 'M', 'A', 'P', '2', 0}); + append32(font, map_offset); + append32(font, map_size); + append32(font, map_crc); + for (int i = 0; i < 5; ++i) append32(font, 0); + return font; +} + +} // namespace + +TEST(EmojiFontMap, UsesLongestSequenceMatch) { + std::vector font = sampleFont(); + EmojiFontMap map; + ASSERT_TRUE(map.begin(font.data(), font.size())); + + const uint8_t text[] = {0xF0, 0x9F, 0x98, 0x80, '!', 'x'}; + uint16_t output = 0; + EXPECT_EQ(5U, map.longestMatch(text, sizeof(text), output)); + EXPECT_EQ(0xE001, output); + + EXPECT_EQ(4U, map.longestMatch(text, 4, output)); + EXPECT_EQ(0xE000, output); +} + +TEST(EmojiFontMap, RejectsCorruptMappingData) { + std::vector font = sampleFont(); + font[40] ^= 0x80; + EmojiFontMap map; + EXPECT_FALSE(map.begin(font.data(), font.size())); + EXPECT_FALSE(map.isReady()); +} + +TEST(EmojiFontMap, RejectsMissingFooter) { + uint8_t data[64] = {}; + EmojiFontMap map; + EXPECT_FALSE(map.begin(data, sizeof(data))); +} + +TEST(EmojiFontMap, AcceptsVersion2Footer) { + std::vector font = sampleVersion2Font(); + EmojiFontMap map; + ASSERT_TRUE(map.begin(font.data(), font.size())); + + const uint8_t text[] = {0xF0, 0x9F, 0x98, 0x80}; + uint16_t output = 0; + EXPECT_EQ(sizeof(text), map.longestMatch(text, sizeof(text), output)); + EXPECT_EQ(0xE000, output); +} + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/test/test_touch_input/test_touch_input.cpp b/test/test_touch_input/test_touch_input.cpp new file mode 100644 index 00000000..bd968156 --- /dev/null +++ b/test/test_touch_input/test_touch_input.cpp @@ -0,0 +1,181 @@ +#include + +#include + +using mesh::ui::TouchAction; +using mesh::ui::TouchInput; + +namespace { + +TouchAction release(TouchInput& input, int width = 137, int height = 137) { + EXPECT_EQ(input.update(false, -1, -1, width, height), TouchAction::None); + return input.update(false, -1, -1, width, height); +} + +} // namespace + +TEST(TouchInput, EmitsOnlyAfterRelease) { + TouchInput input; + EXPECT_EQ(input.update(true, 70, 50, 137, 137), TouchAction::None); + EXPECT_EQ(input.update(true, 72, 51, 137, 137), TouchAction::None); + EXPECT_EQ(release(input), TouchAction::Select); + EXPECT_EQ(input.update(false, -1, -1, 137, 137), TouchAction::None); +} + +TEST(TouchInput, MapsTapZonesToAllActions) { + TouchInput input; + + input.update(true, 10, 60, 137, 137); + input.update(true, 10, 60, 137, 137); + EXPECT_EQ(release(input), TouchAction::Previous); + + input.update(true, 68, 60, 137, 137); + input.update(true, 68, 60, 137, 137); + EXPECT_EQ(release(input), TouchAction::Select); + + input.update(true, 125, 60, 137, 137); + input.update(true, 125, 60, 137, 137); + EXPECT_EQ(release(input), TouchAction::Next); +} + +TEST(TouchInput, CanUseAWiderCenterTapZone) { + TouchInput input(false, false, 70); + + input.update(true, 25, 60, 137, 137); + input.update(true, 25, 60, 137, 137); + EXPECT_EQ(release(input), TouchAction::Select); + + input.update(true, 10, 60, 137, 137); + input.update(true, 10, 60, 137, 137); + EXPECT_EQ(release(input), TouchAction::Previous); + + input.update(true, 127, 60, 137, 137); + input.update(true, 127, 60, 137, 137); + EXPECT_EQ(release(input), TouchAction::Next); +} + +TEST(TouchInput, MapsHorizontalSwipesToPageNavigation) { + TouchInput input; + + input.update(true, 110, 60, 137, 137); + input.update(true, 40, 62, 137, 137); + EXPECT_EQ(release(input), TouchAction::Next); + + input.update(true, 30, 60, 137, 137); + input.update(true, 105, 58, 137, 137); + EXPECT_EQ(release(input), TouchAction::Previous); +} + +TEST(TouchInput, MapsVerticalSwipesToPageNavigation) { + TouchInput input; + + input.update(true, 60, 110, 137, 137); + input.update(true, 62, 35, 137, 137); + EXPECT_EQ(release(input), TouchAction::Next); + + input.update(true, 60, 25, 137, 137); + input.update(true, 58, 105, 137, 137); + EXPECT_EQ(release(input), TouchAction::Previous); +} + +TEST(TouchInput, CanRouteVerticalSwipesToASeparateSelector) { + TouchInput input(true, true); + + input.update(true, 60, 110, 137, 137); + input.update(true, 62, 35, 137, 137); + EXPECT_EQ(release(input), TouchAction::VerticalPrevious); + + input.update(true, 60, 25, 137, 137); + input.update(true, 58, 105, 137, 137); + EXPECT_EQ(release(input), TouchAction::VerticalNext); + + input.update(true, 110, 60, 137, 137); + input.update(true, 40, 62, 137, 137); + EXPECT_EQ(release(input), TouchAction::Previous); +} + +TEST(TouchInput, BottomSelectorHasLargeArrowTapTargets) { + TouchInput input(true, true, 70); + + input.update(true, 15, 125, 137, 137, true); + input.update(true, 15, 125, 137, 137, true); + EXPECT_EQ(input.update(false, -1, -1, 137, 137, true), + TouchAction::None); + EXPECT_EQ(input.update(false, -1, -1, 137, 137, true), + TouchAction::VerticalPrevious); + + input.update(true, 122, 125, 137, 137, true); + input.update(true, 122, 125, 137, 137, true); + EXPECT_EQ(input.update(false, -1, -1, 137, 137, true), + TouchAction::None); + EXPECT_EQ(input.update(false, -1, -1, 137, 137, true), + TouchAction::VerticalNext); + + input.update(true, 68, 125, 137, 137, true); + input.update(true, 68, 125, 137, 137, true); + EXPECT_EQ(input.update(false, -1, -1, 137, 137, true), + TouchAction::None); + EXPECT_EQ(input.update(false, -1, -1, 137, 137, true), + TouchAction::None); +} + +TEST(TouchInput, CanReverseSwipesWithoutReversingTapZones) { + TouchInput input(true); + + input.update(true, 110, 60, 137, 137); + input.update(true, 40, 62, 137, 137); + EXPECT_EQ(release(input), TouchAction::Previous); + + input.update(true, 30, 60, 137, 137); + input.update(true, 105, 58, 137, 137); + EXPECT_EQ(release(input), TouchAction::Next); + + input.update(true, 10, 60, 137, 137); + input.update(true, 10, 60, 137, 137); + EXPECT_EQ(release(input), TouchAction::Previous); + + input.update(true, 125, 60, 137, 137); + input.update(true, 125, 60, 137, 137); + EXPECT_EQ(release(input), TouchAction::Next); +} + +TEST(TouchInput, KeepsGestureAcrossOneMissingTouchSample) { + TouchInput input; + + input.update(true, 110, 60, 137, 137); + input.update(true, 80, 61, 137, 137); + EXPECT_EQ(input.update(false, -1, -1, 137, 137), TouchAction::None); + input.update(true, 40, 62, 137, 137); + EXPECT_EQ(release(input), TouchAction::Next); +} + +TEST(TouchInput, IgnoresContactWithNoDirectionSample) { + TouchInput input; + + input.update(true, 120, 60, 137, 137); + EXPECT_EQ(release(input), TouchAction::None); +} + +TEST(TouchInput, UsesStartZoneForShortAmbiguousMovement) { + TouchInput input(true); + + input.update(true, 40, 60, 137, 137); + input.update(true, 52, 60, 137, 137); + EXPECT_EQ(release(input), TouchAction::Previous); +} + +TEST(TouchInput, RepeatedSwipesKeepTheSameDirection) { + TouchInput input(true); + + for (int attempt = 0; attempt < 10; ++attempt) { + input.update(true, 110, 60, 137, 137); + input.update(true, 72, 61, 137, 137); + input.update(true, 35, 62, 137, 137); + EXPECT_EQ(release(input), TouchAction::Previous); + } +} + +int main(int argc, char** argv) { + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/tools/sensecap_indicator_font/OFL-1.1.txt b/tools/sensecap_indicator_font/OFL-1.1.txt new file mode 100644 index 00000000..e03b82db --- /dev/null +++ b/tools/sensecap_indicator_font/OFL-1.1.txt @@ -0,0 +1,94 @@ +Copyright 2013 Google LLC +Copyright 2022 The Noto Project Authors (https://github.com/notofonts/latin-greek-cyrillic) + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +https://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font Software, +subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/tools/sensecap_indicator_font/README.md b/tools/sensecap_indicator_font/README.md new file mode 100644 index 00000000..6c9cf7a4 --- /dev/null +++ b/tools/sensecap_indicator_font/README.md @@ -0,0 +1,35 @@ +# SenseCAP Indicator SD font + +`generate_font.py` creates the native-resolution font used by the SenseCAP +Indicator. Text is Noto Sans Mono Bold rendered into an 18x24 monospaced cell. +Every text pixel is binary (`0` or `255`), so the font remains sharp and has no +antialiasing. + +The complete Unicode Emoji 17.0 RGI set is rendered from Noto Color Emoji into +12x12 RGB332 cells. Transparency is binary, and each cell is enlarged 2x with +nearest-neighbor scaling for a crisp 24x24 result on the 480x480 panel. Emoji +sequences are mapped into the BMP private-use range by a trie appended to the +font file because the display library's runtime font interface accepts 16-bit +glyph identifiers. The private-use glyph is intercepted at draw time and the +corresponding color cell is overlaid after the UI canvas is copied. +On later UI refreshes, unchanged emoji pixels are excluded from the indexed +canvas transfer. This preserves the already-presented color cell and avoids a +visible fallback-to-color flash. + +The generated `ui-font.vlw` is stored on the Indicator's SD card. The RP2040 +font service streams it to the ESP32-S3 at boot; the application falls back to +its built-in font if the card, service, file, checksum, or mapping is invalid. + +To reproduce the checked-in asset: + +```bash +python3 -m venv /tmp/meshcore-font-venv +/tmp/meshcore-font-venv/bin/pip install -r tools/sensecap_indicator_font/requirements.txt +/tmp/meshcore-font-venv/bin/python tools/sensecap_indicator_font/generate_font.py \ + --output variants/sensecap_indicator-espnow/sd/ui-font.vlw \ + --preview /tmp/meshcore-indicator-font-preview.png +``` + +The source fonts are licensed under the SIL Open Font License 1.1; see +`OFL-1.1.txt`. The Unicode data source, pinned color-font revision, and exact +input hashes are recorded in the generated JSON manifest. diff --git a/tools/sensecap_indicator_font/generate_font.py b/tools/sensecap_indicator_font/generate_font.py new file mode 100644 index 00000000..5be95d64 --- /dev/null +++ b/tools/sensecap_indicator_font/generate_font.py @@ -0,0 +1,459 @@ +#!/usr/bin/env python3 +"""Build the Indicator's native-resolution text and color emoji font.""" + +from __future__ import annotations + +import argparse +import hashlib +import json +import struct +import urllib.request +import zlib +from dataclasses import dataclass, field +from pathlib import Path + +from fontTools.ttLib import TTFont +from PIL import Image, ImageDraw, ImageFont + + +SOURCES = { + "NotoColorEmoji.ttf": ( + "https://raw.githubusercontent.com/googlefonts/noto-emoji/" + "8998f5dd683424a73e2314a8c1f1e359c19e8742/fonts/" + "NotoColorEmoji.ttf", + "72a635cb3d2f3524c51620cdde406b217204e8a6a06c6a096ff8ed4b5fd6e27b", + ), + "NotoSansMono-wdth-wght.ttf": ( + "https://raw.githubusercontent.com/google/fonts/main/ofl/notosansmono/" + "NotoSansMono%5Bwdth%2Cwght%5D.ttf", + "2cb2adb378a8f574213e23df697050b83c54c27df465a2015552740b2769a081", + ), + "emoji-test-17.0.txt": ( + "https://www.unicode.org/Public/17.0.0/emoji/emoji-test.txt", + "1d8a944f88d7952f7ef7c5167fef3c67995bcae24543949710231b03a201acda", + ), +} + +TEXT_CELL_WIDTH = 18 +EMOJI_CELL_WIDTH = 12 +CELL_HEIGHT = 24 +EMOJI_CELL_HEIGHT = 12 +BASELINE = 18 +TEXT_NATIVE_SCALE = 3 +FIRST_EMOJI_GLYPH = 0xE000 +LAST_EMOJI_GLYPH = 0xF8FF +FOOTER_MAGIC = b"MCEMAP2\0" +ATLAS_MAGIC = b"CE01" +TRANSPARENT_RGB332 = 0xE3 +PIXEL_OFF = 0 +PIXEL_ON = 255 +TEXT_THRESHOLD = 96 +EMOJI_ALPHA_THRESHOLD = 48 +EMOJI_REGRESSION_MIN_ON_PIXELS = { + "\U0001f44b": 60, # waving hand + "\U0001f642": 70, # slightly smiling face + "\U0001f60a": 70, # smiling face with smiling eyes + "\U0001f44d": 60, # thumbs up +} + + +def digest(path: Path) -> str: + sha = hashlib.sha256() + with path.open("rb") as source: + for block in iter(lambda: source.read(1024 * 1024), b""): + sha.update(block) + return sha.hexdigest() + + +def fetch_sources(cache_dir: Path) -> dict[str, Path]: + cache_dir.mkdir(parents=True, exist_ok=True) + paths: dict[str, Path] = {} + for name, (url, expected_sha) in SOURCES.items(): + path = cache_dir / name + if not path.exists() or digest(path) != expected_sha: + print(f"Downloading {name}") + with urllib.request.urlopen(url, timeout=60) as response: + contents = response.read() + if hashlib.sha256(contents).hexdigest() != expected_sha: + raise RuntimeError(f"source checksum mismatch: {name}") + path.write_bytes(contents) + paths[name] = path + return paths + + +def parse_emoji_test(path: Path) -> tuple[list[tuple[str, int, str]], dict[bytes, int]]: + glyphs: list[tuple[str, int, str]] = [] + aliases: dict[bytes, int] = {} + last_output = 0 + for raw_line in path.read_text(encoding="utf-8").splitlines(): + line = raw_line.strip() + if not line or line.startswith("#"): + continue + data, comment = line.split("#", 1) + codepoints, status = data.split(";", 1) + sequence = "".join(chr(int(value, 16)) for value in codepoints.split()) + status = status.strip() + description_fields = comment.strip().split(" ", 2) + description = description_fields[2] if len(description_fields) == 3 else sequence + encoded = sequence.encode("utf-8") + if status in ("fully-qualified", "component"): + output = FIRST_EMOJI_GLYPH + len(glyphs) + if output > LAST_EMOJI_GLYPH: + raise RuntimeError("emoji glyphs exceed the BMP private-use range") + glyphs.append((sequence, output, description)) + aliases[encoded] = output + last_output = output + elif status in ("minimally-qualified", "unqualified"): + if last_output == 0: + raise RuntimeError("emoji qualification alias has no canonical glyph") + aliases[encoded] = last_output + + # Accept clients that omit the emoji presentation selector even when the + # qualification file does not list that spelling separately. + for sequence, output, _ in glyphs: + without_vs16 = sequence.replace("\ufe0f", "").encode("utf-8") + aliases.setdefault(without_vs16, output) + return glyphs, aliases + + +def text_codepoints(font_path: Path) -> list[int]: + font = TTFont(font_path, lazy=True) + supported: set[int] = set() + for table in font["cmap"].tables: + if table.isUnicode(): + supported.update(table.cmap) + font.close() + + ranges = ( + (0x21, 0x7E), # ASCII (space is encoded as NBSP at runtime) + (0x00A0, 0x024F), # Latin and phonetic extensions + (0x0370, 0x052F), # Greek and Cyrillic + (0x2000, 0x206F), # punctuation and format marks + (0x20A0, 0x20CF), # currency + (0x2100, 0x214F), # letter-like symbols + (0x2190, 0x21FF), # arrows + (0x2500, 0x259F), # box drawing, blocks, and geometric fill + ) + return [ + codepoint + for first, last in ranges + for codepoint in range(first, last + 1) + if codepoint in supported and not 0xE000 <= codepoint <= 0xF8FF + ] + + +def make_binary(image: Image.Image, threshold: int) -> Image.Image: + return image.point( + lambda value: PIXEL_ON if value >= threshold else PIXEL_OFF, + mode="L", + ) + + +def render_text_glyph(font: ImageFont.FreeTypeFont, codepoint: int) -> bytes: + image = Image.new("L", (TEXT_CELL_WIDTH, CELL_HEIGHT), 0) + draw = ImageDraw.Draw(image) + draw.text( + (TEXT_CELL_WIDTH // 2, BASELINE - 1), + chr(codepoint), + font=font, + fill=255, + anchor="ms", + ) + return make_binary(image, TEXT_THRESHOLD).tobytes() + + +def render_empty_emoji_fallback(sequence: str) -> Image.Image: + image = Image.new( + "RGBA", (EMOJI_CELL_WIDTH, EMOJI_CELL_HEIGHT), (0, 0, 0, 0) + ) + if sequence == "\u2796": + ImageDraw.Draw(image).line( + ( + 1, + EMOJI_CELL_HEIGHT // 2, + EMOJI_CELL_WIDTH - 2, + EMOJI_CELL_HEIGHT // 2, + ), + fill=(50, 120, 220, 255), + width=2, + ) + return image + raise RuntimeError(f"emoji rendered blank: {sequence!r}") + + +def render_emoji_image(font: ImageFont.FreeTypeFont, sequence: str) -> Image.Image: + bbox = font.getbbox(sequence, anchor="lt") + if bbox is None or bbox[2] <= bbox[0] or bbox[3] <= bbox[1]: + return render_empty_emoji_fallback(sequence) + source = Image.new( + "RGBA", (bbox[2] - bbox[0], bbox[3] - bbox[1]), (0, 0, 0, 0) + ) + ImageDraw.Draw(source).text( + (-bbox[0], -bbox[1]), + sequence, + font=font, + embedded_color=True, + ) + cropped_bbox = source.getchannel("A").getbbox() + if cropped_bbox is None: + return render_empty_emoji_fallback(sequence) + source = source.crop(cropped_bbox) + scale = min( + EMOJI_CELL_WIDTH / source.width, + EMOJI_CELL_HEIGHT / source.height, + ) + width = max(1, round(source.width * scale)) + height = max(1, round(source.height * scale)) + source = source.resize((width, height), Image.Resampling.LANCZOS) + image = Image.new( + "RGBA", (EMOJI_CELL_WIDTH, EMOJI_CELL_HEIGHT), (0, 0, 0, 0) + ) + image.paste( + source, + ( + (EMOJI_CELL_WIDTH - width) // 2, + (EMOJI_CELL_HEIGHT - height) // 2, + ), + source, + ) + if image.getchannel("A").getbbox() is None: + return render_empty_emoji_fallback(sequence) + return image + + +def pack_rgb332(image: Image.Image) -> bytes: + packed = bytearray() + for red, green, blue, alpha in image.getdata(): + if alpha < EMOJI_ALPHA_THRESHOLD: + packed.append(TRANSPARENT_RGB332) + continue + value = (red & 0xE0) | ((green >> 3) & 0x1C) | (blue >> 6) + if value == TRANSPARENT_RGB332: + value ^= 1 + packed.append(value) + return bytes(packed) + + +@dataclass +class TrieNode: + children: dict[int, "TrieNode"] = field(default_factory=dict) + output: int = 0 + index: int = 0 + + +def build_map(aliases: dict[bytes, int]) -> bytes: + root = TrieNode() + for sequence, output in sorted(aliases.items()): + node = root + for value in sequence: + node = node.children.setdefault(value, TrieNode()) + if node.output not in (0, output): + raise RuntimeError("conflicting emoji aliases") + node.output = output + + nodes: list[TrieNode] = [root] + for node in nodes: + for _, child in sorted(node.children.items()): + if child.index == 0 and child is not root: + child.index = len(nodes) + nodes.append(child) + if len(nodes) > 0xFFFF: + raise RuntimeError("emoji trie has too many nodes") + + node_records = bytearray() + edge_records = bytearray() + edge_index = 0 + for node in nodes: + children = sorted(node.children.items()) + node_records += struct.pack(" 0xFFFF: + raise RuntimeError("emoji trie has too many edges") + + return ( + b"EM01" + + struct.pack(" bytes: + return struct.pack( + ">7I", + codepoint, + CELL_HEIGHT, + width, + width, + BASELINE, + 0, + 0, + ) + + +def rgb332_to_rgba(value: int) -> tuple[int, int, int, int]: + if value == TRANSPARENT_RGB332: + return (0, 0, 0, 0) + red = (value >> 5) & 7 + green = (value >> 2) & 7 + blue = value & 3 + return ( + (red * 255 + 3) // 7, + (green * 255 + 3) // 7, + (blue * 255 + 1) // 3, + 255, + ) + + +def make_preview(path: Path, emoji_bitmaps: list[tuple[str, bytes]]) -> None: + scale = 6 + columns = 16 + rows = (len(emoji_bitmaps) + columns - 1) // columns + preview = Image.new( + "RGBA", + ( + columns * EMOJI_CELL_WIDTH * scale, + rows * EMOJI_CELL_HEIGHT * scale, + ), + (28, 28, 28, 255), + ) + for index, (_, bitmap) in enumerate(emoji_bitmaps): + glyph = Image.new("RGBA", (EMOJI_CELL_WIDTH, EMOJI_CELL_HEIGHT)) + glyph.putdata([rgb332_to_rgba(value) for value in bitmap]) + glyph = glyph.resize( + (EMOJI_CELL_WIDTH * scale, EMOJI_CELL_HEIGHT * scale), + Image.Resampling.NEAREST, + ) + x = (index % columns) * EMOJI_CELL_WIDTH * scale + y = (index // columns) * EMOJI_CELL_HEIGHT * scale + preview.alpha_composite(glyph, (x, y)) + preview.save(path) + + +def build_font(output: Path, cache_dir: Path, preview: Path | None) -> None: + sources = fetch_sources(cache_dir) + emoji_glyphs, aliases = parse_emoji_test(sources["emoji-test-17.0.txt"]) + text_points = text_codepoints(sources["NotoSansMono-wdth-wght.ttf"]) + + text_font = ImageFont.truetype( + str(sources["NotoSansMono-wdth-wght.ttf"]), 20 + ) + text_font.set_variation_by_name("Bold") + emoji_font = ImageFont.truetype(str(sources["NotoColorEmoji.ttf"]), 109) + + glyphs: list[tuple[int, int, bytes]] = [ + ( + codepoint, + TEXT_CELL_WIDTH, + render_text_glyph(text_font, codepoint), + ) + for codepoint in text_points + ] + rendered_emoji: list[tuple[str, bytes]] = [] + color_emoji: list[bytes] = [] + for index, (sequence, _, _) in enumerate(emoji_glyphs, start=1): + bitmap = pack_rgb332(render_emoji_image(emoji_font, sequence)) + minimum_pixels = EMOJI_REGRESSION_MIN_ON_PIXELS.get(sequence) + if minimum_pixels is not None: + on_pixels = sum(pixel != TRANSPARENT_RGB332 for pixel in bitmap) + if on_pixels < minimum_pixels: + raise RuntimeError( + f"emoji lost identifying pixels: {sequence!r} " + f"has {on_pixels}, expected at least {minimum_pixels}" + ) + color_emoji.append(bitmap) + if preview is not None and (index <= 128 or index % 97 == 0): + rendered_emoji.append((sequence, bitmap)) + if index % 500 == 0: + print(f"Rendered {index}/{len(emoji_glyphs)} emoji") + + if any( + pixel not in (PIXEL_OFF, PIXEL_ON) + for _, _, bitmap in glyphs + for pixel in bitmap + ): + raise RuntimeError("font contains antialiased pixels") + + glyphs.sort(key=lambda item: item[0]) + header = struct.pack(">6I", len(glyphs), 11, CELL_HEIGHT, 0, BASELINE, 1) + records = b"".join( + glyph_record(codepoint, width) for codepoint, width, _ in glyphs + ) + bitmaps = b"".join(bitmap for _, _, bitmap in glyphs) + mapping = build_map(aliases) + map_offset = len(header) + len(records) + len(bitmaps) + atlas_header = ATLAS_MAGIC + struct.pack( + " None: + parser = argparse.ArgumentParser() + parser.add_argument("--output", type=Path, required=True) + parser.add_argument( + "--cache-dir", + type=Path, + default=Path.home() / ".cache" / "meshcore-indicator-font", + ) + parser.add_argument("--preview", type=Path) + args = parser.parse_args() + build_font(args.output, args.cache_dir, args.preview) + + +if __name__ == "__main__": + main() diff --git a/tools/sensecap_indicator_font/requirements.txt b/tools/sensecap_indicator_font/requirements.txt new file mode 100644 index 00000000..11beccaf --- /dev/null +++ b/tools/sensecap_indicator_font/requirements.txt @@ -0,0 +1,2 @@ +fonttools==4.59.1 +Pillow==10.2.0 diff --git a/tools/sensecap_indicator_rp2040/README.md b/tools/sensecap_indicator_rp2040/README.md new file mode 100644 index 00000000..8a6030f7 --- /dev/null +++ b/tools/sensecap_indicator_rp2040/README.md @@ -0,0 +1,33 @@ +# SenseCAP Indicator SD font service + +The Indicator connects its SD card to the RP2040 rather than the ESP32-S3. +This small RP2040 image owns the card and streams `/meshcore/ui-font.vlw` to +the main application over the internal UART at boot. The ESP32-S3 verifies the +whole-file CRC and falls back to its built-in font if the service, card, file, +or emoji map is unavailable or invalid. + +Build and flash the service through the RP2040 USB connector: + +```bash +pio run -d tools/sensecap_indicator_rp2040 +pio run -d tools/sensecap_indicator_rp2040 -t upload --upload-port /dev/ttyACM2 +``` + +Then upload the generated font to the SD card through that same USB serial +port. The update is checksummed and uses temporary and backup files so an +interrupted upload keeps the last complete font: + +```bash +python3 -m pip install pyserial +python3 tools/sensecap_indicator_rp2040/upload_font.py --port /dev/ttyACM2 +``` + +The checked-in asset contains binary 18x24 Noto Sans Mono Bold text and a +12x12 RGB332 Unicode Emoji 17.0 color atlas. Text and emoji transparency have +no antialiasing; the ESP32-S3 renders the asset at the panel's native 480x480 +resolution. See +`../sensecap_indicator_font/README.md` to regenerate the asset. + +For diagnostics, send `MCFONT STATUS` over RP2040 USB serial. The response +reports internal-UART INFO requests, GET attempts, completed streams, and +bytes sent since the RP2040 last booted. diff --git a/tools/sensecap_indicator_rp2040/platformio.ini b/tools/sensecap_indicator_rp2040/platformio.ini new file mode 100644 index 00000000..a9b9cb9f --- /dev/null +++ b/tools/sensecap_indicator_rp2040/platformio.ini @@ -0,0 +1,13 @@ +[platformio] +default_envs = sensecap_indicator_rp2040_font +src_dir = src + +[env:sensecap_indicator_rp2040_font] +platform = https://github.com/maxgerhardt/platform-raspberrypi.git#4e22a0dcdd94eead72fdf56ea59a3d7c8aa2f379 +board = seeed_indicator_rp2040 +framework = arduino +monitor_speed = 115200 +upload_protocol = picotool +build_flags = + -Wall + -Wextra diff --git a/tools/sensecap_indicator_rp2040/src/main.cpp b/tools/sensecap_indicator_rp2040/src/main.cpp new file mode 100644 index 00000000..3976345c --- /dev/null +++ b/tools/sensecap_indicator_rp2040/src/main.cpp @@ -0,0 +1,385 @@ +#include +#include +#include + +namespace { + +constexpr uint32_t FONT_UART_BAUD = 1000000; +constexpr uint32_t SD_CLOCK_HZ = 1000000; +constexpr uint32_t RECEIVE_IDLE_TIMEOUT_MS = 10000; +constexpr size_t MAX_FONT_BYTES = 1536 * 1024; + +constexpr int FONT_UART_TX = 16; +constexpr int FONT_UART_RX = 17; +constexpr int SD_SCK = 10; +constexpr int SD_MOSI = 11; +constexpr int SD_MISO = 12; +constexpr int SD_CS = 13; + +constexpr const char* FONT_DIRECTORY = "/meshcore"; +constexpr const char* FONT_PATH = "/meshcore/ui-font.vlw"; +constexpr const char* FONT_META_PATH = "/meshcore/ui-font.meta"; +constexpr const char* TEMP_FONT_PATH = "/meshcore/ui-font.tmp"; +constexpr const char* TEMP_META_PATH = "/meshcore/ui-font-meta.tmp"; +constexpr const char* BACKUP_FONT_PATH = "/meshcore/ui-font.bak"; +constexpr const char* BACKUP_META_PATH = "/meshcore/ui-font-meta.bak"; + +bool sdReady = false; +size_t fontSize = 0; +uint32_t fontCrc = 0; +uint32_t espInfoRequests = 0; +uint32_t espGetAttempts = 0; +uint32_t espGetCompleted = 0; +size_t espLastBytes = 0; + +uint32_t updateCrc32(uint32_t crc, const uint8_t* data, size_t size) { + for (size_t i = 0; i < size; ++i) { + crc ^= data[i]; + for (uint8_t bit = 0; bit < 8; ++bit) { + crc = (crc >> 1) ^ (0xEDB88320UL & (0U - (crc & 1U))); + } + } + return crc; +} + +bool readLine(File& file, char* line, size_t capacity) { + size_t length = 0; + while (file.available()) { + int value = file.read(); + if (value < 0) break; + if (value == '\n') { + line[length] = 0; + return true; + } + if (value != '\r' && length + 1 < capacity) { + line[length++] = (char)value; + } + } + line[length] = 0; + return length != 0; +} + +bool parseMetadata(const char* line, size_t& size, uint32_t& crc) { + unsigned long parsedSize = 0; + unsigned long parsedCrc = 0; + if (sscanf(line, "MCFONT 1 %lu %lx", &parsedSize, &parsedCrc) != 2 + || parsedSize < 64 + || parsedSize > MAX_FONT_BYTES) { + return false; + } + size = (size_t)parsedSize; + crc = (uint32_t)parsedCrc; + return true; +} + +bool validatePair(const char* fontPath, const char* metadataPath, + size_t& size, uint32_t& crc) { + File metadata = SD.open(metadataPath, FILE_READ); + if (!metadata) return false; + + char line[64]; + bool valid = readLine(metadata, line, sizeof(line)) + && parseMetadata(line, size, crc); + metadata.close(); + if (!valid) return false; + + File font = SD.open(fontPath, FILE_READ); + if (!font) return false; + valid = font.size() == size; + font.close(); + return valid; +} + +void removeIfPresent(const char* path) { + if (SD.exists(path)) SD.remove(path); +} + +void cleanTransactionFiles() { + removeIfPresent(TEMP_FONT_PATH); + removeIfPresent(TEMP_META_PATH); + removeIfPresent(BACKUP_FONT_PATH); + removeIfPresent(BACKUP_META_PATH); +} + +bool promotePair(const char* sourceFont, const char* sourceMetadata) { + removeIfPresent(FONT_PATH); + removeIfPresent(FONT_META_PATH); + if (!SD.rename(sourceFont, FONT_PATH)) return false; + if (SD.rename(sourceMetadata, FONT_META_PATH)) return true; + removeIfPresent(FONT_PATH); + return false; +} + +void recoverFontTransaction() { + size_t size; + uint32_t crc; + if (validatePair(FONT_PATH, FONT_META_PATH, size, crc)) { + cleanTransactionFiles(); + return; + } + + // A reset between the two final renames can leave the new font next to its + // temporary metadata. Complete that transaction when the sizes still agree. + if (validatePair(FONT_PATH, TEMP_META_PATH, size, crc)) { + removeIfPresent(FONT_META_PATH); + if (SD.rename(TEMP_META_PATH, FONT_META_PATH)) { + cleanTransactionFiles(); + return; + } + } + + if (validatePair(TEMP_FONT_PATH, TEMP_META_PATH, size, crc) + && promotePair(TEMP_FONT_PATH, TEMP_META_PATH)) { + cleanTransactionFiles(); + return; + } + + if (validatePair(BACKUP_FONT_PATH, BACKUP_META_PATH, size, crc) + && promotePair(BACKUP_FONT_PATH, BACKUP_META_PATH)) { + cleanTransactionFiles(); + return; + } + + removeIfPresent(FONT_PATH); + removeIfPresent(FONT_META_PATH); + cleanTransactionFiles(); +} + +bool refreshFontInfo() { + fontSize = 0; + fontCrc = 0; + return sdReady && validatePair(FONT_PATH, FONT_META_PATH, fontSize, fontCrc); +} + +void sendInfo(Print& output, bool trackEspRequest) { + if (trackEspRequest) ++espInfoRequests; + if (!refreshFontInfo()) { + output.print("MCFONT 0 0 00000000\n"); + return; + } + output.printf("MCFONT 1 %lu %08lx\n", (unsigned long)fontSize, + (unsigned long)fontCrc); +} + +void sendFont(Print& output, bool trackEspRequest) { + if (trackEspRequest) { + ++espGetAttempts; + espLastBytes = 0; + } + if (!refreshFontInfo()) { + output.print("MCFONT 0 0 00000000\n"); + return; + } + + File font = SD.open(FONT_PATH, FILE_READ); + if (!font) { + output.print("MCFONT 0 0 00000000\n"); + return; + } + + output.printf("MCFONT 1 %lu %08lx\n", (unsigned long)fontSize, + (unsigned long)fontCrc); + uint8_t buffer[512]; + size_t sent = 0; + while (font.available()) { + size_t count = font.read(buffer, sizeof(buffer)); + if (count == 0) break; + size_t written = output.write(buffer, count); + sent += written; + if (written != count) break; + } + font.close(); + if (trackEspRequest) { + espLastBytes = sent; + if (sent == fontSize) ++espGetCompleted; + } +} + +bool writeMetadata(const char* path, size_t size, uint32_t crc) { + removeIfPresent(path); + File metadata = SD.open(path, "w"); + if (!metadata) return false; + metadata.printf("MCFONT 1 %lu %08lx\n", (unsigned long)size, + (unsigned long)crc); + metadata.flush(); + metadata.close(); + return true; +} + +bool moveCurrentToBackup() { + removeIfPresent(BACKUP_FONT_PATH); + removeIfPresent(BACKUP_META_PATH); + + bool movedFont = false; + if (SD.exists(FONT_PATH)) { + if (!SD.rename(FONT_PATH, BACKUP_FONT_PATH)) return false; + movedFont = true; + } + if (SD.exists(FONT_META_PATH) + && !SD.rename(FONT_META_PATH, BACKUP_META_PATH)) { + if (movedFont) SD.rename(BACKUP_FONT_PATH, FONT_PATH); + return false; + } + return true; +} + +bool installTemporaryPair(size_t expectedSize, uint32_t expectedCrc) { + if (!moveCurrentToBackup()) return false; + if (!SD.rename(TEMP_FONT_PATH, FONT_PATH)) { + recoverFontTransaction(); + return refreshFontInfo() && fontSize == expectedSize && fontCrc == expectedCrc; + } + if (!SD.rename(TEMP_META_PATH, FONT_META_PATH)) { + recoverFontTransaction(); + return refreshFontInfo() && fontSize == expectedSize && fontCrc == expectedCrc; + } + cleanTransactionFiles(); + return refreshFontInfo() && fontSize == expectedSize && fontCrc == expectedCrc; +} + +void receiveFont(Stream& input, Print& output, size_t expectedSize, + uint32_t expectedCrc) { + if (!sdReady) { + output.print("ERROR SD\n"); + return; + } + + removeIfPresent(TEMP_FONT_PATH); + removeIfPresent(TEMP_META_PATH); + File font = SD.open(TEMP_FONT_PATH, "w"); + if (!font) { + output.print("ERROR OPEN\n"); + return; + } + + output.print("READY\n"); + uint8_t buffer[512]; + size_t received = 0; + uint32_t crc = 0xFFFFFFFFUL; + uint32_t lastProgress = millis(); + bool writeFailed = false; + while (received < expectedSize + && millis() - lastProgress < RECEIVE_IDLE_TIMEOUT_MS) { + int available = input.available(); + if (available <= 0) { + delay(1); + continue; + } + size_t count = (size_t)available; + if (count > sizeof(buffer)) count = sizeof(buffer); + if (count > expectedSize - received) count = expectedSize - received; + size_t actual = input.readBytes(buffer, count); + if (actual == 0) continue; + if (font.write(buffer, actual) != actual) { + writeFailed = true; + break; + } + crc = updateCrc32(crc, buffer, actual); + received += actual; + lastProgress = millis(); + } + font.flush(); + font.close(); + + if (writeFailed || received != expectedSize || ~crc != expectedCrc) { + removeIfPresent(TEMP_FONT_PATH); + output.print(writeFailed ? "ERROR WRITE\n" : "ERROR CHECKSUM\n"); + return; + } + if (!writeMetadata(TEMP_META_PATH, expectedSize, expectedCrc) + || !installTemporaryPair(expectedSize, expectedCrc)) { + recoverFontTransaction(); + output.print("ERROR INSTALL\n"); + return; + } + output.print("OK\n"); +} + +struct CommandReader { + Stream& input; + Print& output; + bool allowUpload; + char line[96] = {}; + size_t length = 0; +}; + +void processCommand(CommandReader& reader) { + if (strcmp(reader.line, "MCFONT INFO") == 0) { + sendInfo(reader.output, !reader.allowUpload); + return; + } + if (strcmp(reader.line, "MCFONT STATUS") == 0) { + reader.output.printf("MCFONT STATUS %lu %lu %lu %lu\n", + (unsigned long)espInfoRequests, + (unsigned long)espGetAttempts, + (unsigned long)espGetCompleted, + (unsigned long)espLastBytes); + return; + } + if (strcmp(reader.line, "MCFONT GET") == 0) { + sendFont(reader.output, !reader.allowUpload); + return; + } + + unsigned long size = 0; + unsigned long crc = 0; + if (sscanf(reader.line, "MCFONT PUT %lu %lx", &size, &crc) == 2) { + if (!reader.allowUpload) { + reader.output.print("ERROR READONLY\n"); + } else if (size < 64 || size > MAX_FONT_BYTES) { + reader.output.print("ERROR SIZE\n"); + } else { + receiveFont(reader.input, reader.output, (size_t)size, (uint32_t)crc); + } + return; + } + reader.output.print("ERROR COMMAND\n"); +} + +void pollCommands(CommandReader& reader) { + while (reader.input.available()) { + int value = reader.input.read(); + if (value < 0) break; + if (value == '\n') { + reader.line[reader.length] = 0; + processCommand(reader); + reader.length = 0; + } else if (value != '\r') { + if (reader.length + 1 < sizeof(reader.line)) { + reader.line[reader.length++] = (char)value; + } else { + reader.length = 0; + } + } + } +} + +CommandReader usbCommands = {Serial, Serial, true}; +CommandReader espCommands = {Serial1, Serial1, false}; + +} // namespace + +void setup() { + Serial.begin(115200); + + Serial1.setRX(FONT_UART_RX); + Serial1.setTX(FONT_UART_TX); + Serial1.setFIFOSize(1024); + Serial1.begin(FONT_UART_BAUD); + + SPI1.setSCK(SD_SCK); + SPI1.setTX(SD_MOSI); + SPI1.setRX(SD_MISO); + sdReady = SD.begin(SD_CS, SD_CLOCK_HZ, SPI1); + if (sdReady) { + if (!SD.exists(FONT_DIRECTORY)) SD.mkdir(FONT_DIRECTORY); + recoverFontTransaction(); + refreshFontInfo(); + } +} + +void loop() { + pollCommands(espCommands); + pollCommands(usbCommands); + delay(1); +} diff --git a/tools/sensecap_indicator_rp2040/upload_font.py b/tools/sensecap_indicator_rp2040/upload_font.py new file mode 100644 index 00000000..73371b6e --- /dev/null +++ b/tools/sensecap_indicator_rp2040/upload_font.py @@ -0,0 +1,96 @@ +#!/usr/bin/env python3 +"""Upload a checked font asset to the Indicator RP2040 SD service.""" + +from __future__ import annotations + +import argparse +import sys +import time +import zlib +from pathlib import Path + +import serial + + +MAX_FONT_BYTES = 1536 * 1024 + + +def read_line(port: serial.Serial, timeout: float) -> str: + deadline = time.monotonic() + timeout + line = bytearray() + while time.monotonic() < deadline: + value = port.read(1) + if not value: + continue + if value == b"\n": + return line.rstrip(b"\r").decode("ascii", errors="replace") + line += value + raise TimeoutError("font service did not respond") + + +def upload(port_name: str, font_path: Path, timeout: float) -> None: + data = font_path.read_bytes() + if not 64 <= len(data) <= MAX_FONT_BYTES: + raise ValueError(f"font size must be between 64 and {MAX_FONT_BYTES} bytes") + crc = zlib.crc32(data) & 0xFFFFFFFF + + with serial.Serial( + port_name, + 115200, + timeout=0.2, + write_timeout=timeout, + ) as port: + time.sleep(0.25) + # Terminate any partial command left by an interrupted terminal or + # uploader before beginning the transactional transfer. + port.write(b"\n") + port.flush() + time.sleep(0.05) + port.reset_input_buffer() + port.write(f"MCFONT PUT {len(data)} {crc:08x}\n".encode("ascii")) + port.flush() + response = read_line(port, timeout) + if response != "READY": + raise RuntimeError(f"font service refused upload: {response}") + + sent = 0 + while sent < len(data): + sent += port.write(data[sent : sent + 4096]) + port.flush() + + response = read_line(port, timeout) + if response != "OK": + raise RuntimeError(f"font service failed to install font: {response}") + + port.write(b"MCFONT INFO\n") + port.flush() + expected = f"MCFONT 1 {len(data)} {crc:08x}" + response = read_line(port, timeout) + if response != expected: + raise RuntimeError( + f"font verification failed: expected {expected!r}, got {response!r}" + ) + + print(f"Installed {font_path} ({len(data)} bytes, CRC32 {crc:08x})") + + +def main() -> int: + parser = argparse.ArgumentParser() + parser.add_argument("--port", required=True, help="RP2040 USB serial port") + parser.add_argument( + "--font", + type=Path, + default=Path("variants/sensecap_indicator-espnow/sd/ui-font.vlw"), + ) + parser.add_argument("--timeout", type=float, default=30.0) + args = parser.parse_args() + try: + upload(args.port, args.font, args.timeout) + except (OSError, ValueError, RuntimeError, TimeoutError, serial.SerialException) as exc: + print(f"error: {exc}", file=sys.stderr) + return 1 + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/variants/sensecap_indicator-espnow/IndicatorFontClient.cpp b/variants/sensecap_indicator-espnow/IndicatorFontClient.cpp new file mode 100644 index 00000000..adcb4512 --- /dev/null +++ b/variants/sensecap_indicator-espnow/IndicatorFontClient.cpp @@ -0,0 +1,133 @@ +#include "IndicatorFontClient.h" + +#include +#include + +namespace { + +static const uint32_t FONT_UART_BAUD = 1000000; +static const int FONT_UART_RX = 20; +static const int FONT_UART_TX = 19; +static const size_t MAX_FONT_BYTES = 1536 * 1024; + +uint32_t updateCrc32(uint32_t crc, const uint8_t* data, size_t size) { + for (size_t i = 0; i < size; ++i) { + crc ^= data[i]; + for (uint8_t bit = 0; bit < 8; ++bit) { + crc = (crc >> 1) ^ (0xEDB88320UL & (0U - (crc & 1U))); + } + } + return crc; +} + +bool readLine(HardwareSerial& serial, char* line, size_t capacity, + uint32_t timeout_millis) { + size_t length = 0; + uint32_t started = millis(); + while (millis() - started < timeout_millis) { + while (serial.available()) { + int value = serial.read(); + if (value < 0) break; + if (value == '\n') { + line[length] = 0; + return true; + } + if (value != '\r' && length + 1 < capacity) { + line[length++] = (char)value; + } + } + delay(1); + } + line[0] = 0; + return false; +} + +bool parseInfo(const char* line, size_t& size, uint32_t& crc) { + unsigned long parsed_size = 0; + unsigned long parsed_crc = 0; + int present = 0; + if (sscanf(line, "MCFONT 1 %lu %lx", &parsed_size, &parsed_crc) != 2) { + if (sscanf(line, "MCFONT %d", &present) == 1 && present == 0) return false; + return false; + } + if (parsed_size < 64 || parsed_size > MAX_FONT_BYTES) return false; + size = (size_t)parsed_size; + crc = (uint32_t)parsed_crc; + return true; +} + +bool requestInfo(HardwareSerial& serial, size_t& size, uint32_t& crc) { + char line[64]; + for (int attempt = 0; attempt < 3; ++attempt) { + while (serial.available()) serial.read(); + serial.print("MCFONT INFO\n"); + serial.flush(); + if (readLine(serial, line, sizeof(line), 1000) + && parseInfo(line, size, crc)) { + return true; + } + delay(100); + } + return false; +} + +bool receiveFont(HardwareSerial& serial, uint8_t* data, size_t size, + uint32_t expected_crc) { + char line[64]; + serial.print("MCFONT GET\n"); + serial.flush(); + + size_t response_size; + uint32_t response_crc; + if (!readLine(serial, line, sizeof(line), 1500) + || !parseInfo(line, response_size, response_crc) + || response_size != size + || response_crc != expected_crc) { + return false; + } + + size_t received = 0; + uint32_t crc = 0xFFFFFFFFUL; + uint32_t last_progress = millis(); + while (received < size && millis() - last_progress < 2000) { + int available = serial.available(); + if (available <= 0) { + delay(1); + continue; + } + size_t count = (size_t)available; + if (count > size - received) count = size - received; + size_t actual = serial.readBytes(data + received, count); + if (actual == 0) continue; + crc = updateCrc32(crc, data + received, actual); + received += actual; + last_progress = millis(); + } + return received == size && ~crc == expected_crc; +} + +} // namespace + +uint8_t* IndicatorFontClient::load(size_t& size) { + size = 0; + if (!psramFound()) return nullptr; + + Serial2.begin(FONT_UART_BAUD, SERIAL_8N1, FONT_UART_RX, FONT_UART_TX); + delay(50); + + uint32_t expected_crc; + if (!requestInfo(Serial2, size, expected_crc)) { + Serial2.end(); + size = 0; + return nullptr; + } + + uint8_t* data = (uint8_t*)ps_malloc(size); + if (data == nullptr || !receiveFont(Serial2, data, size, expected_crc)) { + free(data); + data = nullptr; + size = 0; + } + Serial2.end(); + return data; +} diff --git a/variants/sensecap_indicator-espnow/IndicatorFontClient.h b/variants/sensecap_indicator-espnow/IndicatorFontClient.h new file mode 100644 index 00000000..34281a7b --- /dev/null +++ b/variants/sensecap_indicator-espnow/IndicatorFontClient.h @@ -0,0 +1,9 @@ +#pragma once + +#include +#include + +class IndicatorFontClient { +public: + static uint8_t* load(size_t& size); +}; diff --git a/variants/sensecap_indicator-espnow/IndicatorRadioHal.cpp b/variants/sensecap_indicator-espnow/IndicatorRadioHal.cpp new file mode 100644 index 00000000..e55966cc --- /dev/null +++ b/variants/sensecap_indicator-espnow/IndicatorRadioHal.cpp @@ -0,0 +1,166 @@ +#include "IndicatorRadioHal.h" + +#ifdef SENSECAP_INDICATOR_LORA + +IndicatorRadioHal::IndicatorRadioHal(SPIClass& spi) : ArduinoHal(spi) {} + +bool IndicatorRadioHal::isExpanderPin(uint32_t pin) { + return pin != RADIOLIB_NC && (pin & EXPANDER_FLAG) != 0; +} + +uint8_t IndicatorRadioHal::expanderIndex(uint32_t pin) { + return static_cast(pin & ~EXPANDER_FLAG); +} + +bool IndicatorRadioHal::readRegister(uint8_t reg, uint16_t& value) { + uint8_t data[2]; + if (!lgfx::i2c::readRegister(I2C_PORT, EXPANDER_ADDRESS, reg, data, + sizeof(data), I2C_FREQUENCY) + .has_value()) { + return false; + } + value = data[0]; + value |= static_cast(data[1]) << 8; + return true; +} + +bool IndicatorRadioHal::writeRegister(uint8_t reg, uint16_t value) { + uint8_t data[] = { + reg, + static_cast(value), + static_cast(value >> 8), + }; + return lgfx::i2c::transactionWrite(I2C_PORT, EXPANDER_ADDRESS, data, + sizeof(data), I2C_FREQUENCY) + .has_value(); +} + +bool IndicatorRadioHal::beginExpander() { + if (_expanderReady) return true; + + uint16_t inputs; + if (!readRegister(OUTPUT_REGISTER, _output) + || !readRegister(CONFIG_REGISTER, _config) + || !readRegister(INPUT_REGISTER, inputs)) { + // The display normally initializes this shared bus first. Reinitialize it + // here as a fallback when display or touch probing ended early. + if (!lgfx::i2c::init(I2C_PORT, PIN_BOARD_SDA, PIN_BOARD_SCL).has_value() + || !readRegister(OUTPUT_REGISTER, _output) + || !readRegister(CONFIG_REGISTER, _config) + || !readRegister(INPUT_REGISTER, inputs)) { + return false; + } + } + + ::pinMode(EXPANDER_INTERRUPT_GPIO, INPUT_PULLUP); + _irqLevel = (inputs & (1U << RADIO_IRQ_INDEX)) != 0; + _expanderReady = true; + return true; +} + +bool IndicatorRadioHal::readInputs(uint16_t& value) { + if (!beginExpander() || !readRegister(INPUT_REGISTER, value)) return false; + processInterruptLevel(value); + return true; +} + +void IndicatorRadioHal::processInterruptLevel(uint16_t inputs) { + bool level = (inputs & (1U << RADIO_IRQ_INDEX)) != 0; + if (level == _irqLevel) return; + + _irqLevel = level; + if (_irqCallback == nullptr) return; + if ((_irqMode == GpioInterruptRising && level) + || (_irqMode == GpioInterruptFalling && !level)) { + _irqCallback(); + } +} + +void IndicatorRadioHal::serviceInterrupt() { + if (_irqCallback == nullptr || !_expanderReady + || ::digitalRead(EXPANDER_INTERRUPT_GPIO) != LOW) { + return; + } + + uint16_t inputs; + readInputs(inputs); +} + +void IndicatorRadioHal::pinMode(uint32_t pin, uint32_t mode) { + if (!isExpanderPin(pin)) { + ArduinoHal::pinMode(pin, mode); + return; + } + + uint8_t index = expanderIndex(pin); + if (index >= 16 || !beginExpander()) return; + uint16_t next = _config; + if (mode == GpioModeOutput) { + next &= ~(1U << index); + } else { + next |= 1U << index; + } + if (next != _config && writeRegister(CONFIG_REGISTER, next)) _config = next; +} + +void IndicatorRadioHal::digitalWrite(uint32_t pin, uint32_t value) { + if (!isExpanderPin(pin)) { + ArduinoHal::digitalWrite(pin, value); + return; + } + + uint8_t index = expanderIndex(pin); + if (index >= 16 || !beginExpander()) return; + uint16_t next = value == GpioLevelHigh ? _output | (1U << index) + : _output & ~(1U << index); + if (next != _output && writeRegister(OUTPUT_REGISTER, next)) _output = next; +} + +uint32_t IndicatorRadioHal::digitalRead(uint32_t pin) { + if (!isExpanderPin(pin)) return ArduinoHal::digitalRead(pin); + + uint8_t index = expanderIndex(pin); + uint16_t inputs; + if (index >= 16 || !readInputs(inputs)) { + // A failed BUSY read must prevent an unsafe SPI command. Other failed + // reads are treated as inactive. + return pin == P_LORA_BUSY ? GpioLevelHigh : GpioLevelLow; + } + return (inputs & (1U << index)) != 0 ? GpioLevelHigh : GpioLevelLow; +} + +void IndicatorRadioHal::attachInterrupt(uint32_t interrupt_num, + void (*callback)(void), uint32_t mode) { + if (!isExpanderPin(interrupt_num)) { + ArduinoHal::attachInterrupt(interrupt_num, callback, mode); + return; + } + + if (expanderIndex(interrupt_num) != RADIO_IRQ_INDEX + || !beginExpander()) { + return; + } + + _irqCallback = callback; + _irqMode = mode; + uint16_t inputs; + if (readRegister(INPUT_REGISTER, inputs)) { + _irqLevel = (inputs & (1U << RADIO_IRQ_INDEX)) != 0; + } +} + +void IndicatorRadioHal::detachInterrupt(uint32_t interrupt_num) { + if (!isExpanderPin(interrupt_num)) { + ArduinoHal::detachInterrupt(interrupt_num); + return; + } + if (expanderIndex(interrupt_num) == RADIO_IRQ_INDEX) { + _irqCallback = nullptr; + } +} + +uint32_t IndicatorRadioHal::pinToInterrupt(uint32_t pin) { + return isExpanderPin(pin) ? pin : ArduinoHal::pinToInterrupt(pin); +} + +#endif diff --git a/variants/sensecap_indicator-espnow/IndicatorRadioHal.h b/variants/sensecap_indicator-espnow/IndicatorRadioHal.h new file mode 100644 index 00000000..3c47396e --- /dev/null +++ b/variants/sensecap_indicator-espnow/IndicatorRadioHal.h @@ -0,0 +1,52 @@ +#pragma once + +#include +#include +#define LGFX_USE_V1 +#include +#include + +// RadioLib HAL for the Indicator's SX1262. Four radio signals are routed +// through a TCA9535 instead of ordinary ESP32 GPIOs. The expander's shared, +// active-low interrupt output is polled from normal task context so I2C is +// never touched by an ISR. +class IndicatorRadioHal : public ArduinoHal { +public: + explicit IndicatorRadioHal(SPIClass& spi); + + bool beginExpander(); + void serviceInterrupt(); + + void pinMode(uint32_t pin, uint32_t mode) override; + void digitalWrite(uint32_t pin, uint32_t value) override; + uint32_t digitalRead(uint32_t pin) override; + void attachInterrupt(uint32_t interrupt_num, void (*callback)(void), + uint32_t mode) override; + void detachInterrupt(uint32_t interrupt_num) override; + uint32_t pinToInterrupt(uint32_t pin) override; + +private: + static constexpr uint8_t EXPANDER_ADDRESS = 0x20; + static constexpr uint8_t I2C_PORT = 0; + static constexpr uint32_t I2C_FREQUENCY = 400000; + static constexpr uint32_t EXPANDER_FLAG = 0x40; + static constexpr uint8_t INPUT_REGISTER = 0x00; + static constexpr uint8_t OUTPUT_REGISTER = 0x02; + static constexpr uint8_t CONFIG_REGISTER = 0x06; + static constexpr uint8_t RADIO_IRQ_INDEX = 3; + static constexpr uint8_t EXPANDER_INTERRUPT_GPIO = 42; + + bool _expanderReady = false; + uint16_t _output = 0xFFFF; + uint16_t _config = 0xFFFF; + bool _irqLevel = false; + void (*_irqCallback)(void) = nullptr; + uint32_t _irqMode = RISING; + + static bool isExpanderPin(uint32_t pin); + static uint8_t expanderIndex(uint32_t pin); + bool readRegister(uint8_t reg, uint16_t& value); + bool writeRegister(uint8_t reg, uint16_t value); + bool readInputs(uint16_t& value); + void processInterruptLevel(uint16_t inputs); +}; diff --git a/variants/sensecap_indicator-espnow/IndicatorSX1262Wrapper.h b/variants/sensecap_indicator-espnow/IndicatorSX1262Wrapper.h new file mode 100644 index 00000000..4754ce84 --- /dev/null +++ b/variants/sensecap_indicator-espnow/IndicatorSX1262Wrapper.h @@ -0,0 +1,19 @@ +#pragma once + +#include +#include "IndicatorRadioHal.h" + +class IndicatorSX1262Wrapper : public CustomSX1262Wrapper { +public: + IndicatorSX1262Wrapper(CustomSX1262& radio, mesh::MainBoard& board, + IndicatorRadioHal& hal) + : CustomSX1262Wrapper(radio, board), _hal(hal) {} + + void loop() override { + _hal.serviceInterrupt(); + CustomSX1262Wrapper::loop(); + } + +private: + IndicatorRadioHal& _hal; +}; diff --git a/variants/sensecap_indicator-espnow/IndicatorTouch.h b/variants/sensecap_indicator-espnow/IndicatorTouch.h new file mode 100644 index 00000000..5bcad118 --- /dev/null +++ b/variants/sensecap_indicator-espnow/IndicatorTouch.h @@ -0,0 +1,91 @@ +#pragma once + +#define LGFX_USE_V1 +#include +#include + +// This FT5x06-compatible controller exposes valid point data at register 0x02, +// but some units return zero for all optional identity registers. Probe the +// point register instead of rejecting those units by vendor ID. +class IndicatorTouch : public lgfx::Touch_FT5x06 { + static constexpr size_t POINT_DATA_SIZE = 5; + + bool readPointData(uint8_t* data, size_t size) { + const uint8_t point_count_reg = 0x02; + return lgfx::i2c::transactionWriteRead( + _cfg.i2c_port, _cfg.i2c_addr, &point_count_reg, 1, + data, size, _cfg.freq) + .has_value(); + } + + bool readStablePointData(uint8_t* data) { + uint8_t samples[2][POINT_DATA_SIZE] = {}; + if (!readPointData(samples[0], sizeof(samples[0]))) return false; + if ((samples[0][0] & 0x0F) == 0) { + memcpy(data, samples[0], POINT_DATA_SIZE); + return true; + } + + // Coordinates may change while the controller is being read. Match two + // consecutive snapshots, as the standard driver does, so X/Y bytes from + // different positions cannot reverse a gesture. If the finger keeps + // moving through every retry, use the newest complete snapshot. + uint8_t current = 0; + for (uint8_t attempt = 0; attempt < 5; ++attempt) { + const uint8_t next = current ^ 1U; + if (!readPointData(samples[next], sizeof(samples[next]))) return false; + if (memcmp(samples[current], samples[next], POINT_DATA_SIZE) == 0) { + memcpy(data, samples[next], POINT_DATA_SIZE); + return true; + } + current = next; + } + memcpy(data, samples[current], POINT_DATA_SIZE); + return true; + } + +public: + bool init() override { + _inited = false; + if (!lgfx::i2c::init(_cfg.i2c_port, _cfg.pin_sda, _cfg.pin_scl) + .has_value()) { + return false; + } + + uint8_t point_count = 0; + if (!readPointData(&point_count, 1)) { + return false; + } + + // Select normal operation and polling mode, matching the generic driver. + if (!lgfx::i2c::writeRegister8( + _cfg.i2c_port, _cfg.i2c_addr, 0x00, 0x00, 0, _cfg.freq) + .has_value() + || !lgfx::i2c::writeRegister8( + _cfg.i2c_port, _cfg.i2c_addr, 0xA4, 0x00, 0, _cfg.freq) + .has_value()) { + return false; + } + + _inited = true; + return true; + } + + uint_fast8_t getTouchRaw(lgfx::touch_point_t* point, + uint_fast8_t count) override { + if (point == nullptr || count == 0 || (!_inited && !init())) return 0; + + uint8_t data[POINT_DATA_SIZE] = {}; + if (!readStablePointData(data)) { + _inited = false; + return 0; + } + if ((data[0] & 0x0F) == 0) return 0; + + point[0].x = ((data[1] & 0x0F) << 8) | data[2]; + point[0].y = ((data[3] & 0x0F) << 8) | data[4]; + point[0].size = 1; + point[0].id = data[3] >> 4; + return 1; + } +}; diff --git a/variants/sensecap_indicator-espnow/README.md b/variants/sensecap_indicator-espnow/README.md new file mode 100644 index 00000000..001b04f4 --- /dev/null +++ b/variants/sensecap_indicator-espnow/README.md @@ -0,0 +1,102 @@ +# SenseCAP Indicator controls + +The Indicator uses its full 480x480 panel resolution while preserving the +existing 160x160 UI coordinate system. A 4-bit internal canvas avoids PSRAM +contention with RGB scanout; text and icons are rendered directly at 3x detail +instead of enlarging a completed 160x160 frame. The screen blanks after five +minutes on USB power; the hardware button or a touch wakes it without +selecting anything. + +## Touch navigation + +- Swipe horizontally to move between home pages. The dots under the status bar + show the current page. +- The middle 70% of the panel is the Select tap target. The outer 15% on each + side performs Previous or Next; horizontal swipes remain available anywhere. +- A gesture is committed after a stable release. Brief missing touch samples + are ignored so one swipe cannot become a second, opposite endpoint tap. + +## Reading messages + +The message preview is a non-destructive local inbox, newest first: + +- The first home page shows the retained local `INBOX` count, which remains + useful when a USB host has already drained the protocol's unread count. Tap + the center to open the inbox and channel selector even when the count is 0. +- `Message 1/N` is the newest buffered preview. +- Each preview retains the complete 160-byte maximum chat payload. Long UTF-8 + messages wrap through the available middle of the screen instead of being + cut at the small-display 78-byte limit. +- When a USB host drains the radio queue, the displayed preview is retained + for five minutes rather than disappearing immediately. +- Swipe left for an older preview and right for a newer preview. Navigation + stops at the oldest and newest entries instead of wrapping. +- The bottom bar shows the active inbox filter. Its large `<` and `>` end + buttons select the previous or next filter; swipe up or down does the same. + Filters include `All channels`, `Direct`, and configured channels such as + `Ch 1 #testing`. A newly received message automatically selects its source + channel. +- Tap the center to return home without deleting the previews. +- On the first home page, tap the wide center target to reopen the previews, + including when `INBOX` is zero. + +Channel messages identify both the configured slot and name, such as +`Ch 0 Public` or `Ch 1 #testing`. The value in brackets after it is the route, +for example `[0h]` for a zero-hop flood or `[direct]` for a direct route. + +The bottom selector filters received messages; it does not change the outbound +channel because the device UI does not include a text composer. Select the +outbound channel in the connected application, or list and address channel +slots from the CLI with `get_channels`, `public `, or `chan +`. Channel 0 is conventionally Public; always use `get_channels` +before assuming the other slot numbers. + +## Radio page + +The radio page redraws once per second. Noise-floor calibration publishes a +new 64-sample average about every two seconds, so a faster redraw would usually +repeat the same value. The display shows the fractional sample mean to one +decimal place; individual SX1262 instantaneous RSSI samples are still +quantized to 0.5 dB, so the decimals are useful for comparing averages rather +than claiming hundredth-dB measurement accuracy. + +## USB + WiFi Companion + +Build `SenseCapIndicator-LoRa_comp_radio_usb_wifi` to retain the USB Companion +link and expose the same framed Companion protocol over WiFi TCP port `5000`. +Fresh devices advertise an open `MeshCore-Setup-XXXX` access point, where the +four-character suffix identifies the device; join it and open +`http://192.168.4.1/` to save WiFi credentials. Saved credentials and the WiFi +on/off preference survive application-only reflashes. Setup mode explicitly +restores standard 2.4 GHz b/g/n operation, so a previously installed ESP-NOW +image cannot leave the setup AP hidden behind its long-range protocol setting. + +The combined profile uses minimum WiFi modem power saving by default. USB +remains available for recovery and management if the configured network is +unavailable. TCP port `5001` serves host-backed LoRa OTA files, while port +`5002` provides the bounded OTA management console. The USB text terminal also +accepts `get wifi.status`, `get wifi.ssid`, `get wifi.cli`, and +`start webconfig ap`; enter it with `+++MESHCORE-TERM-START` and return to the +framed Companion protocol with `+++MESHCORE-TERM-STOP`. + +If a Companion client does not supply device time over USB or WiFi, this build +starts evaluating LoRa time after two minutes. It requires three independent, +agreeing sources from signed adverts or authenticated Public-channel messages; +one repeated sender cannot set the clock alone. A successful Companion or +local CLI time update always wins and disables the LoRa fallback until reboot. + +The combined image uses two 2.5 MiB OTA application slots. Its partition map +keeps the prior NVS and SPIFFS addresses, so installing the partition table and +application over an existing Indicator preserves identity, channels, radio +settings, and saved WiFi credentials. + +## SD-backed font + +The RP2040 streams the checked-in pixel-font asset from the SD card to the +ESP32-S3 at boot. Text is binary 18x24 Noto Sans Mono Bold. Emoji use 12x12 +RGB332 color cells with binary transparency and are enlarged 2x with +nearest-neighbor scaling. Periodic status updates preserve unchanged emoji in +the panel framebuffer so the full-color cell is not replaced and redrawn once +per second. See +[`../../tools/sensecap_indicator_rp2040/README.md`](../../tools/sensecap_indicator_rp2040/README.md) +for installation and diagnostics. diff --git a/variants/sensecap_indicator-espnow/SCIndicatorDisplay.h b/variants/sensecap_indicator-espnow/SCIndicatorDisplay.h index aabedd24..871ef463 100644 --- a/variants/sensecap_indicator-espnow/SCIndicatorDisplay.h +++ b/variants/sensecap_indicator-espnow/SCIndicatorDisplay.h @@ -1,6 +1,9 @@ #pragma once #include +#include "IndicatorFontClient.h" +#include "IndicatorTouch.h" +#include #define LGFX_USE_V1 #include @@ -13,7 +16,7 @@ class LGFX : public lgfx::LGFX_Device lgfx::Panel_ST7701 _panel_instance; lgfx::Bus_RGB _bus_instance; lgfx::Light_PWM _light_instance; - lgfx::Touch_FT5x06 _touch_instance; + IndicatorTouch _touch_instance; public: const uint16_t screenWidth = 480; @@ -37,7 +40,8 @@ public: { auto cfg = _panel_instance.config_detail(); - cfg.pin_cs = 4 | IO_EXPANDER; + // Chip-select is driven through the board's I2C expander below. + cfg.pin_cs = GPIO_NUM_NC; cfg.pin_sclk = 41; cfg.pin_mosi = 48; cfg.use_psram = 1; @@ -105,8 +109,8 @@ public: cfg.y_max = 479; cfg.pin_int = GPIO_NUM_NC; cfg.pin_rst = GPIO_NUM_NC; - cfg.bus_shared = true; - cfg.offset_rotation = 0; + cfg.bus_shared = false; + cfg.offset_rotation = 2; cfg.i2c_port = 0; cfg.i2c_addr = 0x48; @@ -123,6 +127,131 @@ public: class SCIndicatorDisplay : public LGFXDisplay { LGFX disp; + uint8_t expander_address = 0; + uint16_t expander_output = 0; + + static constexpr gpio_num_t BACKLIGHT_PIN = GPIO_NUM_45; + static constexpr uint8_t I2C_PORT = 0; + static constexpr uint32_t I2C_FREQUENCY = 400000; + static constexpr uint8_t EXPANDER_OUTPUT_REGISTER = 0x02; + static constexpr uint8_t EXPANDER_CONFIG_REGISTER = 0x06; + static constexpr uint16_t PANEL_CS_MASK = 1U << 4; + static constexpr uint16_t PANEL_RESET_MASK = 1U << 5; + static constexpr uint16_t TOUCH_INTERRUPT_MASK = 1U << 6; + static constexpr uint16_t TOUCH_RESET_MASK = 1U << 7; + + static void setBacklight(bool enabled) { + // Detach any stale LEDC routing before changing the level. Reasserting a + // plain GPIO level makes wake reliable even if a previous image left the + // backlight PWM channel stopped or assigned elsewhere. + gpio_reset_pin(BACKLIGHT_PIN); + gpio_set_direction(BACKLIGHT_PIN, GPIO_MODE_OUTPUT); + gpio_set_level(BACKLIGHT_PIN, enabled ? 1 : 0); + } + + static bool readExpanderRegister(uint8_t address, uint8_t reg, + uint16_t& value) { + uint8_t data[2]; + if (!lgfx::i2c::readRegister(I2C_PORT, address, reg, data, sizeof(data), + I2C_FREQUENCY) + .has_value()) { + return false; + } + value = data[0]; + value |= static_cast(data[1]) << 8; + return true; + } + + static bool writeExpanderRegister(uint8_t address, uint8_t reg, + uint16_t value) { + uint8_t data[] = { + reg, + static_cast(value), + static_cast(value >> 8), + }; + return lgfx::i2c::transactionWrite(I2C_PORT, address, data, sizeof(data), + I2C_FREQUENCY) + .has_value(); + } + + bool prepareControllersAt(uint8_t address) { + uint16_t config; + if (!readExpanderRegister(address, EXPANDER_OUTPUT_REGISTER, + expander_output) + || !readExpanderRegister(address, EXPANDER_CONFIG_REGISTER, config)) { + return false; + } + + // Set safe output latches before changing pin directions. Keep LCD CS + // inactive while both controllers are held in reset. + expander_output |= PANEL_CS_MASK; + expander_output &= ~(PANEL_RESET_MASK | TOUCH_RESET_MASK); + if (!writeExpanderRegister(address, EXPANDER_OUTPUT_REGISTER, + expander_output)) { + return false; + } + + config &= ~(PANEL_CS_MASK | PANEL_RESET_MASK | TOUCH_RESET_MASK); + config |= TOUCH_INTERRUPT_MASK; + if (!writeExpanderRegister(address, EXPANDER_CONFIG_REGISTER, config)) { + return false; + } + delay(10); + + expander_output |= PANEL_RESET_MASK | TOUCH_RESET_MASK; + if (!writeExpanderRegister(address, EXPANDER_OUTPUT_REGISTER, + expander_output)) { + return false; + } + delay(120); + + // Hold LCD CS active while the graphics driver emits the ST7701 init + // sequence over the shared clock and data pins. + expander_output &= ~PANEL_CS_MASK; + if (!writeExpanderRegister(address, EXPANDER_OUTPUT_REGISTER, + expander_output)) { + return false; + } + expander_address = address; + return true; + } + + bool prepareControllers() { + if (!lgfx::i2c::init(I2C_PORT, PIN_BOARD_SDA, PIN_BOARD_SCL).has_value()) { + return false; + } + return prepareControllersAt(0x20) || prepareControllersAt(0x39); + } + + bool releasePanelChipSelect() { + if (expander_address == 0) return false; + expander_output |= PANEL_CS_MASK; + return writeExpanderRegister(expander_address, EXPANDER_OUTPUT_REGISTER, + expander_output); + } + public: SCIndicatorDisplay() : LGFXDisplay(480, 480, disp) {} + + bool begin() { + if (!prepareControllers()) return false; + const bool initialized = LGFXDisplay::begin(); + const bool released = releasePanelChipSelect(); + if (!initialized || !released) return false; + setBacklight(true); + size_t fontSize; + uint8_t* fontData = IndicatorFontClient::load(fontSize); + if (fontData != nullptr) installRuntimeFont(fontData, fontSize); + return true; + } + + void turnOn() override { + setBacklight(true); + _isOn = true; + } + + void turnOff() override { + setBacklight(false); + _isOn = false; + } }; diff --git a/variants/sensecap_indicator-espnow/dual_ota_2560k_preserve_spiffs.csv b/variants/sensecap_indicator-espnow/dual_ota_2560k_preserve_spiffs.csv new file mode 100644 index 00000000..b820c714 --- /dev/null +++ b/variants/sensecap_indicator-espnow/dual_ota_2560k_preserve_spiffs.csv @@ -0,0 +1,10 @@ +# Two 2.5 MiB OTA slots for the 8 MiB SenseCAP Indicator. +# NVS, SPIFFS, and coredump retain Arduino default.csv's addresses so an +# in-place partition-table migration does not discard configured node data. +# Name, Type, SubType, Offset, Size, Flags +nvs, data, nvs, 0x9000, 0x5000, +otadata, data, ota, 0xe000, 0x2000, +app0, app, ota_0, 0x10000, 0x280000, +spiffs, data, spiffs, 0x290000, 0x160000, +coredump, data, coredump,0x3f0000, 0x10000, +app1, app, ota_1, 0x400000, 0x280000, diff --git a/variants/sensecap_indicator-espnow/platformio.ini b/variants/sensecap_indicator-espnow/platformio.ini index a5952d6e..b86941b1 100644 --- a/variants/sensecap_indicator-espnow/platformio.ini +++ b/variants/sensecap_indicator-espnow/platformio.ini @@ -11,17 +11,41 @@ build_flags = ${esp32_base.build_flags} -D PIN_BOARD_SDA=39 -D PIN_BOARD_SCL=40 + -D BOARD_HAS_PSRAM -D DISPLAY_CLASS=SCIndicatorDisplay -D DISPLAY_LINES=21 -D LINE_LENGTH=53 -D DISABLE_WIFI_OTA=1 -D IO_EXPANDER=0x40 -D IO_EXPANDER_IRQ=42 - -D UI_ZOOM=3.5 + -D DISPLAY_ROTATION=1 + ; Render at the panel's native 480x480 resolution while preserving the + ; established 160x160 UI coordinate system. A 4-bit internal canvas avoids + ; competing with the RGB scanout framebuffer in PSRAM. + -D UI_ZOOM=1 + -D UI_COORD_SCALE=3 + -D UI_BUFFER_COLOR_DEPTH=4 + -D AUTO_OFF_MILLIS=300000UL + -D USB_MESSAGE_PREVIEW_MILLIS=300000UL + ; Retain every byte of a maximum-length 160-byte chat message. The generic + ; 78-byte preview is intended for small displays and left most of this panel + ; unused while silently truncating longer text. + -D UI_MSG_PREVIEW_SIZE=161 + -D UI_RADIO_REFRESH_MILLIS=1000UL + ; Use the configured five-minute timeout literally on this USB-powered LCD. + -D UI_USB_AUTO_OFF_MULTIPLIER=1UL + ; GPIO 38 cannot wake the ESP32-S3 from the no-wakeup hibernate path. + ; Keep this USB-powered target on and use the display timeout instead. + -D UI_NO_HIBERNATE -D UI_RECENT_LIST_SIZE=9 -D UI_SENSORS_PAGE=1 -D PIN_USER_BTN=38 -D HAS_TOUCH + -D TOUCH_REVERSE_SWIPE + -D TOUCH_SEPARATE_VERTICAL_SWIPES + ; The outer 15% remains available for Previous/Next taps; the middle 70% + ; is Select. This makes the primary tap target much easier on a 480px panel. + -D TOUCH_CENTER_ZONE_PERCENT=70 -I variants/sensecap_indicator-espnow build_src_filter = ${esp32_base.build_src_filter} +<../variants/sensecap_indicator-espnow/*.cpp> @@ -32,6 +56,35 @@ lib_deps=${esp32_base.lib_deps} adafruit/Adafruit BusIO @ ^1.17.2 lovyan03/LovyanGFX @ ^1.2.7 +; D1L and D1Pro route the onboard SX1262's control pins through the TCA9535 +; expander. Keep the original ESP-NOW target above for Indicators without the +; LoRa hardware, and use this target for the LoRa-capable models. +[SenseCapIndicator-LoRa] +extends = SenseCapIndicator-ESPNow +build_flags = + ${SenseCapIndicator-ESPNow.build_flags} + -D SENSECAP_INDICATOR_LORA + -D USE_SX1262 + -D RADIO_CLASS=CustomSX1262 + -D WRAPPER_CLASS=IndicatorSX1262Wrapper + -D P_LORA_SCLK=41 + -D P_LORA_MISO=47 + -D P_LORA_MOSI=48 + -D P_LORA_NSS=64 + -D P_LORA_RESET=65 + -D P_LORA_BUSY=66 + -D P_LORA_DIO_1=67 + -D SX126X_DIO2_AS_RF_SWITCH=true + -D SX126X_DIO3_TCXO_VOLTAGE=2.4 + -D SX126X_CURRENT_LIMIT=140 + -D SX126X_RX_BOOSTED_GAIN=1 + -D LORA_TX_POWER=22 + -D MAX_LORA_TX_POWER=22 + -D RECOVERABLE_EXTERNAL_RADIO +build_src_filter = ${SenseCapIndicator-ESPNow.build_src_filter} + - +lib_deps = ${SenseCapIndicator-ESPNow.lib_deps} + [env:SenseCapIndicator-ESPNow_comp_radio_usb] extends = SenseCapIndicator-ESPNow build_flags = @@ -39,6 +92,7 @@ build_flags = -I examples/companion_radio/ui-new -D MAX_CONTACTS=350 -D MAX_GROUP_CHANNELS=40 + -D ENABLE_USB_INTERFACE ; NOTE: DO NOT ENABLE --> -D MESH_PACKET_LOGGING=1 ; NOTE: DO NOT ENABLE --> -D MESH_DEBUG=1 ; NOTE: DO NOT ENABLE --> -D ESPNOW_DEBUG_LOGGING=1 @@ -48,3 +102,48 @@ build_src_filter = ${SenseCapIndicator-ESPNow.build_src_filter} lib_deps = ${SenseCapIndicator-ESPNow.lib_deps} densaugeo/base64 @ ~1.4.0 + +[env:SenseCapIndicator-LoRa_comp_radio_usb] +extends = SenseCapIndicator-LoRa +build_flags = + ${SenseCapIndicator-LoRa.build_flags} + -I examples/companion_radio/ui-new + -D MAX_CONTACTS=350 + -D MAX_GROUP_CHANNELS=40 + -D ENABLE_USB_INTERFACE +; NOTE: DO NOT ENABLE --> -D MESH_PACKET_LOGGING=1 +; NOTE: DO NOT ENABLE --> -D MESH_DEBUG=1 +build_src_filter = ${SenseCapIndicator-LoRa.build_src_filter} + +<../examples/companion_radio/ui-new/*.cpp> + +<../examples/companion_radio/*.cpp> +lib_deps = + ${SenseCapIndicator-LoRa.lib_deps} + densaugeo/base64 @ ~1.4.0 + +; Keep the recoverable USB Companion link while also exposing the same framed +; protocol over WiFi TCP port 5000. Placeholder credentials deliberately start +; WebConfig in setup-AP mode on a fresh device; saved NVS credentials win on +; later boots. +[env:SenseCapIndicator-LoRa_comp_radio_usb_wifi] +extends = env:SenseCapIndicator-LoRa_comp_radio_usb +; Two 2.5 MiB OTA slots fit the combined display/WiFi image. The custom map +; deliberately leaves the existing NVS and SPIFFS offsets unchanged so moving +; an already-configured USB Indicator to this build preserves its identity, +; channels, radio settings, and WiFi credentials. +board_build.partitions = variants/sensecap_indicator-espnow/dual_ota_2560k_preserve_spiffs.csv +build_flags = + ${env:SenseCapIndicator-LoRa_comp_radio_usb.build_flags} + -D WIFI_DEBUG_LOGGING=1 + -D WIFI_SSID='"myssid"' + -D WIFI_PWD='"mypwd"' + -D DEFAULT_WIFI_POWER_SAVE_MODE=0 + ; If neither the USB nor WiFi Companion link supplies authoritative time, + ; begin evaluating independently sourced LoRa timestamps after two minutes. + -D COMPANION_MESH_CLOCK_SYNC=1 + -D MESH_CLOCK_SYNC_STARTUP_DELAY_MILLIS=120000ULL + -D MESH_CLOCK_SYNC_REQUIRED_SAMPLES_DEFAULT=3 +build_src_filter = + ${env:SenseCapIndicator-LoRa_comp_radio_usb.build_src_filter} + + +lib_deps = + ${env:SenseCapIndicator-LoRa_comp_radio_usb.lib_deps} diff --git a/variants/sensecap_indicator-espnow/sd/ui-font.vlw b/variants/sensecap_indicator-espnow/sd/ui-font.vlw new file mode 100644 index 0000000000000000000000000000000000000000..45dfe8acac20974f53648ef71a31efefa1333fea GIT binary patch literal 1302608 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

LY=@C04 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


Fqsdsd@zL%rt&zA$LT!I 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 z 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

MgC|Z_(}Jr#L4) z5w!b>-<-ZUgK?9~t(q3$)-9aptX~s>38w^)6>$4xj|4{5uo4vYFzur9U}bG`W$m-E z&u*`Mb}PrR5Nm5Ixi!=*bDv!K>@&8~jD7am3J2S@T_0oD%=PPSO$-`WR_w*;SzGC) zJ|!6HqR*%#QOh8<&MCP#E1Djy3bj@eUV(yZV%w|F(z|^tw~<>Db#S5tBq!P*$Eg}u z$HuOYk6j;Io^jUKbK^)lCdQVhoSF69>dxl+)Yt^V`_0@kaB6J%UOWeXmp55Izs06cRm}mS$Adn;Pb2GS9F>cVe`Ld_vF#nFw>op3G7Axg*Zq-3zXJ zCw6DobwZ0#9F)$WaKTny%r6YE>r?_ol+JDU&Q%HDbO;rS@qRQ(4hxazle{I-slsh? zaRUhlhZDq?ChLWyfQf{?k91N-jzZ)_lxH1^5$gHb7nKvw>dYn%jQ|p z2F{%8)-Jl2W>KU(w?&mYI559Eusc7$JC8s>{&9mz@H}oreqiJTy8{C-zh>MA7RJVI z)ELKAAKe<;e$wCrzZ)C-o#i|6T&}+mUd+_y##~ab&D&SaE~0_EJA*M}HM4^d!?h7b z=WaN=GX-^DOesq3suV(BrndcvD7N-&zRWN}%S-oQ-4PAAyLSc4TnO{V!k^(hIV#*u z)jVxNiuG-67B<@9&IZqIcdmd#g9C*Jh|kTr1M*O3EY@i(&^P5Au*W2zI9hPj*xM)u##qA zQ(G?l{t@Yk7Sj{Au@cZcufo2I&~7n3eJUa{7R<}6Z@TY})EC-!>I*k%e|UOWdLx;j z6fcTNQ2F3agZLLeVzKX#x)#4vWloac_YZ*?kY*djby4413HBeO~70nh`H$VA0X z=0FkVutj?@@7H--HfwuP^(JB__|78#6i!Eh5i*u3j+d zIs2Q>=cYauDZF#`^WXgDHy`)Se16t(KAr>r=HscEkDcID-_*xqnwz=+nCnxkxt{lh zHK2w!-xT{P#VXq2OJjJNq%gfBe21^VJ@UoM6W)N7ZYBCi*zJu}6{I0eK zdnQ&9e020oEYovXB~U`_kfI`?&~NF{hqAr1V2b-VVakIdoB?;kTUdVIKuj+xnnOWRlki(UP2uHp= zV#R~~2vLQuTF6a`p6Fc2TivR`{`^pX{)Th|+K2Ls9qs-3euWF|?LF=NgANXWLP4h| zzu(@T7JMq+G1!R%A&N||g+8ZuF+ZzZvLx8PkRQY#xf4ud=ntOK1O(gL<2G|lg2?ke zaYcPA0;4HpN63q&Iy(B+r{uF$2m*J&#Q~pipJUw-4^>>eLjj#Q|`&1I*_x zTteyN3P~^D@lk0LhbEuaDF?@89|SP3J&E7^-pJ ze3SWMfnexBy}*dJB?qJ7Kp<>He+O&e{y+yG6{0-UHa2GGzQz(^cx1`dGABk`6S`I? zODKG6a^SJoTGX64`Si)hs>F2iJY$FRPyf${oJan*r)9(cB*a4>sHs;3;OEM2IlqycUp~l-rBsUeRtC@;nfzl*%TD8k(hObs)U79)YGQ z5Uy<%@KJ;%Tsq%UbPNTH&}H3wFR1^89rhILif^*0s|0Cqq~M@L0jw6BqH7i8NYO5SF$n4TsXY*@;7LQ_ZDGS zF}x0w7oy#wkB)~tIlUn5VW3@{Ob@9y)x*V_&Y-$)*Kl^XW?jW`vv*BS!0*4?ueN%T@_8@SoTy@vLw1{FH;^SL$6boc z6e@Ir)1+`*FIYc*S@`7F#ZMB(iJE$&70C#`Y_Qg$m`Y$trj)=h&jc1v)Z zhAC+5x+y&ZZ(Wzcu^vtUHa@Q3QXBPP{N7T(4g>NrGh|1q$H-P)V08*DKi7>Dr-=@< zc@q+zQhMdYPzHJIr?x?9?i=IM}ea+-9{sBxGt zq#GtRxZk1DS>$vk)UPgvwPTy7lSlc`*cPdY{I-Yd@p870$0VX~m4`CKy;B18H#diy zIjn&;ftM9fY;)Jo@eQ_kQ|cd#o5P}BG~gG%&2Chu$6R#(dtq3QH6?Mv%|@^(lkiLH zuR^JWZ}EkzZ@&57@P#@!Z@w=y|Nh7CVXC|O{`*%i2&-uIzBGu=(Kp|F|GoF#d{g-J z)vjKB>4GAJgl^%Y|DRtlOlN@}jy58grEen@7eqgqo{`OQak5}0J~R7jxG6UDy)$Bx zmr>>~E2pQuxVWD|)0~8W?p!JiDI^fbLb;KPolC_=R29v6T|W1(!j)CVmg|AThZ@9} zpZ}_=+7`j|7M#k%ja*xzajrGE2z!r{N|m59U4w4bqojmjhcH zI1kgQ>28feoFe?B)0(7EdHw!m_c5pS#Ic&^pRYN7qSfmhZ>+5ia3V*eq{Lx=1T#&t zj7%9jL)))|NunzpW4Czt;DKA)w^#DF_ahO` z3c0nvvVHs3^y12X4!pLOUt72>SlqAe-5y(58`E%**Dn4Vh=K68*T$LzJ8jgz*A?A+ z>Aih>y6u$knm$9;cY7r*?r)(hdnLCrew|lJRO?pwLyoO$DoUkLjJKQ@tfUl%M8&bthO+-Cpc791i|8sZwY*r_}F zoC}?o3h4e|Mz-ATah#3o_!;!IcKi zc-d`sFi$Nj)7a?nu4w)OQhnWqC#8=S?p{nZ-LxLGq3BnSB156sW}wAc3}D)2aCHFX zEUcuVwWZ|^_|YK;I}kXnqlkbw_j^2YgNchWdY%DVX_{sa5ooj=6s9pV- z4u0*$H(p=N^0t17&ATHPMPItZDbc@t_l=7w4fPEr6G8vbyYFTOEk+}rN(akdPRGz%+GWP~iankl`seMg#e_S{E{u`~^0(N>_w~j}LYU&_g!^-yJdCK~ zcSu`Q>pjYzhmyo2P=aI_FUh5+W+R|9S;TiSUVvR&8-q4e_h=J$b{E7-A*LbX+GR!n znq#~yhXoK9Vn9Ca1UmfJ7S`6H{bS+G+U@<7#oKF1pN~T)7e*Gc2!cqPBut3@meHF? z-HljP60W4`5=HeKBfBRP)#r^O9{VT8h?Z1EZum18W&h!3D z$Z?+fw&Q&B+d>+i^RK@B)KeH97SlIz_SCokwXu+Ep_cUZu-3(AEPSGryx$r+I{ICu zdqKWT7d!nu9n&G>KG-)m(`T@+pLx2zUiI72!!$=mhCT%c3r+6ud<|cq zM;<9KDhCECUBe@Da|MgzPd#G#~8Tc#6WYm{JmVzM{rMqK>#MW9jOf~`RiBsQkmp&yS1 z1jFU(QH8J8XoMohAR3-6QRm1(kp#k3$y-p2Yn&*%X^(j;IXy>mmmrr#)!+hx~0*oLAXLVbK!&gu0SL4T%SJ4sN=YyVayzE+uhcaJl*lYz~r_kTsY$W1K1G6+yI1){Su>CV#nJ z?{g_}L$Hj#5RSRJ#qs3EYkZoxsIOf%b+z;$E#b(8h+~VGgQE)k(yyah8ZS#oqKi;l zH8CZQg^Vi^y?GTbY)g@+1;Dhx*CNwIBJY*kmKeb30o~rYc{!_mG>C7Wd-{2C z&zCdAY=z1s!5`iHXy3)}zWc7rUwr-b*FVy5XlZCaj0{u4ht{M@GlPAmIKWQGOp(U~ zGl3$c9UX0(IA31)+(gy1x@X_b^yJc_adTsG^25nr8#gy5rzfXxC|+0){(`zeOaAoa zf^D-nVrY8FVhz*8C6hOhG-l1chMK{>E40xJA9}%^!QzZ$xa+pflU;_1@YOPbS&vPNy)!S)R4SbL{+PBB-{pwu>>qoH-hhwHhcmrul%< z?Q=A9bBcrXCf&{R%HU$AT=cr$Gh=r_Y^`thY%H0>r$=|e-HqLBWoqmeoNZiU!<5D6 z#8IpAfA-X?m%Ce!C&kSNFTMI|%cW<3rudb&=>xp^!Ip&i!3Y2F>8GDAfoI$;7qTp) zNVLDR8`{Q_xM>FIyLYyvD8;rWa~oTm8(XuE!`OXIM)Jeg`oIhGq`GfraLei2sy)mQ zpLLG7+8VsX2!8|fmeV0?Yqx@gOw-x7wXnEHC`uh0^2pX8lUua(U!eHH_TaYFwFMa(k7{Aq0ANl2W=Y zMCrUim5Jk34q8~8$_kFf^SZ|wgcqq@jFWI-pF)LKX7^2S{??j8z!^7KnWrgGF}Bhw zOss$W^Pm5nbvF5rAAb1ZfBE0V)ccQu|Ng)H2ORw4KmPXT$SxSBJ3pWN?LSWbTyT@~ z;pA^8CntZd_~-uw6vKaMa{lh0{{BPohvL3d+zKYhPN#{`Km55y*2z^`j?Q1p#n6w{ z#<}b@ceysS`lZLC)O`7}`xNP4U%vc{v|%p~H8u|A43KfBT@+qp|CpXMPD@&h{R%827UX@$bs;#wVQ#0j@nn%kUMp4imdJoNcy&vMV^ z=Q0>5#j(#frzWO0RYwGqd{aGBn>*{&^94M`Qtr<;XL@G1Zi?cc&*ysP7~F0mQKBw} z4^I^W?X=4fnDfO#G6LdX;vy5}Tx^qtnY`5hc|<9q5`goMvgqcPQ;~QUd3ZLuj)I4V zz>FV8NAn{yQ<)|F>%Q0NX}Kw0oSj}YI6Jzqy1u~4+wilav+Jv~it#kRy1vE1LD?v$ zAI;88&331ZChU_ZPMp;AaO_X_`SWbMjWVp!7zll-wPqC0LUMp*P1s;GTRi0odz-1ILcJN2187C-=q2aAnsU9DA~&qUMk$qN|ecjRI;U& zBjD5!O(j!)Y{h9H)za!`$eBzLLTgKl7lz92{1OKkze)|9&t)MNB}?N9OyvG`))3zs z9CR1fZ_Uqg;(^)>&awh@UdN<$^Uf?NG>?zapaYz*lSVq;4`w5ebP15pf@ec2r=>#- zAFfbrYj#kB0mmgs+rHPqjrr7xlgVZb;JS8ux`1zN4~c|do{vu~>x6FKZWhdTayG>- z2u?0_(=tiC-$vyXe<%*qS4d-og$nxr%A3bW= zl^kJm%*M-UvK%KX0pmm#BvpA`M}?D(nQ|?3fsN%Cuj*5LA3j`Jb<%*twI`XuwD|DJ zs@fv1b!uHcSy5JF3|h>}PKd!RaVHKQw0ZT#7_C`!5TTujD~Wva$%C!=mk&zWWvSNr z%cI>-KYbE>^5kWRo8t4APd+BNl8d5~CrNXGsv0i;`MK`UD zGcDG{T-T)7HnpY4$0sHgiX$gUmV$w>fMo#J{oz~`29N9w(HE4 z>bEA#RfNXyW{_N+>s**K9J_UEZ5rX!EtWsEFWU;YXLe(-5Q$q03qu#97HsYdF3c4- zV_cY+fu4o0EK;vdd|0dS#p~l&oOmpxLzzR$H|Pmshqn za?2}0IWTB>WrGz$^xOE-RlK^KOM`Q38+^(+a8vs-$Hs1LaL~}HIzRI7wYBB(+(ci< zH!gS$z7&WwT{hdp3;fKsU9el|%LgP~&>`vAv&mTv=Neh7Qd6NVeC7GZlZQ`MnpKb| zy1S_*ayV4cb*d)HQ-XPQ}umnR(CspMO9T*rLzB!i;OdUreHfA z%@o~GoqCT^cH=SG>cZf-Galz?9cFKE_{0-FkWhy@G_$o&DE?zF9IaPn{Z<|KM;j5g z2=PEwDEZOmNH8W;@URSk-jD2rO!joB(#1wu-F-t+iDL4>v|MfJBl$t)ly1 z>ey^*fbmNA8@NYR9T6(n=uR26`f|pn4 zKYl{<=a6yf@z&HFHyKedVdpiu)M)StTtgxvQSwt=& zFYL*wScBW!gL0i!{x)8nZ9OduNhoAUF$;;GQPz@dZ(`y*i86Qv2+SnGSFv%D^qxj;l*1x&@` z8i1}rAs3u^0zNf~E16jmgZh>U01I`-Nx2~An@s3lL~1U1ye`taetdFaJzt+gH=nH7 z9N@Ec2H3SHD?~WaG=vUPB>o{scDu2wY<(TQiaWcab!&5d7yLFY=qIwy?`J!!euFx=&YKH*$R2<6JC#ogPLH@myH z`}(_gD6BuGJm1~jd+oJfUb*qw--u4#-MuTXz4rR+ui*+^=({&w|C_&gUA)J4_qG=P z<`=*Gw_@N}!@<}7lOnwsX3_j$#2OFCOqj_OnY;jT?FolPQdz*BCrq}N!}pXK{DffT zd&+|=NIKFV`pOY{`g(g2p9DSSD7o{qRMX>uOPKOXh3=CY`=%vgabdz|Cz&+}8W>O` z6Up(ptHM`TFtyl7m@!2rs2FS!zzTn$OdKl=nRy-II(1r16n^yul{3~sRqf&0+QXG% zs$_p97$tG6S~#p&2XpW+@sEt<^5xb>VC})mMj0KUe&@-9qR6IJaJ>!FdA{+O3-5m~ zuRDA8sIfYFDR4FrIID(B7tTUzs0$0kfHOFjJWid#fpGY2-BH0H%?G5u;j^BQgaaSh zxw}Myw=`6ze2v2&zu((pm7iN_r|Eam`AXwDxHgg7-p-9LH_;zk$uV1aTP0g`oCI@o z##eBB8#eyabk(^-`1Uomw^L@?n|!oo8Z#Hc)}VJ|uq;o<;9$sOowj$-#}0}iXm0I2 z0i#hcqQC{HhFj#0P7)6vm>Ps!P|;~BBPU^?03X*Xb} zsnEW$9)Krqw>E8bNL^QL%WoeaFEoN}>?0sEm8Pb9*c5L_Y8XUe3q?j(fM~%l;vx!8 zlIbR+dwW?a6->*UL7zgk2W=qj7$$wWU@|}C@ur)`gPwS9JD>1)gXwXfC$liVon?pD zxZwOku3vG`!yfa^R_UgDm>o()eOe6C6CKUIU{AYA2qP4URVW(O z{4==RZ@Rg{r*d{5AVrNv1*_DZ^e6r0>MW8?p@XwpW^gLHM^mY+-y4VoywR2{a^FON z6^9L}XoK{aQ>?`Ea?E%`iw%Cptb=@Embhma(&f9dp4 z>}gEgr0V@%6O;V`5+Y3gBQyjIJ`Bd-^%{OM6-`x3+S#W(+MP{$CD$A;2Q#Hud@nfK zQXfqrI~VM!uc;T0N)<)uB&_I1ETT2;m*GTCJd(=mha>Dq8kp%q1>;&!PI?fWXQWx5 zTx^k9pM7dVnSf&j#?n3&V%Y1I&4WwSlucm@463pHJvmBf*el_m8eisWzRh;GFAb+@ zoXZy|B@bw*;lxL7Ez?lbaMShJaQxiD>Z*DT)ErN-W^z>~H|o9h3nXQEb+z3Ic)Hi5 z(&m35n!F){Z6STuQ=Qb^*N1Er?iK_$&M)0B%nZ2IScp0-WDQ!Kp^rc0aKx*4stZZA zT4!eN(BBb)Hxq1%ZO&K+4b@dMJ;w=gJ;CO#hOGGmJ6Q_rSu8)d~H0VfoOhSPM#;Eoj#Pv%@25dKGb;8 z`DAFwMdN*7{ZkR5A7ksE{@ooqJ5v8t2bZ^YHZN3%sDG;cv*YWVv1+M*sxRDG&#ey# z4%V^ac4mD2!fEQCx`9w^pkujD>Yudqk-T-eb|Ows1W%v-aay35iuDhsfJd2fv4vhf zDEi*j!cxq}UB!N`cBzH%X@rE$zE{}9CIP{xi*7vEiyLOF#f|BdxvR&d^Cw(O0TYfj zReSxC0BUf~J>e)5!G7)mwvs6}t_>CjvC74U_?1{KJ(764TZV~nyqie$S?}L&5WHrG z!~?lilBC2`{XkC^n z3i79t$?j2uqb-4`X(d|#t}yu z*GFuL@U|xH5y#lobZ3oMaaXTRI_-W&DJ(p*pjwtr8;niDVD_}J5ZquI67)%Y*-b`w z`CIvkp(sAjq_;r9yP>$hRJ-b?Sa zq~eAZ{^Bq)meWYf0-HV;GAKceOINB@7_cq*Agfu8TlDY84F?* zL)fsyrtn=7a3O4%rPz&9%DIOfixRHvC?%1KW#l27BFfm{r~^($o&{Srt`uXG$RS&& z@L_ljgY5&&7O4&dhV1A%TbJIjB^L2z zXMJE`aAq^VwYk4nx~6X3#&XZCsQJm6nVYL~?WpC$9=5NEToz8P;fW&Lx7RM#UuEwO1m4z>b(448#Sp%cQ%7*@>+knxcC;YjY zf)f2XpQ@Lf8|?aIH{{oL7xlM0Gc$AAe0Lyk>2uc*#x_hlFF|mAmfVE;irWV65ARW> zWc=K7jSu!rvj^YlDOFiDkm+U%=p&#LgS58ni~((W$owT*6%ii-o-c?9#fCA#;=C!gQ_x zo!r_DUBpYbX8HEgqKPY=+hDcO_KF0uJi&pI+mrOz9E7XQ{fldYpfn1=dkkbSoZ~^2 zs0RupDp*~LCOl<{GJcFt@_A2L-s8!ad1Sd&0WU5IF5~B6u*Dwpyx*Vq_ys4zdAhY> zl=&^uZh2e;!}jKW#XOM{=nq;a9dS3)C#DnAmf5ow zn4LB*dZss~SEr>|`H@pjudM~~?s(A+t4u7a!|^p0b4r(^gXtYNXs6vRgEm;X#X|){ ze9(=$^ysBRdXU^&`>wb%*lE1++ITIjV4ra>Z2Q#2?S{e! zU7%3WAY31{CUvWL56|yu6!T%HD}Q&MvBN%`ON@{2qWMTvBxPCZB~Ex5qtPqV3wl&Y zYG^u~$mOP|Cnu+;bIZ|WF1Ij^`9^Lz85mlbo)o*4p#W`rVhBnYp;gz-{QgZ-n9aF4 zd0E@z^ve;8d)xX9o_^*y`};k@cVc~zty4mR?K61<8z($XEM_x;GB7n2RG(a^>ib+Q zHNJ~c#oVFT?hO=t_S%~tE3dB3x%%NI;kvJL#jj5LMg;ej6Ur|FAL`CJ^cyIZFy=DLSh-3%HX*x)I4f{9xp6dI{N;LJ?%C3f_= zv5F%!h#{U5BoaQKufk(-DAeiBb(KF-6Lc4u`9eRgth7CCPhIoF73Ic##ew70UIv?L z>;d=*!}r!yKGJ;JU_>d9!Cd{-B1cwZ87Vq#lT=n03N=?6XHQgC1=>Y2n20#={gst; zU^Ce;>a6__S11mYRaAM=YKXMfSCkV{{ZT8?+H>~*c;%&6Ug7_&NAR^*-hN5&X>=VM zI(pjAG=?R=-xu`MiQy>I2PmT;2|hnAN}~D_l(olh&z?TMs__s-IwAwh41?P&-wg+wtk(Lu3e*=HN^PG9rq+9JxRk((g=;X82ND0#hIlg_w>sI z%cMuFXHJUC7Tut|*Sa5K24dN|iOVc<+=L&W+~1$HShh7a+vH^IU2b80J(dxcjlhtO zz{p@_%l3~#Azak4lG)B?_L`Ytk`!8bNhTos?u@~_F@w2^v0x~Upe!qu6merz9?W0w zJkl3nyHOlqOX#H;pB%@_Pe`FQ6zg zl1yfj$q|ubkEA#pf`21gl`VAkHL+nEGNF{>NG8h!hL(Xmhh_37&mLLQQk6_Dg`MPx z=4>=diAy9brZh1Q4+w>m33fY(eg+2cjJ5p%&8?*7r#_=Rnx^#kUSzy)Da`p?OG+#$ zE}qr3#G!}Q1!Y}a$a8U{fEOtGdn2+ABqR&v1)F^q((6p{3~GaeFj^%PBZdGQAGl=~ zyLCf0L&p6BFv^U?jrrJ$&WXI_8)xbyZIk1lWP!(|S4`gK37PPdn$(lP~Sf@@s5p`x3bK`6qkjzJz?04hGHM5w{ZLoWJwg3&FI5LcyGltCdy zvc63iQr(C+2@(s{l`5(HDy+%j;Uyp@sFh4z6h*)%xyek0JOCpEfi{0+`TKr8uTQqL zkTjj~b2-J^MpfQTSB=0Y0i zW|~zsBx3N>Pf^;UD<%f-e)_>4_zt~q1{$9V-n;AQdF$~Q%PH;-Zn4Kb&fw{;Yy`ww zFs!XXQ34YaxHrgo;^OgBhAISq2fX{iO+9s*Bd&ILKmF8p?%g!dZIX3xLh*iIhxAu{ zo)Bsjd@N>a;`oX56X2kyJs52FwZjjN2L%Vy;3u$FH-bAH;hz$|FMX;#*i^vjU@+|j zC7f|5cuf&Rm(RI0?8DbW`c(#cd@w!WA~eR)Ws- zMVOIW*$Jl12HWc4#bi1hWKz2%Zt)iJi}tD>hJZZ~(%3iNI)_SiHJ}572?nNY-RzMb zM`KsG!XDef-r(nczQ48Bvmf&(O;6h&WQV%k(1| zQ-uOnk1^=NH0;Iz&OY#1N8%?cDOm(7S~xq(u#V#>{BeGb1#borj!VL#7e?#Jh(OE7 zEfh73J9tIfLmTGVTc|fxdzj=A@+`-WgLurIEVME}5K6X?CU=RJGWzVS)m8%0de+7D zkr=9EkWsUt-tb1{?FI)oO1o)-iKp^8=dhmco-M;h6_vGZy>4ie&6G5=rD8V7XKXhX zz?2&r%CTa8y@%F2?*=pZ!OE7L-Y`Q-X?&q+RZYc)6*bil@rrEosjuHyrgsH1+1pU* zaZTCAjVqe57e9qk?%m4J?jLq{(=gvH$1?MIHzDq3SkW@e&FaJ}dFH?$tZ#As_2A9- zPVdU}kYCzs#E4wEhD>#@Y(TTClZXA&Whr^ef;^8AXP};F3@)&6c10m*^mYfAW?k zYOZNEat%idYjGF4_(D;wy}R_E=pU$7ZBX~cmjd}yw$kl86drd)@c^SddMD<-m6f&; zB5K){!H-eRz_+kEfBu!}*UQA^7%@*+uP)!$_XUvb5&%9c>b z7&SBAlH$t zRV`dKZ#-i_9j=w()}32-WD&V7X1OPk3bF=IrdviIKZ;n#cP!ew693t;27A+QGUKn*LJWkZQ@VnL>^8eL%i}( zep~s%fJVt3W~1IAF)*cz!S3@8eRKU3@$eUFUm@ zE|b*y@OU4o~pW=1+y)+TEnWZ#if55wg{^X{nD%!a$Pf_W-^_OUD`C zrK8iD#1#0kljckdX_TqYI(441FFJd78eR69q@F%qU=hat3a5`9Jh;D_^|Ad24<5TG zzF<+)V(Udm{^lvktmUF3M?M@*;lUJ6+yBAXty2vvoHj@Au!0pPKRPH|Q|qQdn|l64 z*iW=9{1!G0vpu+-Z4xzX#}H-f!7ci%fhP89!>*PnPg|U3%Gp0AZuZ(PElfKWHhM+4 zty{&pd(b97jm@s<;`7_c#KgPJ)(-S()7SXKyJ{7>ihLPTsmJtfzCKP;DkuJlIb?Mg zrVFRDJ+)EU>YAFa#e8?y;Vs+{Q&v;^_G#{i{~M;2*&61Gy>0bvEm38zFj&8O^>gi6 z^;no#^$BfaUDiqAhI(4?CSVXbbYFy9}Yy|_Gf1B=9-QDcG=9)(CO@(XH~ zLAch&V=X(pN(w!9WRlmd=F4c>=7JpT4=k1}l6HPWv3 zjw_mHLv#q8rgm;|ajAtbJp;~Km>IlL8ZSP;ei=`b{A!vHsjPN(%rEJyqbBnqg2klo z7jx9>W)JPcYUiNd25`>dGiPw|n9rntJnZALFue@9Jas=seg(&d!8Eq6eU@H#EkYXU zR%Ii##f-VErIz3neIwbJy?|l-b+h{z!d`)350>I^G*-%N30)GyUH@Zd1wwHbY1dL5 zcX>=0SBvHko$*C9oqM*-b*dnI#^zMG47xF&Ruu=CDw&HZ*7TdnyHPvO607r}1$fn| z6!`+3SM4v@I}%a}PmT8__Qk7|hrsh|&g=x7;vfF-ZxZ{$aBYI)O{h}{{JmxDU=9^Y zveep)(>BR<$n2@n%AXlJsyQ2tC`OHEJNhOX9o|2&zi&c^AVh9x;0)MKu<3WdInaC- z=fgob>{%MMO_>_PxleP(wx3fIC9=JmmC5G95-^sXSFfvSfGVT8?m<-vQO)Au)y1W& z&Ok+>HeNBqCE?`;ujb2DumR@AZ4!1uH-(G+G~r1m3CtzJC1-d)<@P%vo#qiHf9LI6oz2`ara)-no7pp_@$Hy` zXy%u(E3k94zl+D1bpDJrA3O!d2S0jYcY}Q=5pfpG2~*LPoK%Ur^dZ)dtk;i@4zzUm z-4LVwEj1m-RMrYZp#;WJTT%1IBfbV zr@a;zw{z4>iY)ehYiViwI>4qUIJdpD)PODyT+Z}<)nV-S^}^Etk34LLXZsTX{1Xm- z84F6)(Z;#Cje0&H+6P*9zyHHS-HVH-4;}i^`|tl~D1U8f2^Ey@zklfc{59c2z(emB zhu#;)@Wb~}9pUZYe}8Cb2>c`d9g^#!cn-b)8uaGe+z<79V8ndt!R;kWK)Q&*h{VRA zuSziyCw)Wllyf+j!%XKSd;8>P_IbgAvj-)3nSF{!ERYWq zloxI9Nv5Q@OAzPOZVi5@i1`j z;o;qTTZiLe?1ix}fcNhG@CbPC@LqiF9X@P94j(z3AO4VS6|H+e93CdD*4Ev7hp!Lg zZ!baZKJp>FtqQ+&xAtFn+IDwx1#`Raae1^Wl{}GRmQeat>hbL;&h_#?7c)@E@&8Pm zvxJfd5;0d05ETe0AshaMxIWKQehD|vqg`PZa=rFTTF1TXwr6?dB~N=pZz50crgn5o zNuDz?xHmq7e|*I#UJLRNCSvD)Z+Y&Lx!0@mBOEqh5(PgDE;CA)0+KR%QmW*LjR^oB z;lzRxKFzXtC;m|F_PJ@I#JM93ZLk_~3r)_^kA>>o%$DD}=!`|GpEC@-Ndkyu({Q^N z$p0J|)m-Ew*=Q2$Wk~kYkR1C`KKf+a?*>tdm{FCFc{z^QCuP*s)uR5VMcX;M+$Xi_ zYPzFlG(d=|o7w5ve+*46{4{k*JqvmSI#^jkuPUlRq@@Osrb{KmC5t09N=wVb=&dAZ zV`Gp9VIxB_b`(>@+FxVRa{b6&a~;h z&WLYr>hZ5$?dkvz47_)#v+L@BFx1sCFwoh-(w9EKb#`_LckwL`3^Cn@YoMdEzeAC2 zmVG!n%iOQpiD19`Cnpk9U!SGK%GDdIR=)e~m8;95)!VnP*|g@}U2E2?Lx`LJ<3ptnTp|)<*%6Gq^^w~hMtzT#9 zQ&!jYc2~xyPaBo!%sQ7os`eQNWCxUkO2RYzrW7}@m2q3riapSs$57v##Q&SY@u zQwy%$6kGZ@?9#_!;w61*jK|Bs2OSsC|4RC>=Mi#i)FW>Fb3}>8b>@?ts2(?b_Ug53 zS4SM4qydS~IXo>qnyqZfo_)w&2OAyYx2-;b+U>%i z#b~u!GKbb}C;U35lB>~F^VRKz29z07o*4mZm2vgTN0b_%H7g%kY2_S!eV_yj27AM( z{euLpJY(`m@i{xrDW9|0_4DqO7KR<2o4jy_QGuh=KSASkF!V5z84Cs$7~vjV|f(%Rqcqr$Y)RU`t}qr#)}r+rnnlI2aorOxN$cb-mX4S>JT)gLZ$UI~skv zy@#XV&ZUxr%b7DiT$AE?J8sSe$bF-uAq4jL2YCPINMB;#^zQf@-f(WR`JmNQ4&_t(ef1PP=Q!>U z4>l(ZUzS*#WP8(%^ z%=|TIapVUQHk?S~CNt<#)261zMj77Y0Dy;$?+wVtta*wWtKHM##%laPY}WHqxQADE z)zN>YQ#TomvKXYb9^fob(E?*A*%{`jS)gC1@RbBF+;P}~5q3TouDs3i4}pE)s_vB! zl4`k3oMnbna~PZYFZHt)Vgo0BzyZ!(+WEG_Cf)~zExHAGoX87zJ^(9XIpEj7$gkf5 zV~bcuK?&}%_)~^fwnLv99X(aMvGx**a#7beJNL>fugvjHRI7x3VmT|>!kjb;2}LxK zk5+>GL3o5uzD59PWSN?nnVKB2h05vT{QRP{v(N=j(Yem(yAG$ML^JwP`DC`q=pyEm zKl>dy0QQhpsJRMWN5%Lr(v$6#04^`Bi1QCQ2onq2V$e+6d@>UB>D)Ag6I^4F6hdR!NOpsyTF{H7!N*lIzRXj z0n47FXxwv}VBK?X_Uv}8VKurtdAy_Bm6&` zTDe9+6*bW3#7xT^!5?t0*Hw4~M}dbHQ$)F5EkM`VKAa7;90-4R;KI29{++vUZoeg( z`x*Jj(!+iR6t=cip81LP6*DF@0(;ck`x)4HH6N2-BP1druZQH(`V6=DLT9>FxCyk- z>($HTwl@g#DrS!&akXg`+I=g^Xj2qNu=SOL{jRndU7@qgqug;ch=LOnf*-ogicBwG z1hc&vMhr+D92yn5?I_@>VuEMpapkiHHZU8W!r87y ziVO4esOrE;_E?EabU~gxT`0*=$OsqAp|Cv{IPkk2`(S3pVEZP=l#jRL!pIR~jtoa{ zyTfM1B7*E4!IAiR1R(QkoRfYbkDZ%ku@lz3U1|IQQZsAB)}DgL!$6 zuhR#D&)^q(!wTn!x6duJAIcvd&R@8Y&u;P?g2D)u@Gqu)jt0Dt ze*#=om`rPpI#q&<&Rz&8>O-$+FzlZw8JO9dD&djINhS{%jxl$j{X}8Y{yuq_;Qmbm zV5a`b;z*qgF2pt-eqn-7rGb*7?Jf3)uSA5y7o)Ir9pgp(zuwnS30tuh#tg=!{6W*07%t(Oh=^Xd`R>rq?l4RYG$xN(ub z9j92M5{#3A#H)p=gn}fTKOcfiy}#C$O}fe3Sm5r}>ZHlX%|2kPVIQyTwbielON8aO z9*Z`)AxT|jl&P0w^+;5k!G^zRg9$8eL@o;jfn8n1g~dR`aSy}Jq6B+NQ?85}$>5Tu zMYVQO7BZw=ma#1}Eb~)x(YdKi2s)*W!%{GDfFXUdrzd6L@QF`fUCO{_9v_%+Fu>0y zf5#@jd=WJ^3&$I@4@ify#AbfwAGS7YwbgK=P2}u|3!Ud#hSoChqf)wGn4dmWW9j4P z{_!1J8rt7?I#YkzzIEcx^?5FL!Ijz4q$<;vOaP-^6rCt6D8mpr=X1zL%RZ$ojC9)k z_%Pi2Z`}BxzW#$*=}h3vxLfjHh~7>HUQ2J+vQ5NO?fMjHDW$fS-Nc>->Bs`^CVv91 zT(4c~%gH45KlJN_Qlkgs4mO0gXjiJkYy?Q~F4TAhdwe*ohlpvetoU=7#~=!=0zV)A z6HKj0u=9Z55>enYwQc-Ut!rZ^e7(j)Y)NJdF}F%ki&XyWGWusc)Hmvest_*(zYJF2 zD}nl_>a6$CKVfaG!Do#iJ4dqobNQ0t-ifw$pGO<&>q~nzYja7y*PzkNZw#`AA)W?)onr35NpLG}rZb8iktpdd z$0s*5lf23$pYh^eHvDO{YdtvtrTK z=6aJRGFKaA>qto)EW(~UW2d-jC!>P!!L9zCEH{x`r`|rSv^X_3OzPa}Az{XpB7AN` zEeoI4l`_2fDdiWqvq_kIK|sU$ELVG7QfW8O~)$U?1zxhx)`hM4I2aef)5*y`GYl3P{!D3Z520o>de07UQTyU%Z7nMa!I`fn$Hp&)1Sek1 z#`e^Cw<~@VjEqf-+Gs+%mb67J{&H9>TiR5LjkpbNW58_>N45T4Yd2u&U$55O)9<=0 zNtPL!21-JczCJVs(5aF}dy>i2Sa>bHw2TketCX~Gg%3qz1C_7N-Rx7{Q^}n*XfW)E zs{1Q&iZ<4vK6=2HR$i|ZbR#Q40~TZiL~1j5sbok5lp%;$?L^x}{2A9I>UN=;UK7sB z&jv8JV?URr{8YAc#&2V9U1d{8P5TD=if99jodYc{UW#>nB2Xq*U*XG7PcP-rMbAM+ z@k(wEwzwpa!KVg=F?lxv4pQP0d z9eH%ra)$TuR2cp{pb(cY%9<)PAc%Hlesl5 zn_HRFlK5iD9Tb>o5>Bf5ZXX>jy>>hbbdPYqX# z=OD=nRU>$yQqC!5&DI_Kk+GZccN-_TI3v$cJ3oXfSE@u$FN-ytfbZdzx>A>;x-C0I1^uj165y|c3+sWxIp@A zwH2zK=jp$*3|_i2ePzI`iR-k#9F*hLg~Beg?FRahx-Q=$(~NK@D~*_6I98c_&Uu#} z_q5-(FcA<}*h}74Uzcq!^IQx#H5GJJxkBw_LiMFNg%YpS7c!;E)g)|uiBf_ZG0`ot zWwMp3jDdD(>qVfNlw|Bm4%T`uGvw^1BInHgBYg?uh^;s{;|`W0js=%D?lMdS2lnp^ zX2P6~9A$0LCmt}TmQ@VEFts9ovROZ9pX+#5J}mCLNbZ5s*x51pBP#tdJJc|O0*rQ0lbi4p4`g+H2*p3$ zyO|-i2HR3gG*73bLle7+%JsN5) zBZgVQOfd|F%bua&C??NT*IQ?0M_$_MHkvId9)jR_kW~Y@Qrzk{x}bABLI`+ILf{30 zPdwP4TQ#d~mz-2%l{uR#>_^Qvd&~Qy4mVpn zWt+?IxULunHg@_5G=KCkdbr}@q~cW5Q}N$cZ~4lk4^8YT3tv|zI1*W+zL6hx{bFR~ z7hOMOOUh3(Ey69CpRzgS-FL;sFF2vQuy(PCM*4yr{;5+|6O%G42CU|`(mV7-Qb4(ceEhpgpj?bnE2B-7>%QUg!HHllr01q#H} z#YaP1qQmvOHO)zUj{^D1p6JAoPibQZ1}CWv+U#4u~~aTKXQ@Q_d;e zjPBKKr26l=42mIK*wHTZH4v{ip}s^D25%yOoKy{&k?xjRpmPbG6DB5m={gg9N~&e$ zHaLVQUx>}00?*NAkqStT%!MMK#NEtVTbOCKtlf%qg*IO{%}~qtLrn3YLd)nwD4#i7 zWN2^8=D;+u47w^eK3AX1^X^gf6I7Jw31xe=lguFf9V1O+Fths!NrTB=L$-z9RnAcx z0m8<$XcxD5_c(iYM)=`(Z6Vv9v?B!XhXqkDmrpp}+ALpuoCHx#=~EJkdABGbPM-Rb z5@>uppoqqO#2fn5&U-FFf4;2G;FLLx2=gsdJ`8g`qHv$tPdd-$Fd}Pcf4HZH<4>-; zWtH{ztvgHJz(VOly!4jwY7G^Gxp2fvhWR(-VutDY88f_f`__%|$@yt#xWT5($$2*y z+E4$*>Yt0+8N3)WgoAfcBNrc7eELZgGE$W&9xcuR2pLwXvGXRnsoo5-1{8cTDd5dB z8>{mtPml${bJ#;w(g3wR)JmW+`JX2BXr8ow;)&euI_R)6zOveIEeyWdrqFfCMFehf zh(TB~1g}lcOkwd9I5D~fnBagpC?~PHuTWc(fYCPQ7afSTf%(Rjr+54I?G5eiE9!dc>l=*frFoHcCXvKt z@fJ#O+P**G>36#c96vkgA&-v@9P^kynJPOgNi4OV?MjGJUg^!&z|;%?4CSWIu&z!@(np* zTJtzdDhg+_dvXo=2II-L@5wd{3Gbo&iwarxA3sh0Ku^1KYNhq*rv8CT1O2XOcU+;5 zxMCx-rb}n2MFm?H>bRzfp#vkv1QRUDNX$> z&HK1u^N8DdFI;dx7cQM1yn6N0rFniXTo^=ztL&wWul8Tc3m1jYPlF4>g{$W;UA=yN z@zOj89Isxu^xojr!AqB}n%|zEoH_H+RW?x#p1(ARYP+k~&*Z? z4vQXFuj=Q5oxiwbzZWd)@AG4$YH#lgg_#BhRHqybpa7wL({s?K=sj+~(zbEYz(=R0 z?h4w~axgG!G5hzRvD>aKmKXnN%Y5ItbGsBuR|%$3B~1iZhi%`kbBx=mHTPSWb#gRbI4Q`2nU^l6}doKyQ9_ra;s?xtv9>fB@!$idPUsKm~n z-Qv>8iIC&P$z|H4ixJu1>O1+8>*$I|eY&26j|)J#i<8x#8-<{y$d_ zbgHFrdM2CP7qIGTzJhliv=|sN-MORUtpfbkowq84w1VM)nfM7EJdh5(C0LUaVI*Xm zUK1B75AuWk?p-LM>$b$bbd`sjA6%Ml41rvlMp#EFIC$w;u(j_mi9vwPDT!H0=Bd`c zOPJxgZ?%2vFTC|n{`UWV_0@o1{Yk*jz50{*C$Bzd4$r?@hzqYiZ}=}?JrkdK^)C&7 z>(y8P_SILv74WM8Z}>~#UsC2uq%W18dfO`7Jgh}yp2xLhujc`Vak*ffW7gwdCeizFP>x%_ zF1ZcV?^_DYm%KHlxTEns3uWLxM{^zhU5gA#-n-PaQ!Vh~TqmYWY^T?Lbv4S`SwB5G zx5!~hiaz0BqdK4ihgVD=>!oQse29lDI#fx+%>`-rhSOfX>k3p7B*@mC8|>-vx}D>E zPg@Vea@?q+*08Dtb=B0hpbk?}6Z;3@2l891oGB)P^l+3im}5p}P4;)$>B8$7KG;9I)0*}>EGy0n`* z)}5(a2js4E#>a*nmYqmL<}wGLaPr8bxbLR!OmkPTYyLDYe)>-`wG5(*xA`{4!iGX zW={JgIXLq#vb&o$Y}goz_r?rwR%Q&VGMc+TY=#Z4O>x*;poc37O{W&=GeWpgnSBCvG3z6U1%MrDxwctYUm1DvF z?YX`H(cFAa3a8CHxt-@^K7s^UxLxu#5TAtd+v0m+R81rZr{HBug>`Y z-In3bThUv;W{8I2)~$aXyREAQvA%t4j0bkN*?n|tj48O_udk2wvxQ0f%4VhYh6Qq* z(YfMd>l_>F^zfcXa#w6cb28Sbhz=GTA9Ab}+&>gNJ-h>TH9Ne0Uva)T67c-&yidW3 zzWIfKYdQ`dJlN=XYR*cR>d{)Jegns*cE*ITqsDDAPS-o!1A!bnL; zR%KKIY-gtR?>-a`b$Dctq?FKv*I-kbF&o!hJI-bN@+7`MsNOU(Gb3|tbEq%_vuns< zEYQsw{BZ!n!^AZN=bm=c1D;td=t7}}(cVi0|N)mbZL%x z(1i;FGB6@BEJFw55i^L*W|iXVV9d~OQ&>zgbau#e!3B*|=fJ_RC!xB7(TIXIO2J@- zI>h7)9SUBN)m(Hr9>YM5@tj)y!5(v95MmBua=1r4!aeA&3fP#it}xYfJ&q@XhF3^D zC~PxQ&!8cuBL&p8xG)zAddKu=7_RJ`n;spVZW4!ePIeStcv^J9?625Se|juPofhZW z48LcX#D|&;yKo}IW=-n4PR*IlUpnutqv(rj@NJBBso zTb0*a%gduj);trR`PR1z`9~hX+n#t|W#zuOE``4f{*G_W&dO z)Mc}9TLk5Q_Q)fDW^pn24$+!W#1n`}#4K{MIc#Ejt`dG^rC|%75dX~n^k$EgZ*AYc z)rGX8obRnU|H9?ZG&DTp!%;FMks)^&=XVVbo^El`c3ssJ-j%jyZ7cE>spd3y7Bsus zGnnt{l9qgYv~ZHEYp~03cUMgpTA>}rx~m%%#PCSvA6k`d4U8+S2AN9BD+`2IuMT?L z3`e*|TW*)S^c%(%Zaq+mY-IKdlC}7Icx2B~pxHA!(h_2dN7D$j{?OOkk5gWueqJ-I!EsC3Y39SeYlbyCcr(kF{_vaU)* zF@QyR`7=cRjM8V#R+#d8Or8cL*b`^LRpt41l40u_OXqSNa>Oh-k&<{aFRRqa*TJZWA|8OZKoMO@_>0a)~= zFm0s_=P6%9STs2Pz(e`MZ;o|j?7`Wpp@PB*se_!$NUP7JBhFU8_QaHaVVZSfa__jN zyqq*Qnaf#A9%AXeA*b}uQ+%K-X~GL-bGbcu4*58wFrT50(gr9~;V5uVJd!NP z^UNAEm^|V@G?RyPTSHcuJXHk>nU|+3uG+fQ%kxZbPeTKZsgsA^gIvE?o=qw*3L4Qi zRq=gcYkBz^@`3_6L=NP(t}Ktq7-&ztXJt9@{7#(a-?N8CIJ<{3P20HD{xxJN^VFNI z{NwkY^r204^0YTJs{(=|+}@ZD*6~Zcp8@b0=oF)44P3iaK>?^XA}i=hn_9 z?*neIb6^Sxzd1-fcwwc256GzgowCiag{ zsU(TmNIRt!5YZG@CMLAs4$qqBaXxqZP;Bz=3_6%7>I>hy`HFCkIjo!izWc7Z_3``e zlpwBL<#R6VY3$oEg4KjM5QLuNW*9N-3?7@IFLDkT&_dGJ=X^SO%q5(QM4q6gWSKmT z)zyvW?cK@7N=Cz#`w8P*_4q&wH_B8XPvgUl;{)ASTPm9SMygx7KN=tC8EmN@8EIy% zrfZ^$@oQh-L2j&QX`DQm=|Y~`?(T0?Hjj6iJQWq3fo!%!={wuOJs)X#oUkE%vKaPXsv0W=lYjEq!w5B40K z_{gx_*Nc_J9nnF8%H|0UjYfUPbO+G-%`Sa@hdh$biEG*E53njjhXJ2 zp2l%RCw*!-iCWR@<>4-&ijY1djn&PckzYZcQu%p!aIj*1kY_Mo@s0IPo{_8ZV9k1$ zJ_F+)5rxuceM`;h@q=7`gFKbY+D}h3RyHZWDkxJSeJW})6`4?e_E$GI{;u>vjaZUC zTm&@e%k#uQZOv&{p2@F97EWA#)pU(FX1L)=`Bjr4CrvixR|UlknaMA%oNGZiD?jUd zSaoRj`DJBwztX|#yRUqqJj>RXXSuvP`E63YrPien^@}UotbSDvjC66?XGJ6VwZ8WB z#KDSujqP`zQe>ANa?$kU)>%a4%id)gxDK0&lo#m&0^i~s(Ci`In?bz5Y)Fh8_ zaB@t2L3Oo$N2M;g^Pz{-ZZ}1vx5x1DklJ=FCU)|z%E!#*^0Uc>@At@~?(Ec(6xq+7 zQk#G04(CQWxQU+Rv4uOQHgnfAdxdE3J2yYn+4)dYCySQs3*L!NX7&fqj`1R=HgCqA z3*iamc2kpf4IvL-t~)ys*U1AI^Sx6OuVMP1*%+=5dHm1T^|0fiM}Ixp`kr2F7|!rp zFAMbwW}oGI0#xw!;_>!9JzV=2_#c3|TQcwvv7>sl9|YQ9^2k2OqxCB<4`*5!D>`{h zid>ImgAgcSN#`+(2~+{&DF9tK*`9)~xlCl1wY`g%hVV-&Y3rOkj>n}>;3s_?GJd^i*yXP>pa z^B56~hLE|C!lXipUxg?56@X0U2g^f_!lU#tZZD73F7H=y;Yc`EFou@DyOkxPbtTJ} zVHp&!{maEep>F;TdF0Gl2&lFv*Gt(WofQu0Lm?P)^0+p~@~+1=rs@Edi#N{W*~BFTdC*Y9~)2Cw?cVY(<|{o`;5pREP+t*8(MRY3sCx z$07yqRG+c>ig?(A;l-7*k#Rf)5)K)HKn2O4%?@GV-^=)WRF)E2E|0|JBX?WKFVfob zMfEF39{6%7NGTvMkdWYAKcci{)j;yg9*oe$#XGeHjD&c0JQfNmFCHa1Klhd&P9tR$ zTx}NpOag8cYb+0tHQEJge2ay3|J!rThA32k&(MO|ttcNkQ&6(%Kz@{{-BQ_dxj)oWN-+srHPC|xFy zl|6;1K<&MT5Ln^YhT4UW67}zvYLbV2rdHk*7vAy|8p&TOp9)9Opvr%<8=o0+}%wnQVG>cD#o2W39_Q@`#BvvHl|OQcLxn;LIKwe2~Z>c^nB7 zcEUprCs@GVv%V)!N@aNir4^gj3bY&~D43UZbno~_(SB}u(z2yxUM7zvITA^J$-=^n z#|0$H>s_!^`;fagzf2q_5BvUH8uEIyXBHoROER>jFz=A!A%?`SO1+6heq~u0Qp-dh zX@FPA7bu~GiM<3G`Yd^RN$8xbQ@xUsc2?y%6oI_8Gfp@#Q6@YN>viCFWl|E=4d!E32`M~iLxEG7? zoH%e?bnTjcg+D!cGQKRo;FEDNE_!_Q$1Y(rQ&Osi4J*?@RH4VP9Uz^H@x^OIa1DDBt9arluDr|9 zqrAiAlb>EjPTnd$PO=<7fLmO=2qW=+ClLpL#hd)TY3XzE#L!p{5hYq&A(itKnLMTZLUIa8 zD9=ZIc{@%9oop5=o^r3L@%1B50 zlS`Ivl7YgY6rxNXKYr0_)a8r9gZwQCeaSAITa3*p`6=S`IgM{1u{1!SV#NXRg?O{6+S<4E(S zyg^`xv6q9{<5xK+?CTK)H_0Q_cMG4)Ry%NUdHNji?V;l#zm8sXc}n@APJC)@#hcdt zs4XUaRNF(_qBiH^<>S`or0|<5o&zKf&AIt~lhBU(FsUPCpNs1|sSJ}mbT-fl>o3%J zLgdj2)pAv;0|#hgE~`9s;#g&rhuUVOEJU4mHe@{8b_Y_FWjUG--?vEPvtz>E{=7zdx zWG0@RpD)f###3)_T3`|+Rd8c5;UF&h2>Vj&21XV_PepV!K%S=i2xRhms_Ue$LXeL(!JQM-JZ;r{P)6#@yEmb9f=Nqh{EDw?z<`+*>VJ27#{xk!@?2ntCIcj z$A#e|yT!vZ{us}jKO83dd*IxRbOfM@gXv0e{c@&lX#dB*{ zJ#4nmz4FTQk3awXDh$u<%k}=(+$+yN&)J*jHBad+JpcUK=(*=}ue_353x2-r`L)82 z7oK1H{Ho_4_qg|!RnLLj;CUr(D=T}v_mx+A*X}Fi)<)4Pd_DjC0)JhJl#_d}~&$SW^WnwrjXCW96m>o{+X0nimIUDqW?r zp6l*j{B!K0=(R(KUVr@uufHhx{`=S7fBp5>e(++n{?PmJ`}sq!|KJC&N3Z?h2l>~o z>8iZfUwr-bL;2UQy?-eG{_8Kk2F5;rD1Ych<9R%~9J4~GDwvPYf*NNaeQciK=fS^nV4*Zov(T-pJ>R12pH8cF`H@~Gd|K#s5{AyJ3upGdaOTXuCssf4LL8qtQ;2a~`^1w^ zo`GLHYu7&M`1d{W#Hz9yh&rvgZ6n53;jZiG1q7=E(ywM(cj5^^QQ4S>k?1e?_w%U$9Ge4o%fi> z4KI&m3i2#ktg}c*-((`pB8t(1q~SmgVu~qVkU!nziD2|sH}MlM-q2fcP-kvYHYu++ z3CB7xJi#hgqu(Wuy}FZ!_mo$qjmYFtR9Ikdjz~C*Jt@Z9J9!pjVxC1FWnpF^9>4rp$&TQD{o5z+*0W$<}{66o@9%)6wftKO(!4?@t zlj8Fk@<z;>2>lf zr0`;b$v2M|lv@njEDe*$mdTcuA&ozy{3uK%x`i`Kx_GRSTENt*1gjwk_OPnJf4=gQ zlHtMmr4U^al03v~|8J=NIwCF!sd^M!yd@qy+*DpKK2V-?`T2bLr50(9SDd2^P<&K` ztemLm7|A}+T|B|>!UN0CjdUK-9_kH5ykmmX<=MHa%?o5%;SARNdV5LaL$H!=wMs30 z${_@iex~F}%W(c4d0b0vWrhrpK!z2($01(X)0#8Y2xZKP_SyXE0q~fr@BN=MecYWy z?&a-uB@kpKD5M<1`CiQ&d{V*X-pf4P@8^8U^6vDJ#4gunUF$-c-~EmfLUCD|=pJee z!j@K)vd`iVvKdbhV_EtH%g^pFY~DvYC>(mHS!JHECVltA58?^2rR7;(o&(2c%fs!S z-0$gR2>GQj4UUg>= zx%$4~Ypg;^s2is;daz!}sT zS=(nudw0e{CO?^h8GBX`EMpvYvfYbIJfy>{4zQ7O=Ut5Yy`eE{l<3(2C%W{!rbPds zbs06@D7p#I|LA;wWUjLWfH#jVfb+9aQ?fwNpR5(Qz#4s+QRp8Rb=m;*3)voucpNAfiTDH*PM?QP&t?EvbK;i;+h|V=yaOjFTw03Z9YjqNEhoqLvDtF!jQ! zg2S$KE^B{CteVR86`So0T@9Kis;jwew?-Nw=!nh-960FR&8wT*o;;bw1rkT zeY>n|J=#Fwscvfi!V1hE#@mUAT;oYP@JUfP-N!gclEY7pnd^etx}Q zrbbDaR=ZqW=aqIY#crrD9sQsG{Cz#4|M|~<|M$QAnZbYjXFY!T_xg42-~XlXFOB!_ z4S)ZizaB+@?S233-+%VYfB%_Sps)YzXE=HK+0O#{$AACjFaQ1T6H{W(dO;Au9MR_( zG&)9W*FOIEmxGs8UpD*49$OWy`tqvBz8tN3;mhcGM9bl-FPFXWSQLH1`SZTNtmPc9 z`tfm_6+dnv!B3`t8UDy~u2PJ)5QN@NP{2*3iu+_vClfMd8e9(2QE#Lj{`iqcYU;V1u{L ziLxJ;hZ(#L26kSXBdk0F1gESMo*MSji-%w;*e|RwF;wVRak+;<&N|CRk$Rbg{Rvpv zYnQX0BCvZ_R*sKtyaj>v@`=^{H^ucv)PWXE)~G^T&?hvO`}K1mNi` z{O|7>0`CXN!{nV)=}@x7^?v?jN1XSiB*4$`%g3|hZ)%;;eed=k=k&c&mPTS>(a%=? z4)FbtWkKyp;F}R&)A)XLk|+510X8n^+u-+)>Vp?wG3^^YANEch)erpon&y5iObeaw zO)2_oKDw~Ge*ff%z3f@OF7s=-cS4c!On&TWkeQICQ2>Xj5u|bNB0)?VbKytQc-o&Ry-bos zE>0Tb+3%$B{P%w-6$3Sv0!J}fPz=RU_U@oO)6_bo6Z9kH-A4&P`Qz+w$T?J{nDe}u;ITv z`s}0TKZ?He#pp}XqhB(YM;`+RdhAO$1;VoiIF7#Zg~y!Xzli^f&dV3R^w^gkO?-Uu z(ML-ng=ppbHLn*sdhr_xe*MMu(Vzdh3w!-HUwrYk7jg6idXdjZ^l;eYX5G_kudR2$ z9KNxf{~JGWUa?J>{v6-VR=?j!`nadIwI-i2w>`UskBCo+Vav16J{+|k-YXnE^=uUF zZ57(KO~3S(TcXYGODm4gK6Uu;Ugz-av)i`V2UvKXdUi|HN;rIt-MyE9wtR&!|K>=m zeKg&&1rM#eeQ@GdutrU%0@AH(3GQ67FW+Xq!Z+>U(7$x+yfF7RjztTzomV)hx-iQ1 z0R5-NMx&dzG)bJha%GMYpand7Gnw0tb=;io918*6OoouDc`=Tip5Y2lsYlcEP7~kV zJEJD<1aFcCWCG!yJkHqSreOGgO1x(7j}~w@JT}Yy-JQ`+jx%-Mnns%pN1IU6bW5XL zePw4#fw)HO4Dg63{Y8ZIAyj_ajk7p4(tVygORv#LKgQ*=oQy?NGS=haAnT5IC&zVb ztbY2=mCnG9Oxi9AEhEf~pS4?$4Ucf)tm(s;drhYzVk5epm5! z-n#Srb7dwDKR^GAfOd?a?%K7E+~ph23-_^UWycOB5wGI(N^|yiM_*{0X@EyUuexJm zB#rz0OVj`NaWVORMYMln{A;@9m&<=goD~Mh#ud0LeZ;rB^>FK6N84K2L_qCoJ*+(j zNA?Qty&ey5qml^@$1&C9NC6K=fO~giGrae3te@R_?k&XE;oRN2H;zA!3-ScU8_W*F z!|*`vJoa}(8LhS%7Pg}UEn@wF*u^Q1sIK&Ferp(miU3+dy^pv0Yh2_GO|>D zhOb*jw^Dv6I4TQzP<{&W$9wluBo0#^S}|O=@`E!5Y$-nq2HTJEqq1>5E)?QI>t6W9 z3tOR8<;_YG#cbQ&BOfcSy{*?jr2No&i+1}q-oGnzSM|c07BSs{`~+yl3}u<-^3rW%zv7IFO^bJCU;P9oRVB4BL`=c+Y9wqFfIh(8l? z)4U1qUcrVWK)p^SJQ{YmUmYDL>e^ZpRKoradW)XH-;l}i+|kZE)@E=y%+uq|R4q8Ke}-?ky=CI@}{qMc8jS zBB#wqqAgEF*ck2Jwr#h-mfhR7Y&+aaN4ceL%P;KKnb&+h1{El=&< z+qzr$sm%^MuE3n~n+{XKw)(i_VOz)-)hDN}j3T&;0$FL5M>RtAi6W}Pi2^h$q7+U! zW4qp2xX8sF>Wu=cg$KU%H7fj6P3NrQ?!#0yRyg{BDpYrTiBHR;FddJ{17}GdMPU`( zfRiVxWmyU?tIsy!Q1k@SLKKQd@&K?RXvrh8C(&rx%2`S2Ly*Vu-1SS6>9rIxNB-qi zKJ7o8M2~s`o^ppz5!kDU(_tQPIBAdwOa49|iLvIJ`iY|NGHBnW?&keN-`Ms3H@Q;= zVguQa4juZ@cio`-n}>|P`}8+)#QxBs?=mG=QS&3icCE~=_l@O8uHVALcfb211r$YF z^&=0&fa`1Dhzu*5Z$8bBJ8w=`tp1mydanD;a5fFZ@wF@$F37c~p!3~^Ig7@zGjFfM zL5Y0{=V0MDnDbj0f+g#)PQ>-dUN<3ms@=FDA%FfIo@_nm2ZKBtZHS@MKKL~$Z7e}J zI_AZRc8&(t*>FU|(p;U+IU=W*LE?igUJWuh-sk0)GZ@@zyNlZKyV@@PD!j0^Jg z45j2j93O9%Lzn^gwB-}bK<)uJ#c$`Z^e%VFgDev2Gvy(D5HCreBpnJ20KIIaA8PVF zk8;Lg%_1-~359`cyuUn*C3%TwoRnLNs`bo$tV)et7*nIwJMdIDDI2>A#u@o)}Q zWya@qV($*Y-YXADV?}70JeFUSl_bA7${F5~c*#7%hiv%l;^L5XA;?3LB(hPoHEcF{ z$lJso-#*N{^9zaiTP9DaUqK#{)}<|pMs;zR5IHQ&uYY&OhaOw85BY+SK^~RoBt4Tf zze}F`rO(~@rK%m`B3lARe*=l=~#9=Pr3dIidU{`9fY~IfCr-rIbgO zFWw%hl~}$!D`^w#^ZH(ST>6k2mL%3+07c{%wp4^1EwuUz>IwxY=9)cHj}zLtOd)T5 zgmBw^aUqw91CM$$`WNLWfBYxRl00?wl7v6#9(^e$ocdPIQ`38)-%sao)yRPD%x^wd z$a?H=S>ug$HdehIk!fCR=Uh3NE58N3V4nV1^JR|32EQs7N{svIE3h;Q^Y^@k-#b)5 z1{4)2ObRmr^G{)NZCaKywz9X>RD8l_B4!t_cnotI7dbdd?Ct4QgyHwJTwj4iG_v#N zLm2d)q>su7T~*Hfl5f0qHo+(ia550AOB2pVq9Af8}^rUEcdBAEx#Y0k> zP|Ma6malJc+M0OzfnRB>L=hfBENomlVBJHIK^{Ujtg#aRIj_wtAqs^?^3cB_DDNfv zyw2itc4A2K1p2J>32EilTU?^zml&K2V>X6Aionj-(`b`@oZ7BOLZ18|0^_J$MF?a_ z$ii_Zy-PyN(q}{~Vq5_SjZ92~XKb+$>v5^ebM|n|bHqyP7vhY$A;4i+COHtsVg(C| z#dv&@)k82(5lkZ!<1_Kh%=A1=@L(m!d10roZ+dECgtf6ieI}1$4f1#_d4PB)%!#Su zq!jqgE3RTZO&r85oqp5B@#%P`hlanUi1OA;g|e!nvKPuESVeV6e_8Ha%rbSz^9N=nk%CTR zm*UCi>)V1?(~%Mk7G@~W%k%>*m&d9*p5Rvne~>&V4YB%#0#c2~tp1`GA*Mpn*x;9D z2(iV}mVTGz`2O-p>q>!Kd~qr z;!5jFx$8Wv|3uHXdk*sI_$n5ByXVX)HAH87IZs+V!O8Pj=bAa7dm=u5fDHl({?xE| zE^-vr^LW2+y3iFUVJ4J5f6AdF_I*85?$3X%8%1Ll?J#Vcu3#MKFqA^9?9EhJR&L-d-q=vs=-Vj6VFTDk*y1TD5`*9^oJv zWoN}@=Sk)77zYqdT5^WloFa|>`^?DCzqtNC^v*He6-tb z%gc-l#pS8Wh3GTNbFX~6{)qY|Y4}h0bb|cl>6_3k(?h?2B!&@(o}apwp;R*%Qm=(> z8C1-usH2;xE%>#*Oks)$lNa^0Odhq*GzhMpp}(M|v37>`xfn0b$3?Z16P(Xg`!+-S zhBYn6I4!@h`VHAE!)D`oCTPDCzY`P1c;1Dn2t!=y_HcQAS^6l2e196=MZ*O~Fsi?? zGKGpA!^0q1qeaFR_1Si`fN9+m<6ANfS#ROP`QD_s=g_Sz}R_YrdxR z9J2m`T5Fiv&UjVhhatui62oK0dy+@?B5JVX$*L{$SUHqnUk2RxM?&3`U%usb{kt<* z|E_H0|H$}EaeAt_NczrKJ7a_S>gF!U!J=y&uNs$)tMm$Lj)cNjwr(GxJX8H(FfhRLu3c|%c>C2FxcZ zjep2PDq$PG>^qc3oMhSEW1)~?%hKnb{n%PK7P+mQ4zpFABU5gxCubMfW*gfPDmLnJ z;Ef|zV&kw3zU)jK+qV}vpoXIYVplfSVMno@|LpqR#IZYoZ=ioNsHkElA0C;lZp?#o0>&Nk145}}x@BBf_(&uh@lv!5xdXa+A z^KJ4wlt)h$b07N-sA3B#eDRr6u225TyVME3=7cT`FW;u+O$e{h$+92+k*u@+$ z{=&Pch}uT&bot>!@?ky@+IQa84?jH8%0>)~ds{!;TWB4=e&pjLm=5zHnZFO^)+$^$ za)b}XuoXT$JbeB7Fd-bi&iVL{G2s31k+^lZFnm2$$a@Qi!NbCP`TekP{bTX$J#vIt zh`V)f`uj3ns`PdH-ASlunBWj^AGUo{G$CqdFibL9EzZ;YjDM|fa$&M(F@`u+$Ps??V3s5$=5Kksb(h|ifV9E*G`XP!^ zX$$%yC62=e#t%0MqC(& zSO=fM=ObTA`rUv_v>sY^?O409$# z+MXQ5-ktS;TNL^T-#W;*coOn)Axoee$}j76eSVG4km6t!Y;s5j$}>GYgDmE#$}fg# z8dOb^Uo#WB{*`)w{WxVFGMqy3pE-4~#0s5W7QgyM~7CUjo_v)$sf7BZp{%J?FQ!29m!#`z-64od~R zFN+~GKSj->M`)lX=VvtT-QP$ZCxxgQ@e9fTnvil3X zJSf!}CzvV8qwHdUMVKQrKQohyRGNwXs&{G|wQisl8LrwZPA`s+u&6PQ^i$)!%#KMh z$Kx}+3zr{oKO;;gMBn5%m5kS2CeK~%4@KS=EvnEgMc0b0#xsyBpNkybV+3TqBo64l z@g>v_zj^OeMw%cq(A}2$To;aK!rDsoJ>{8#Mbgp!Op^utS^Gl^Tcp3BZJ|7?C9=MN zbtIdEFbknf(p6~bW5&uYEirAA+F|;OMG|6$GVh8xJmM#p>02208qc`)hEW@qm1oPl zbpNGZr4QRaS~(*OrTZq>Kjv)3MZAI7KbDaCuRz*A=864diGwm}zq5DwmFyqGA=Mt9 zcgL30T%GsY4b))GhCzt6hoP-VC3CQH&;F9p+Cy*j?V(KlMBupuWx8?0qbQ~Oebnin zAB6#^9WJ&NB|vnxqiZM-w-_g+9gl%#QR^OP)b1#8rY7zU@%E>P0Cn&pFU6@u2Y&RF z?Y)qY(e4jFJj@74TPe2vk0TlswaReB?}TG#>+Zvc&6=NWHfnMv#yJV?X3tBYZR`gL z^c0(A9JW0nTNDzzV=Q9!%Ix+?`fb*f);FYy#@08sdtEdbf?681(X2${jVG_5#!Sm_ z%J4`OxYw-tPf>Eox)wD&*InxyIDGv8M>5>uu>%)5w{haccd$KRivCa&gTd)7JANER zFb7WXaP*xw17bZVjZ-{-9VPrn|2+D(H<-ejZ=+4-_=%&O01=^2MzM;j4{~W`wZVgS zgQc#cj5=nxI9qp6V$dDhj;aq{2ymbyLHJMOltWWg;;)XHf}7GJE%n|54`K_xEn=CR2y9Fljm;*l&zc^Fe1TOvB|V-R}L-aC$ztnya#t_RVSg zl99W>l7=kRyg9vI34g-!huO2%n^1Z^`~-?ZJsmhU`XR zgBNs%uhGE)-vpW|X#z1_Fq=QwPshN!A?%LODp{lDnn2fn`6ke}X2~PX|Hr~f-~hFN z)~Z?i78*O>6uK6U_Ur!b-XF`J_BhbsvUhwy`Yhu~z04nCp9*Ff)SJ7v=i=oOR+{)k zk-dl9BK1eaAx-kh?aPB)7?qYz8(9Onj@3-;=nl4j(DUARCJ$rV__z*_XIV zXc>P6hdmwT^IT}m+nFgpm?VnC59Nn(2}6d!|A*l2?vOr&>8}T;^!Rh9{m0xOgkP3u zg27g6oWY>m6z-u6=SyRNV<~*Td-ozIE%oVWWd`soHL~IBZ(IdXpH8Rz|D8x-LKzUpj;42;ShJ44VSPP=e91l5G8{ z^tr`|$ES}|SfRJ+54tPPyX7u7Dmst9K*vfB^6gzx3GE;*A$Uoel7Ww@vN78D)pcb7 z?%TA^8#V&H!Qdt{pz_nD18gfplE}--uUhh~TW9kc860Gi^VI}m*p$SDAw)~;`~4(Z zf|QQqumtT_L$GEFKQ3ozWSRwsK8I~)&&(V;H*JGjIqaC$9uO8OI90|*5Jw}W={svR zsWECQast=NhNHgy92;_wfPC<_xDYO|w1^Q$OimytkCUxWa)!VWW5ikWx?z<^7O7L> z(GGVCF7PGK)vFR%_T-aE!lB*rN$;?79b{9@BDjiC+REOcZH4T9t|`TD>+{*XZ0(jhO(o93#@?hpP}Z2azrelyJ~WK+?w1 z(ru8d+u@TX)T0o5F9c|5$vAruN1M%|r*@Dd2KZN8HoJnawzkDjv~=~NodQqVy4dDZ zzLip6;oIsKtb}!*8L@)B!>-}>_SWRyi_PaUzcm(SXb{t#M}Ap(luc#m|B9c1h z?!tUa_f?X4kbZ?uk0h@l#C%svOMdWb7e_7z2V1(io^p`6XR+m>!F)}3-11Q5rkW4g zi7-F^bj88NbPsluV`ojpd&9Gx=A#95l=aqMMBRLLV&!*o;-^fgrwmU10=^o302(() zBLMVYs-lm6vBL*L*-Oyp!zp?2sUju)M*J3I)EKZQEQ$)nU;HYLYT|SMRvhdu{$eVo zSDpMtu^ZPxj-<43H%S!bGYE@}L1%%Tnn}sxVLCc++UTm$Jzgj|6^LW&7aDYc?S!62 zVqmQ7%nVE#vI)zB4Nqj&86gfFSs)6#`=N@5LL8qbta-;RM)? zDjfDjGLGLy4@7XdN?CH)mL?4Q$hpundGY@xdECpq@r!@^#ZP@H_%~YW@qhcbpT4o< zji1`$!VSK<{M-0ho5-UZ?fm)kr~cm`@BQ)5|CP!9*x1-#h`zFI?~i}{<87-~uUxr$ zHAi5c-LUHa_|E^|+}Fm$b){)mA*vdRZ#(Xp)&3zX<24mr_=~nO`v+@r1YT1%5Zjy1 zpUMcgzyj73HgtD>Ohv*YI|2*JHuN~FnHveTW@LLYi?L&*&P6IDN&<^Um=Kq?sVE>B z2`mQ@LX4Bz=XuY)1!U}0F*DNkYjf+l=bpOv)Vb&5{W|aY&2QduD)IA!!*3ow{I`Gm z&O5u_F=9Do9|mQcRr%A;+|#E|@6T1Kr$7AU!w=to|Fp}s|8yViHecZU!w)~1fVtv3 zo=>eT&8X_ZZUAd*As&sYo4`d7QrA|R=9vISfVzir=0bSRKC;v3Q8pY3_PZB32AkUxvWa3@ad>iSzJn^DWnN8V*%On9aW57s6|e+wb}!0A%#pjyz&0^6tUDsV187UbV7X=64fY?-x_kwf`=#e#i2-epKb@`=*mCZga&iBRkoNKn{ zDWg4GqwU$|bgK4z^@`Q`L3 zJa}IoA7{+~53^w%pMk<$b8yN(<_tdNWdJb-g7$(6Glr7wLx-rGC= z+*F)G9FnEPMO7`gMn`WIZGQ5r&!m2uRe4Y+LV>_+KxkxvA5vFj`omyKnk$P6D{p#6 z`Fky(;u`FK49d>Vw(Kk}E)vWG`dYSpY^{IgV$F)niExZx+ng1khR`P!+)|;UqVvEY zdUjKOzN?~w2t<4U+&rlv-*x;zg~FW~u6%q2R{BV!BHsxN!g7p^d^A7Y+2(XPoQ8Sp z)zuPB&Gj}ldEHn~|8=gr^Aqtk>x7)p)YSP2&IC1u_|yZj_ zcbz%&&Sm)(){o&DwR8ou5@>iH_a072*tILcdgo5hKVSVgVOK)JQR~@+1Z%=O2~K3O z;+&s^z*n#0Al0PO60Ey+;gmJMh4ClXjd$$ImG*qP?hQB>2YhHn^UbJ{^_(c6__+ z=|Z}UTD)^%rHtLEsn{eNVWg)eBl2eYe>4apJS6Tzhwusdt8G1KNOKcCms?wV0<&{- zVN9pTNc1=(D>P8>XVaPQu|$BrRB)82Q16y@b5ai&Ier#$iyvB_$4*G~4f zfd8>t?RMvJiFuKmz(MzT9U14`1a;Cb7E;#Fp|XkA?Slun6S)_$-Y3tGF!by)C`HWciS6o2+Sx;?PB2SRRCTLYwd~mCNlZ>lOG`==ehdLu)Ap3&Tv7Gh+%OSy3}Ym?jL#(e z0nXw=GI2NGRa&y(w7~3aZZa4hq^G6jCL@R9dJ+>830_}6m{)q+s#sVbrC69C`6MGc%*kW={PQ_uuiWQ;m(M@VP@hjgQ<{T3WhCp1r4w6{82bK)Ub-VC+GP zKlJ!~gKHu$sp+VSCEm4Rl!&&=8{;KNb zdoM8Dhvapz^P}Gi-jKfMskm{EFntdPM!c%mVUeV^z^}6XOx>kwLbV@ky2d!~LLH^G z;2ub!$n7&FSevZQdb$EZ1HTyDQvwZ=(2KRuec7Euohr!pRZ`oIrx;qyXidBtDEWf@ ztI$VzdE$yxwH~C971Vu326{C0EnTZU zMz&iKkkOu5LGiWcn*Ql&B`??XV&6Gz1t+wse(|cjC8z@YaK!wP?i3tP3ah7tCBoI- zN>5=WG)WNzhxHLb7Wid|3iILFM%9Hy?Df3w|Ms*yuBN1~P zF58t*XthQfWICgE!&-+yc`N)_QYwa589S3wG1TqY@!S8tV+Z;&M!oa>wQc7)$YvEh zc9kn)~v>Ug{w-&$rd~;|ruRBNsR20-+hC?I*xxwu#==$M?YdO%fOJ4dML(?z}h2nS8m| zVo7FJDD2X3ANd|m(~=Xxk0mB1gKTll7ghaG1PZ@Va}$k2+TrTz^QY>O@R0rXslwm? z2nSw;UvT9u++LCA2Y{7@S>o>zgK>6Y1=Ae94(C@Sf^K;@9(JK2%F>3PX*uc=vi2q4 zHs{mXJ{J}tD|$NNS_)%U3ePT1^m!dq^a@|Rg9sH)ye@t?`<51`94n9d{8uK%@SQ%# zA|wpR{({waMZQR^j9Mb9_;ki*4FvuVjbU?N%S-C?DW=^ zmU18yYGa40+HUw>(&Vxw~8S_rm6t#o=HuI85rAP@luBXafTVx~75wrjfLX z+m~A}W3WbY^P~ELlLaTs%F0U1_AXs7C_8zwpn%%o+q=~M5Exqf}n1^yH`G9;qW{ai6A)BW67Y2Ilu!`e^^r67YaqS?mu6q#5`yM4SisD)T#s=Q#C;U#HWP z4THqjxy{=THPY<4eS5{Iw*9l02Y?Q=2f~*!PIVBC=;8K^jP2VG-5t^O5%2btjO~7+ zyKs(6+1?)3N7}_rE~PabPzdSzXw*qAr5U;ocosWSQr2zlKdmimZm!+t^KewR*-LBf z_MsuP7@G|%Cqtnjz0U3S-j}&`Xh=RD{_f<-3%dSrX6E4qsYzX@IyUuu|KxPPuAew@ z;#`}IUAj(J#bwT-#U3Am>h>1@^x3aECqI@ZwOVsa=8GLWzJ$0D5T3l?`|kmD;*(g_ z^TSh}_~Z`|NFX$W2P6ERP|srC)e%B13)h!t33dG(=J%NTLmwG!DVzYWJF5ruV0 zi9|Ra0>g-?S~jq7Uswmlbga){t*sGb;KXVuNYW-|lHl+>TD^&hfQ`p%(8Fx1CTvpiD-oi$PvjlQ7oY&t z-|QcNX?PAX<%=}7PGUBHZDGN{X~+{`M_Q)HuHg$N1{6$AhVs|=WPJQ8=JyekU!7eb z=O6?o^?Bf_`HPVR^%IG@Xw-@jumU(5GAR*Ch;-&+nYOB*uj(cLL;F`%FZu9S5SZrm z)b`rk+|t^1a811>)XA8XbLJ!8M`w;;=F0KtVU|Ql$rtSKzWC$|a=Q1W{diz^Q|)99 zKaS5~I|2^82E%5j@=(74&6MP)7{3uyABFxk70}}=PvOmx(Jo(QDdoYy^M!?{x{8}a zJfa6#q)1?vzZKGNWbKjq+3L4HVoD(JEI76Vb{{l6EFW^1o0AWb2R+Rg?BQP#2U*xN zl~&g3Z0PK4a64fhw(`z_ zf%^!o=yG}eSQU%^Tpzf!=x=a)%l-boiM~DznVgX&KQxXg57dilWQ<)uh75=DSgei) zxd#s@+f}EW$(`LO4S-<$a?!|Jt)-BH``cJxx6#xZ6att9p(wJjUA4}c4e#P0?w6Svcr+v ztooal>^Nc$gIe;%u-OZ>B9HJtaqC-5S&F@2Gr<69kWa@ThpCaXqC8Ys7$k`qLmnL< zGl*%7IuHfbkgoW{np@-G55XzMCZ&(UCL~|ydc}Xk-_YRqHh6{K2>SgUWw6tT|AyC_ zSLUs|;`P=w_+hybYPiaezCLdqa}l?;0!!*ur1-sVu;!MM95;MV;%Yx7-Uiq!bHQon z;*|_G!B<8EO}?8?l*kDqDVhr|fq;V;mp(ZK+Q&SfzX#1G^dZo_2qI4%`A11Z>KmE$ zNt6d6i=?K;B@ce>)4D?!3sI4Uo==D1Kc-ZpnntXYws=Xv9HTYe$2kIvgddGzjtDJ{ zJ&TA3(AsSc7bC;SscAmRAJj;|n%qajcPSf^nf7tge+?zl+E84AvL|BmleDy~a~(LQ zr2?g;U1|kNN;=op*4EP9RRh_frlu8Er|ye4TUuIbI~q@&s_klS#iDI5g}Bs9mnnWF zrKaKIoEJz*U5PtO2;zEQoWE@TR+PNZCt4af*^!uR4JjWCClm+%(AsbyFg(V06rpE3 z=ur^-&RWQi@j4fEqU&oR8376PwHdhuXZ6BbFAchJl?U~M-=Xxqs25a=JSsxCyHX7^ zsHD^`!;y^@prwt8J`*^#vO2^!7$HtF^0SVTQq_GZpIQ>>IUk?Cx6sG8%r^@^jCImR z&~G6>K&3gtrMI_u0HHH4U%HJ03FqU+g5Blu5okb17buF1Xl!X9+&RjRq0QhKv1y~e z*HoP1lh1y++CRxprMzu#7v0&ldY7x-?*)I@U&^sDy|&gxLum>4{EHVa=jP-bIirRr zb)-Il>>)VUxXJ?~E?o7*o-6*&klAI$+4c;itF>p2L^Up=J(we;@kxJ@or0s@xA3~% zL|dINHoh;&7V8An)UdExdY81K7ca2R-*E4HVa#fDw;hlvYrrU>_-k!0HQJ9svESCl zyztw~Hopl^D7|o}`sqm5^_9rf6rT>h3vN(L(u5_Eum4&G*P*!u_}3hhvG*$)-QhP;gRBNd0B;g?3GCrZ* zQrNhJK^|=sqjtRfGpulKn>T9DEw>LwyQ|w~U_WIbm$&o&eLoc$cp|3-tJQV&zRTvu zMaVYzmfO1FyC!CTx4;KJ-tk%SKYPe;lwYC0pZ`NrlhU^|HTnHbr?2=g!+-U3)97f^ zX@5DGj?Sj0zP_f@;>U}18PCRmg-)Ly@Sm<|5|#yy!=Q5BIoDNQUhYbc{kFdTdXxUg z^go0#$sIgEgVy% zI)P%7@*h+D7+l6a!Jqt67y_DLGazn&Q<&*WM*Im_vrllqJ z8jp&un3(M+dkgL7FHOJkH56W1X&9crPE__mDl<6{iSifMaP{Pa>FEc5xBv^u`L+$h z11)hTP2TGOGv9s>%A|X>E)L8Xr(LeM94>w+a?&eI25UNTy@skgoL0x>O3X4vx9=={ z=XC@Z9rm*;e!F{O?ek#J-LukQ>zjBqwlo}ESqt?&5_!iM$RG8EAcYMt1;-xs*&9}R z+`-`IYZFIp{*`K*Js7mttvu_wU4-^rdC_Lg^;f>82%C}%HLXiC__5*J!h=0sm>to& zvi3a?KB#|>)>W33cH#N*bQx5HS{sg|BV->nEiJ8VdinV|!Tb7AS74d;A$??aWCW}k zmH{e$%;WLJ>mLqzc_!556Ma-9!YD$}Y72w025mS(cru(Z14D%o!V@tcH}YDr<{-pp z7y;D~qs{y-(&PrlcZL7)bj3X$?#4`I+LvEGI4F}BCot5_HGYzSUp~moBTVJA_3~*m zVXAPE%abR_T9^&#JTUVMi#dHFbrSZ1s+L|bnv=zwUd(Gw#DBx*DKY&wA`2=8G=JsV z!U8`cE2x3Rg#~b9D?vRRURYROURVH|F~9QNcS{Qk^Kh*|ST4}Qg4B*+gw!Uf`tiYl zM--bj@*A7@Lx?h>yv4NroIf5uh-?y44?Bxgb@X4m)?ZUY+zWw?jtP16PoO*^GKMLC z#quB9P)tMLVzeLB$=HPaE*>VDo2Sf^F-=pl7ZS!iK84}G8uWQ?BWcRyoxtNNor94e z@|XJ2aq;sg4;Ih0n(u4PU`6qWCEQWH1}IK>cPZM^v+vfvTVez$ygOaQFeOQorR%Kv1Z}8@*T9YMOWnda(!qCDaNrKCa&=ek+0-)H0@^mTxge3S6!d`(+!$BD(G3^)|v1!vV?HjaX z{4D1C!uph6#e>E!kJVO6?tol@)n0nfVQ+7@+uKT@4$QR)w^yGF(Hjz2u_KzG94K)EA~$)(bx2VpPR`_=j)8 zGf$p`;6aXc5EZ8*SYJ?a-~h2Ke)uUS*G&5<-C|Hd|+>fx$l4d096|$1w+WgLMTtyh@fDSniyio&DyU*?2~5QvF@o z6-}~dQl~Vx59AC@JFHi1(z?#YXUs_%L@^@exfy2HklD4*JrfvWvoeidd$LGR5K= z11us3?W8)wNHUY;L*z$bWj_TUK&Wrke)^ZT{zB=;lF{~U)Q`b^Md`;fwnJf}^keCR z=w~yL8AxXsl{V5Kl5hb@gDPtVmJ+SUaY}(B3$-k0+|caV)Ims?NEbpdS_DTD?=Fy%}XzkJFC z19lm;xZWX3n7=@@I^xEJ4!@f);mAjye%fF@`b4s^Zw5}V0J(l(sPFWrj1 zr4V}2ZfVbjKEs8L{%nEa;Mf=xhMH+Nb5F%V>!*T4Sai7l#U6l_)Y|(bLQ-GW_NDI1u{H?c+H!xW5eYb;m z$d}3R=s+tZsdhh}vUPc9cy7I`uq6)*8?X5D;6#wtFx7V+O|9bzaZpg{!(GT?|Zw)(|WR z9Rs0weV=+z8Khwlr5DzzEv1lR>_`xi}$i9ws;!Kr}{zWS{`R91`QJ&j~06x$T`Muh= zG!Ny|x9CI&*$i2HZsnVABG1GP2q}w8bGRzBVhHXynV(z1{v}LZn|p@iQUI?K!TFhj ztMe1SYBe5)LYKiq#HN-u{2J+%#l3K7dzW>Tb)NEP%jzGnpy9!)EZ;6#esF$u(hyOx z7k7(lzmP)D_b(Umqj`t$k6|o`WCsl zd3dA`e`nzD&_TG)jI=~-_AugTrr~uRk;-c5$F?w^8r389V`6?LmQ+{QUarg~qS?Qz zD~N!X!7e;rhr@$UM+XiB5dw1<3-t6rPZ@{js!R3t^<~hLQ88wa)DIoR&1 zco-t8{m7@Fk3Km3&XEs%yg7JAe(0pWfxbKZ#Q7X1^e0UJ=z}A>-Z}g69hfx^lfN|> zT`bVu8vo4s!dQRd3(Vpn@Rg0y2qt+{9}fYDsUR&l*7s=Y`yUq3u5Uy4(bUjzwX+Y4 zLS$`-cmTl@2)=f1_z-pauewFEWU<+DZSmR;cfZ&#V7bV5&}IRC z)rmj~amhPyvdPMl@yBA}*aJFWgZ3=wLR(ddWhedWPqr0Xat3yf!him}=*Fr>b#2G_ zqJbPs@hGZQJC|)Ksk!x(m8s$Dm*8qo0){?{4amotEH;S|SL)Jgb9t{^sdKw9jk(-l zkg-YP+5xr6;XsCeJ&WpcbFbQ+3hZck+ah~Gf*OD zatnm#Qu=wsn~PUJPyg^V;oT75MqVCYU>0K9B*Gg~##pXL!$VZO9feg1fK7>YO1vu2 z>>;{o7ERujysttJ^@n6Q;(K4OwC6(SWY}{PN}-EW{&hAxb#%&~-)6gg8ww}trl6|x zdZ~OOSxXQhZ{41o3pp9>XDj-;Xw{O_f6p)l2A%pPz%NhnY?~Y}tny=9 zBhr6$Vf6w&wn?5}ojUa^;FCzem0$hUwr$%k5GvZnNC>v%wDfK1X>s*0jz4OAF7$D@ zV}ry|Ka&HhKI8HEJa6)syCXC7114F)!FN&{#}nra`~ZM+K0wYhXWj&P@bxGOf4GJI zCHg31zJLl!^$?T^W{S17sWGn7rFtV0`I}#>MuX#x9Xkfilh6O=?azr;XnNo4j;bH!-t)nJf7y^?@HZ&hh)JY7L_1O znZixIy-fyw|KaL#$NTU}VE!jxu71gM`X?ki-Q}k%_T$aPCZkcZ)ma^mQt=PLSctp2u@fooRQ(aGw(*Im^lslmV6Pj>#sJQA`w+|M38 znjk&un^4z@A3cj^d8D#Ro-t%mx$sF>)a*jfMLZ;~_Op@S;43i|W7G-!59cl>9c6os zJVEq0HE>5FCB~o)kt~#3#H%4Hdb6_joos9@NQH`65r)$wR*90AV^ zx}~OeOzz_E2v-BV3D7t!?x4IA*v>=6*1%aZf@`GhDK6fMNZ%^Rr z#AV6ZjA}qdG* z#NZl1Us;q1V0mY`jG=DAf&sac+Ug_!LTb}1`g)oFEtSn-J$%}x9OKUFO z92vP(OsrViRPjz1Hxdkv8`6_RKTmNvPJQNv^;Sg?3fNR2qLz%>8zSQOZNIee!qExL z#BU>mSZAhCq`}6Fe|ixaY!Fw(yHn7Tk%_fAVS6#iR-)una0cXDV^dW>-ua~})KASN z{psq0$fwKC*)r%nuP-m4g>v6AEagMH7%`MzygdGBglkwdd_Re{v7RX1lcwH zIhr`++^5S=wM$&TTy@E(-RzI6{Ul}XDCn2?5{16E-~JD8)Bl0(u>kf0vyVU?Josw- z2GgZ~!BP6BSo#;o!>#l$wcbjLaA(X=#mc(!d4A1WQXRKgBO7EC~qtm8k3m=w3jv zN$k0~QG4!o=ytpr=~(QrJ;UqWU+$NfDH$35{hduNFX|4Lyy-JDQC!~HneK(knnM48 z*WFQ$is9E?SZl>PTDRxM7ca%oZ=lsBr3Okxs{yNjR%SSSiJ!vhp&c~Sg_I|p`*#}t z2527H<`lmHTJ%CQ6|sWQ%gwXcwS!Txdw5vcPd&b#>eA8@1_9K!%d&akcRTyLJjNlC}fiRQ4X3)EaxR9sZqyk&oYSH(Bp;BSKp zH{^G#W7~d5)E|4>Hisc9S#yr%Mdf!}WfcT^3Pup!)>bFZgETTd!B>`xHf2^)vL<(2&yk>iWh1N{3nxVAJtPb8D^9Vw3q!w^S#T=m{Yi057yxqj0upFcOVZ8MtZ9kh@ zKGh4zcq;_%S<^hYWbyIV81sB!r;X>Rhjm@L)ZC@o5wggdm?BW=%2N&rb zJtp7cVPb-*CXL;$MtQ1RVOXG!GB$0PFOr9=xx!M>&{v<9?%%(S=Xth9}xO@j_u5U+Xs?CMVbB|79*iLmr z0XudIts)_pfq& zV0Qo!wt!_wm>ubvp6p)*r!gD21k+t{&52C-(WW9UnUsqql3pIOJYausDt5nl6h0Op z1c!Ty|4(t?@oCp6Vvv0M%>on0*4VHYzF};H8N!u7fI2*ko-;F%Z^S1&bOEsu-zcC} z`n}9dS<%LzXabE>EPLY%Q-bVkUtMBqY8fnlXmwnln|X@QJBeWhD(F*@8xMi`dx1|i z3Qi?1+oy15YGY*IzQ_g6a;d3}p?&*87ck2KpJY+XIO9qG@`uXe}R z^5+>I;l&1h%b-kp_Ys;Y#gUQ$!%n(!A3C#b;(yRaV-xvRs1rD!db$H-6i5&(yMw`Q z(GF-`N={!}nV3?utSStS@MlxSLF_+v3oNN~!-V31b;&8+7W2G}{P+|UyF8x1fOv67 z&g4W3dS-6;B7TC36W=jyg=!|tK2LCL{T4%Y-RqlO+xP*%nGQJp*u1ri89MFd^twSlf`UZOqU4o&JaM@~eeDVMOsQ=rcFa zBig@~7RQ3YXEGfAxcE(U7@Qg#`_?>}sjHI#dgU2v?9Lsre{HzUI{zG}{_txQN4|ve zSUjp?a6gS~a~S#_Xo7%u?(~EgR$o4sbPMt=ERO(}U?UTp=){T&)pvL9{Xr9ER(14i-iF=Sek*(MQVt z5Bkv1I+nK{R_9xl-xKfFA|S1@cMp6%P`-WtHvHSZy?v^E+xFhlW2H6ww+*aC4sC1e zU!CkP+mC`CN;}uz-(OR@Jv6nnf7@j5v6|j}83;anbi1n;) zxGiI~ZTG*zA0S%`>zcCfXc=!^oLBB4;aTuk2WBF05`~X?N`6yHN+$+4c=e|=L^4u- z@d3u@u%42Vky0^;)tB>2Ybh!JnOk#^)>3}M%i&qvOwU36z?`DtA%(G958Ij|A}!lI z+Z^u#Enx+t_!383qvreYIz2Rj9KfMoas zxSBph@B#c8bYpe(9|#ZNkK$(IAp=AB{0w+M(mz8)q94-udKZ2Gg)SVbZjX=u`i z_H(_JEg3tUxmh|5j-U>N2OTje~`0AH>Y%pnZ@p3DqrobMQvMHgcn{!D7E4uZS!Lwng*vEp5eqQPkYi-PKI1 zbYU}E3>L{S0(2k{?CBZ%Q;)Qyu99T;)YP3EC=_#S$u`&8%6&EZCA<9-Q+>%iafh&m zd1?g=9l%CX`po#_fxLeH3Wa9WjYDw$1{dIh2Lez)M?h=^Or8l@^Y z)&6tGj-5liK}a7pNwQIi;uARj2m^o#KA!fI$Y5dM9h80p>M#y$An3&!PnDH%Pdlz> z@3?W}MhDcY#9451Mnpoyi7`T zsmp>}c4B;16%=22k{x><-=#ec`Z|Z>9%3zHRGbZWt#osevaLVB%#2^Vd z!hZc*fFR~Jgb;r`s~pV+%aUpr2W~W;M3_g^Q1xypkCZK*_f@EU`l%-Kd!cVn_gBz& z4-KJT>zSFC=Z6L90W5&I!Kr=;Y#3fcquGCeqx%oau7G5;!8ya3as#0}2E|hzysv$e zxw8HOy9K0|zbuC(ODJRisu;i09s4g_?_a&X-vz5yeN-yOSW~}0y=)bmI`y~J@4;90 ztnMNA4f|Jmdg*GZTF1ejQk-bxegSd4FHiT_u<|GIXmeO+MiT}Ul(X~SF+PC60D}L| z8B@3Z40D()NHhHa&B}Vs=T^s`YS-E7qvrmDqIB)sem*Yu;gv z0MnAXV+=V_T|3>{n*BK{`&c1W!_lEg!;L>xDs@iW4=IT z)M18G+>Ybu<)eaU+vZP6EFXqw6~yOFUASlbKidZ?E?N46dZh`;O+O` zdyhJ9Xt~u(ocZI!hfpeSBW?S`z_K9K@;Da9rB>D4C|G zo-j$K?9ko22A&yg@9?+d1Yx93pDwNUmo|OUv>!pEPB*sKmxFBu2H$&{SHaWrsAxaE zWWg3g7JKdXxu}(_tb6^`*Li%@Z~p*7-_{NMeH4HBf7jDbzWb6o8Obv}ZD5ImBfJy+ zA!*&=cR8Pe|LKo+e&4vip1F@6LLnSrJOt1I#6!TIdWa`6*oiZR5h$U7(ejv%O(H9x z1Sggxg%6Mj^PTd(;*Y1dGY_Pqnk1E7XzXY_S+*}PZ(mvHJFMpZE`*pBp{Z^SgkYY- z!y5P)(DE{mJ{VSq;qyVPO@$sl#Li1AOA}KAyaR4gcHu%dm(!Vahy<>;;C>(}v{^1YT;AjK4p7TRrEr?UA@W(?VtE)9N zFI!s3D?_ylXV>v@;2L<{(BKW9oMz)Dv^VX>ohfrFOIYk8u_vM{LP?JGjLHJS6g$|{ z<6w+9c{ruN z`UGEO1#3}e*(<_2B0EF5t0>af7cl}^=`RNQew;b;fe+2+@ROAn#%#y^lDyE~ldxZs zn_kQUt?n((U*K2M%=IAbzXqkIWnq69T|1eF>F>@~Ww z^6$4EHixz$XAWMh&5i)c?TC`s8`DB!rMn=u?+(7Uu4( z4Ncu_MjdHdq2>M;-Eb5b8SU*IZ5bcI_5+s??c9lNXKU+g-OgR;@9>XeeZ}>@HtC~` zc!LPjZmv(UyN|B>x0Jd~{}x+`+f|}W(^gw+MMbr#k2-R{GbgH#VjMz~-%u!ad)`zY zLqEnJW5z!OH2rOC-;SI7k2Pm`oX0ZKP@fqSRMviN}3={7jd;`szQwMN1I<-QK2Jd=N84*&yfzGj%$l@O6uzB zN^;(O6F(NMl$3K;C0Q*wB{Py0R(Ak$|Fc-|jBNx0)Y4I(iLO}~`)yGQWLD}AH`!CP z0B)!DZU~I2N4@3hr|$O{OdyRQ(XdRX^C@0nJZ(CG4b%54Gip z{S+q&C6jpZDz)t;F}f5sWW}okX8$5w#X2>tR>Ru^Vdqtwy|%5bcM>yOjnUr|Wh?D? z>Zgca_~Os+@$DR4py&k+BKJb=eNJf^q+4n&ZOaDU8L||?&O?z|$D;0KsvJ41Sav=~ zG&LgFbVkBh>nK>?YP_$c+S~Q}_Q?F6_V)F$_P_b{duq8t{aAg$soxXtE2!_`Zeye@ z!2*d}>lMV}{ra)?9X!E=v!i{nm6(2QX**?phwD{*{%jlD^SaoCABU4UwT-agrDtp0 z^oSUdQl4>ZFG*))JrjrLpFty!f9tem`KxwdA~I#PXKaSDLT4}#ZCFc!(cCeI%3^mN z7-2yIa6JM7>2g#DGmU4u@rMugDyUk0@s5WZ>c_YKv%>i8vnz{WJwU)K&x~up*eWf& zvZzb?{CDWtvq;4M@Z3B;gpADi(6?%Dg2}NOF%|JEJihsfot7)};W@eg98UTGLBqpg zp5VDq_sr?x35#VSOpL$TKFiJtd*S&5(wn=gM%R%1y@WjMwho`d@f_9otf9W* zv!@vHGRkhTKvsVH?HzCbwr!^+Te|CSuVF2B5&HCw_lPW27q%Dd_-#uzOvf$QYHr6L zB=Pzos9vuX;c`0^u%K+q&bCv=8ZcT-5p#q}5pZU)3HmW%=*b_hdq<_f#~V)GhH8cB zj0^+^C`TDW^!8t`cOyza{Ap!G{^>!D(<;^2AEY;Ke-iv^A=XcJRa;w);orFaEVbu! zcq3Xi$)q@T24$XO%T_~a> zl=k=RqBEC!dg6;uB3qRrKqTImxqkth0OPc6KY)LL={Ovsz51yK7ynBHTA;8k;mBMi1}AvMxIPf zg@D=Fq0xs_EB8^mIfv8`AkPZ5$>Uq0o%3(%bXcEa#NS9tLt9l}0pF6beVc)^vNAHZ zVXx(B2}FygyL#>9$!iQsi*+cgtLINnujBK~lg2zkz--0PkBv`?=jf(Kzw%_$`le0e z8&@+5O_o5Eabn{H>;^)?SGZbAGPaz4v2&(;YO~eXoBDaH!W04#&*9uTBc21w%lHqbysS{{^3>j+fhU9) zyZ|)y40tBu0uPTTr_klTpL_u!X5h=aIXSJ%FQDaU8t8a&`_AKm!5J)biqt>8d;9y& zLA8=3G&yPP%p+~2lTBUh7j^O5PobZW^78><=E2T`pC{=f*gq5>JVlIdNg{sw@+EkE z@IN>_U4}|kVdfm+OJg2`w>RetgHw!MKiR$^T{HOAswy9sgvgt>6xUQ~stxEC>{DKa zcEOwOY$>)>wN#OcEk(su#Spu8Lmvlhu6s|d%3EInuOwfZGbxG1Cd%)oy@@hA%uRE& zGTAGLp)8x74eYvu$Xj!>^GkEH0bZM(om+Xf#F#B|@{D_-1_VO0369=?WRIf!e7x}` zxT~JcMt)4}mC*jFN}&?aZW9cD0J<|PeB|P%+D9KKtoTv`%g4XOYJQKue=#zT(?;Eu z&E`S?HVpGj0l5*S8-x<_%+cQJz)|qs$B%1STqd_Ze*E|-#{iIuS&6wZCXSBb!4&W*5`LQW6 zZD36KZ+My^>)u$BJ?dryEp26Kr?`1K!oq?xK9{x+n$(FYFSy8Y_y|BL%RbeXmUgP6 z5#%jGjvEcToJWuDvYtq5yt<2G0*I2hayRD47@Lx0Q)%|aq$G2l)UleHW3pa~3ig^~ z$g!6wuPSNxEd?`=g)Nl}Oa%P|7i~&c`j({KnkBn3c4{yKi~n#lm;D(L>mpJS(G7U9$xNXOM)}hl`O2X1irZ6n(xN%F9bdbc}2L z{pa#_vk=NbA)ew$JlN1>wg0KSddB!ODHs&AwuF_y!^CS4MJbgEX%lQ**pCBy+eyoc z82RN(2A27vQuaTMtNqk=>?dmruAp>aCK729&bKqtnSLOIpvCDGGm$3BK24F(AcBd@ zTGtFbJVYreJsp-XH0B0i#9g1k<-y3H3(M2tn2QWe$j4n+(but`kQgCj){$ZFM%jrX z6B9V_XX944wad-g7xK#|CN!Vc(}#;UeqDwELL2Vx`{PM4fW=y+N8@f7#Kn1)dBu6y zbr75)i8vnqu=KwkDLs5*zvcYjCtLpdpRJa|yFR|rvNy%@KmT`< -#include #include #include +#ifdef SENSECAP_INDICATOR_LORA + #define RADIOLIB_STATIC_ONLY 1 + #include + #include + #include "IndicatorRadioHal.h" + #include "IndicatorSX1262Wrapper.h" +#else + #include +#endif #ifdef ENV_INCLUDE_GPS #include #endif @@ -13,7 +21,11 @@ #endif extern ESP32Board board; -extern ESPNOWRadio radio_driver; +#ifdef SENSECAP_INDICATOR_LORA + extern WRAPPER_CLASS radio_driver; +#else + extern ESPNOWRadio radio_driver; +#endif extern ESP32RTCClock rtc_clock; extern EnvironmentSensorManager sensors; @@ -23,4 +35,7 @@ extern EnvironmentSensorManager sensors; #endif bool radio_init(); +#ifdef RECOVERABLE_EXTERNAL_RADIO +uint32_t radio_fallback_rng_seed(); +#endif mesh::LocalIdentity radio_new_identity();