Clarify 1.18.0.1 changes and firmware download choices
This commit is contained in:
1 parent
06edf9aa8a
commit
da08008893
8 files changed
+428
-210
No files matched your search
+35
-5
@@ -73,8 +73,38 @@ release title/body, and the final asset inventory after publication. Preserve
|
||||
existing assets when making a documentation-only release edit.
|
||||
The current trigger explicitly excludes `repeater-room-*`.
|
||||
|
||||
Use role-specific introductions for Companion, Repeater/Room Server, Sensor,
|
||||
LoRa OTA Repeater, and expanded Full infrastructure pages. Link the exact
|
||||
board/storage [OTAFIX 2.4.12 release](https://github.com/mikecarper/Adafruit_nRF52_Bootloader_OTAFIX/releases/tag/v0.11.0-OTAFIX2.4.12)
|
||||
where nRF52 bootloader requirements apply. Later documentation commits can be
|
||||
linked from release notes without moving the firmware tag or rebuilding assets.
|
||||
## Release notes
|
||||
|
||||
Write one public release page at `docs/releases/VERSION.md`. Make it the
|
||||
starting point from the documentation home page and every GitHub download page.
|
||||
Use the same format for each revision:
|
||||
|
||||
1. **Status and purpose:** stable or testing, version, region, and one sentence
|
||||
explaining the user benefit.
|
||||
2. **New:** a short list of actual additions since the previous stable release.
|
||||
Say who each change helps; link setup instructions beside the feature.
|
||||
3. **Fixed:** name affected boards and the behavior corrected.
|
||||
4. **Choose a download:** picker first, then a short table of role-specific
|
||||
GitHub pages. Explain Full/Reduced sensors and included bootloaders once.
|
||||
5. **Before updating:** only required actions, changed defaults and compatibility
|
||||
limits. Link the installation guides instead of copying them.
|
||||
6. **Tested and limitations:** separate build checks from physical tests. Name
|
||||
important remaining limitations and link source-specific evidence.
|
||||
|
||||
Compare the actual previous release's source and notes. A long commit list can
|
||||
include old work imported by merges; do not present it all as new. Do not relist
|
||||
existing features as additions. Keep tuning commands, build counts, memory
|
||||
layouts and implementation details in the reference guides or test reports.
|
||||
|
||||
The main GitHub release should summarize New, Fixed and Tested in a few bullets
|
||||
and link the public release page. Other download pages should lead with their
|
||||
purpose and link the same notes. Use readable link names such as "ESP32
|
||||
Repeater, Room Server and Sensor" rather than internal keys like `full-profiles`.
|
||||
Label split pages "part 1 of 3" and explain that they contain the same version,
|
||||
not different feature levels. The picker should find the exact board for users.
|
||||
|
||||
Keep required bootloader guidance linked to the exact board/storage
|
||||
[OTAFIX release](https://github.com/mikecarper/Adafruit_nRF52_Bootloader_OTAFIX/releases/tag/v0.11.0-OTAFIX2.4.12).
|
||||
A notes-only correction may update public titles, bodies and documentation.
|
||||
Preserve published tags, binaries, attached build notes and checksum files;
|
||||
verify release status, Latest and the asset inventory remain unchanged.
|
||||
+13
-5
@@ -4,14 +4,21 @@
|
||||
|
||||
# MeshCore documentation
|
||||
|
||||
Choose firmware with the [firmware picker](firmware_picker.md). For help with a device already in service, start with the [FAQ](faq.md).
|
||||
## Start here
|
||||
|
||||
## Current release
|
||||
**Current stable release: [1.18.0.1 USA Cascade](releases/1.18.0.1.md).**
|
||||
Read what changed, which boards benefit and the known limitations in one place.
|
||||
|
||||
- [1.18.0.1 USA Cascade release notes](releases/1.18.0.1.md)
|
||||
- [Test Results](test-results/index.md) - source-specific validation archive
|
||||
| I want to... | Start here |
|
||||
| --- | --- |
|
||||
| See what is new or fixed | [1.18.0.1 release notes](releases/1.18.0.1.md) |
|
||||
| Download firmware for my board | [Firmware picker](firmware_picker.md) |
|
||||
| Install an update | [Update guide](ota_user_guide.md) |
|
||||
| Turn a feature on or off | [Feature controls by role](role_feature_switches.md) |
|
||||
| Find a command | [CLI reference](cli_commands.md) |
|
||||
| Troubleshoot a device | [FAQ](faq.md) |
|
||||
|
||||
## Documentation
|
||||
## Detailed guides
|
||||
|
||||
- [SolarXiao Base/Advanced/MPPT detection and battery controls](solarxiao_power.md)
|
||||
|
||||
@@ -32,6 +39,7 @@ The navigation groups the remaining guides under Documentation, including board-
|
||||
|
||||
## Engineering records
|
||||
|
||||
- [Test Results](test-results/index.md) - hardware and build evidence, with the tested versions
|
||||
- [Research](research/index.md) - design notes, diagnostics, and historical update-chain studies
|
||||
- [Old Releases](old-releases/index.md) - historical release notes and supporting files
|
||||
|
||||
|
||||
+108
-90
@@ -4,13 +4,15 @@
|
||||
|
||||
# Updating your node over the air (OTA) - user guide
|
||||
|
||||
For **1.17.1.5**, use the exact board/storage profile from
|
||||
[OTAFIX 2.4.6](https://github.com/mikecarper/Adafruit_nRF52_Bootloader_OTAFIX/releases/tag/0.11.0-OTAFIX2.4.6)
|
||||
for nRF52 OTAFIX installations. New internal-flash hybrid receivers require
|
||||
its 64 KiB retained-RAM handoff; QSPI and microSD targets require their own
|
||||
matching bootloader profiles. Earlier preview versions mentioned below
|
||||
describe compatibility/migration history, not the current recommended download.
|
||||
Full Companion is a MOTA source and normally updates itself over USB.
|
||||
For **[1.18.0.1 USA Cascade](releases/1.18.0.1.md)**, choose the exact board,
|
||||
role and storage layout in the [firmware picker](firmware_picker.md). Supported
|
||||
nRF52 Repeater and Room Server images can include the matching OTAFIX 2.4.12
|
||||
bootloader; see the [embedded bootloader guide](nrf52_embedded_bootloader.md).
|
||||
Ordinary application images preserve the installed bootloader. Standalone
|
||||
bootloader downloads require an exact board/storage match from
|
||||
[OTAFIX 2.4.12](https://github.com/mikecarper/Adafruit_nRF52_Bootloader_OTAFIX/releases/tag/v0.11.0-OTAFIX2.4.12).
|
||||
Full Companion sends LoRa updates to other nodes and normally updates itself
|
||||
over USB. Older versions mentioned below describe compatibility history.
|
||||
|
||||
Before a Companion upgrade, export its contacts when possible. ESP32, RP2040
|
||||
and STM32 can retain complete legacy records ahead of an interrupted final
|
||||
@@ -60,90 +62,19 @@ preserves the RX benefit without risking missed packets from a legacy
|
||||
> application image alone is not enough. An intermediate repeater only relays packets and needs neither an
|
||||
> install-capable image nor OTAFIX. Check the bootloader release for an exact board match before attempting an update.
|
||||
|
||||
The following nRF52 repeater families gained firmware-side LoRa OTA targets in
|
||||
this release. Their ordinary repeater keeps its complete declared sensor recipe;
|
||||
the install-capable `lora_ota_no_external_sensors` sibling is smaller:
|
||||
|
||||
- Heltec Mesh Solar, T1, and Tower V2
|
||||
- Keepteen LT1, LilyGo T-Impulse Plus, Mesh Pocket, and Nano G2 Ultra
|
||||
- Minewsemi ME25LS01, RAK3401, SenseCAP Solar, and Wio WM1110
|
||||
|
||||
The RAK3401 `RAK_3401_repeater_lora_ota_no_external_sensors` image trims selected
|
||||
optional environmental/ranging drivers but does not disable I2C. It retains the
|
||||
INA219, INA226, INA260, and INA3221 voltage/current monitors, board display and
|
||||
RTC support, and both RAK12500 I2C and RAK12501/L76K UART GPS paths. The four
|
||||
INA drivers are only the retained voltage/current entries in the optional
|
||||
environmental-sensor table; they are not the only I2C users. The SSD1306 OLED,
|
||||
autodiscovered DS3231/RV3028/PCF8563/RX8130CE RTCs, and RAK12500 GPS use I2C as
|
||||
separate board peripherals. Install one GPS module in sensor slot A. Slot D's
|
||||
reset/PPS lines conflict with the RAK13302 radio's BUSY/DIO1 lines.
|
||||
|
||||
The firmware-configured INA3221 address and the RAK12500 address are both
|
||||
`0x42`, so those devices cannot share one bus at those addresses. To install
|
||||
both, leave the RAK12500 at `0x42`, strap INA3221 A0 to SCL for `0x43`, and use
|
||||
a firmware build with `-DTELEM_INA3221_ADDRESS=0x43`.
|
||||
|
||||
The reduced RAK4631 profiles likewise retain the four INA monitors. The plain
|
||||
repeater and Serial2 bridge retain GPS: a RAK12501 can use sensor slot A or D,
|
||||
and a RAK12500 can use slot A or C. The runtime RS-232 bridge defaults to
|
||||
Serial2 so the UART RAK12501 can retain Serial1. The merged runtime image always
|
||||
reserves Serial1: a bounded silent probe cannot prove that a cold RAK12501 is
|
||||
absent, and turning the GPS setting off cannot stop a fitted module from driving
|
||||
the shared UART while WB_IO2/3V3_S remains powered. Use Serial2. Serial1 requires
|
||||
an explicit no-GPS/dedicated image. The reservation remains fail-closed even
|
||||
when an I2C RAK12500 is detected. The explicitly compiled
|
||||
`RAK_4631_repeater_bridge_rs232_serial1_lora_ota_no_external_sensors` target
|
||||
omits the combined GPS provider because its bridge owns the UART used by
|
||||
RAK12501; consequently that legacy image does not expose the I2C RAK12500 path
|
||||
either, even though RAK12500 itself does not use the UART.
|
||||
|
||||
Selected nRF52 repeaters with dedicated external QSPI can now stage the
|
||||
complete package off-chip, so their normal full-sensor repeater build can
|
||||
install a full image or an in-place delta. The current matched families are
|
||||
XIAO nRF52840 and its XIAO-module derivatives, original LilyGo T-Echo,
|
||||
ThinkNode M1/M6, Wio Tracker L1, SenseCAP Solar, and the dedicated RAK4631 +
|
||||
RAK15001 slot-C target. The list also includes a separately wired W25Q16JV on
|
||||
RAK19007 with either RAK4631 or RAK3401 + RAK13302. These require the
|
||||
corresponding exact QSPI-aware OTAFIX bootloader; see
|
||||
[the nRF52 QSPI guide](ota_nrf52_qspi.md).
|
||||
|
||||
The W25Q16 option uses one permanent RAK19007 wiring for either core: CLK/MISO/
|
||||
MOSI tap IO-connector pins 26/27/28, flash CS uses J11 AIN1, and power uses J12
|
||||
VDD (3.3 V) and GND. Add an approximately 10 kOhm CS-to-VDD pull-up and never
|
||||
power the flash from VBAT. The three SPI signals require underside pads or an
|
||||
IO-connector interposer; the easy J10/J11/J12 headers do not expose them. The
|
||||
flash consumes no WisBlock slot, so a supported GPS can remain in slot A.
|
||||
|
||||
The unified RAK repeater images additionally support a header-only W25Q16
|
||||
layout, using J10 `TX1`/`RX1` and J11 `IO1`/`AIN1`. This layout needs the
|
||||
matching compatible OTAFIX 2.4.10 bootloader and gives up UART1 GPS/PPS; I2C
|
||||
sensors remain available. See the [pin table](ota_nrf52_qspi.md#header-only-w25q16-wiring-for-the-unified-rak-images).
|
||||
|
||||
The ordinary full-sensor `RAK_4631_repeater` image remains too large for the
|
||||
safe internal in-place update limit. Without external flash, use
|
||||
`RAK_4631_repeater_lora_ota_no_external_sensors`; it trims selected optional
|
||||
environmental/ranging drivers while retaining generic I2C, battery monitoring,
|
||||
the four INA monitors, and target-compatible GPS. A RAK4631 fitted with
|
||||
RAK15001 in sensor slot C can instead use
|
||||
`RAK_4631_repeater_rak15001_slot_c_lora_ota` to retain the full sensor/GPS set
|
||||
and stage full images or deltas off-chip.
|
||||
|
||||
For the external Winbond breakout, use
|
||||
`RAK_4631_repeater_w25q16_lora_ota` on RAK4631 or
|
||||
`RAK_3401_repeater_rak13302_w25q16_lora_ota` on RAK3401 + RAK13302. They retain
|
||||
the full sensor/GPS recipe and require exactly a 2 MiB `EF4015` W25Q16 plus the
|
||||
bootloader for that same core/radio/flash combination. Install
|
||||
`wiscore_rak4631_w25q16` for RAK4631 or
|
||||
`wiscore_rak3401_rak13302_w25q16` for RAK3401 + RAK13302 as a one-time
|
||||
prerequisite. The physical wiring is shared, but the two firmware identities
|
||||
are deliberately different and cannot be substituted for one another.
|
||||
For nRF52 storage and wiring requirements, see the
|
||||
[QSPI hardware guide](ota_nrf52_qspi.md). Older image names and board-specific
|
||||
constraints are collected in the [hardware reference](#hardware-and-older-image-layouts)
|
||||
at the end of this page; use the picker for current downloads.
|
||||
|
||||
---
|
||||
|
||||
## The important part first: it's safe
|
||||
## Before you start
|
||||
|
||||
- **Nothing installs by itself.** Your node can *discover* and download an update, but
|
||||
it only **installs** when you say so (unless you deliberately turn on auto-install - see below).
|
||||
- **Application updates require installation approval** unless you enable
|
||||
auto-install. Images labelled **with bootloader** have a separate automatic
|
||||
bootloader check after 70 seconds; read the [bootloader guide](nrf52_embedded_bootloader.md)
|
||||
before choosing one.
|
||||
- **Bad downloads can't sneak in.** Every piece of the firmware is checked against a cryptographic
|
||||
fingerprint as it arrives, and the whole image is verified again before install. A corrupt or tampered
|
||||
download is rejected, not installed.
|
||||
@@ -152,8 +83,9 @@ are deliberately different and cannot be substituted for one another.
|
||||
- **Discovery stays quiet; a transfer is deliberate.** Periodic update discovery uses background priority.
|
||||
Once a download starts, its transfer packets are primary traffic across every relay hop, so use
|
||||
TempRadio as an OTA maintenance window when delaying unrelated mesh traffic would matter.
|
||||
- **It can recover.** If an install ever fails, the node falls back to a safe recovery mode (you can
|
||||
re-flash a known-good firmware over USB) - it won't be left bricked.
|
||||
- **Know the recovery route.** Keep local USB/DFU or SWD access available where
|
||||
practical. Recovery depends on the board, installed bootloader and failure;
|
||||
a bootloader update can require a debugger if interrupted.
|
||||
|
||||
---
|
||||
|
||||
@@ -402,7 +334,8 @@ complete target inventory, storage layouts, and safety contract.
|
||||
without valid live `EndF`, they refuse every internal pull before erase
|
||||
because their normal application can extend through `0xED000`. Recover one
|
||||
of those builds over USB/BLE DFU or SWD.
|
||||
- If an **install** fails, the node won't boot a broken image - it lands in **recovery mode**:
|
||||
- If an **install** fails, recovery depends on the board and bootloader. When
|
||||
its recovery mode remains available:
|
||||
- **nRF52:** it appears as a USB drive; drag a known-good firmware `.uf2` for that exact board onto it
|
||||
to recover.
|
||||
- **ESP32:** it keeps the previous firmware in the other slot and rolls back.
|
||||
@@ -710,3 +643,88 @@ that only contains what changed). You get them by:
|
||||
|
||||
For the full technical details (the file format and the radio protocol), see
|
||||
[the OTA protocol spec](ota_protocol.md).
|
||||
|
||||
## Hardware and older image layouts
|
||||
|
||||
Use the [firmware picker](firmware_picker.md) for current downloads. These
|
||||
notes retain hardware constraints and older image names for existing nodes.
|
||||
The 1.18.0.1 RAK release has separately checked Full/Reduced sensor images;
|
||||
older size limits below are not instructions to choose a Reduced build today.
|
||||
|
||||
Older firmware used separate `lora_ota_no_external_sensors` images on the
|
||||
following families. These names explain older installations; use the current
|
||||
picker's Full/Reduced sensor choices for 1.18.0.1:
|
||||
|
||||
- Heltec Mesh Solar, T1, and Tower V2
|
||||
- Keepteen LT1, LilyGo T-Impulse Plus, Mesh Pocket, and Nano G2 Ultra
|
||||
- Minewsemi ME25LS01, RAK3401, SenseCAP Solar, and Wio WM1110
|
||||
|
||||
The RAK3401 `RAK_3401_repeater_lora_ota_no_external_sensors` image trims selected
|
||||
optional environmental/ranging drivers but does not disable I2C. It retains the
|
||||
INA219, INA226, INA260, and INA3221 voltage/current monitors, board display and
|
||||
RTC support, and both RAK12500 I2C and RAK12501/L76K UART GPS paths. The four
|
||||
INA drivers are only the retained voltage/current entries in the optional
|
||||
environmental-sensor table; they are not the only I2C users. The SSD1306 OLED,
|
||||
autodiscovered DS3231/RV3028/PCF8563/RX8130CE RTCs, and RAK12500 GPS use I2C as
|
||||
separate board peripherals. Install one GPS module in sensor slot A. Slot D's
|
||||
reset/PPS lines conflict with the RAK13302 radio's BUSY/DIO1 lines.
|
||||
|
||||
The firmware-configured INA3221 address and the RAK12500 address are both
|
||||
`0x42`, so those devices cannot share one bus at those addresses. To install
|
||||
both, leave the RAK12500 at `0x42`, strap INA3221 A0 to SCL for `0x43`, and use
|
||||
a firmware build with `-DTELEM_INA3221_ADDRESS=0x43`.
|
||||
|
||||
The reduced RAK4631 profiles likewise retain the four INA monitors. The plain
|
||||
repeater and Serial2 bridge retain GPS: a RAK12501 can use sensor slot A or D,
|
||||
and a RAK12500 can use slot A or C. The runtime RS-232 bridge defaults to
|
||||
Serial2 so the UART RAK12501 can retain Serial1. The merged runtime image always
|
||||
reserves Serial1: a bounded silent probe cannot prove that a cold RAK12501 is
|
||||
absent, and turning the GPS setting off cannot stop a fitted module from driving
|
||||
the shared UART while WB_IO2/3V3_S remains powered. Use Serial2. Serial1 requires
|
||||
an explicit no-GPS/dedicated image. The reservation remains fail-closed even
|
||||
when an I2C RAK12500 is detected. The explicitly compiled
|
||||
`RAK_4631_repeater_bridge_rs232_serial1_lora_ota_no_external_sensors` target
|
||||
omits the combined GPS provider because its bridge owns the UART used by
|
||||
RAK12501; consequently that legacy image does not expose the I2C RAK12500 path
|
||||
either, even though RAK12500 itself does not use the UART.
|
||||
|
||||
Selected nRF52 repeaters with dedicated external QSPI can stage the
|
||||
complete package off-chip, so their normal full-sensor repeater build can
|
||||
install a full image or an in-place delta. The current matched families are
|
||||
XIAO nRF52840 and its XIAO-module derivatives, original LilyGo T-Echo,
|
||||
ThinkNode M1/M6, Wio Tracker L1, SenseCAP Solar, and the dedicated RAK4631 +
|
||||
RAK15001 slot-C target. The list also includes a separately wired W25Q16JV on
|
||||
RAK19007 with either RAK4631 or RAK3401 + RAK13302. These require the
|
||||
corresponding exact QSPI-aware OTAFIX bootloader; see
|
||||
[the nRF52 QSPI guide](ota_nrf52_qspi.md).
|
||||
|
||||
The W25Q16 option uses one permanent RAK19007 wiring for either core: CLK/MISO/
|
||||
MOSI tap IO-connector pins 26/27/28, flash CS uses J11 AIN1, and power uses J12
|
||||
VDD (3.3 V) and GND. Add an approximately 10 kOhm CS-to-VDD pull-up and never
|
||||
power the flash from VBAT. The three SPI signals require underside pads or an
|
||||
IO-connector interposer; the easy J10/J11/J12 headers do not expose them. The
|
||||
flash consumes no WisBlock slot, so a supported GPS can remain in slot A.
|
||||
|
||||
The unified RAK repeater images additionally support a header-only W25Q16
|
||||
layout, using J10 `TX1`/`RX1` and J11 `IO1`/`AIN1`. This layout needs the
|
||||
matching compatible OTAFIX 2.4.10 bootloader and gives up UART1 GPS/PPS; I2C
|
||||
sensors remain available. See the [pin table](ota_nrf52_qspi.md#header-only-w25q16-wiring-for-the-unified-rak-images).
|
||||
|
||||
Older full-sensor `RAK_4631_repeater` images exceeded the safe internal
|
||||
in-place update limit. Their smaller sibling,
|
||||
`RAK_4631_repeater_lora_ota_no_external_sensors`, trims selected optional
|
||||
environmental/ranging drivers while retaining generic I2C, battery monitoring,
|
||||
the four INA monitors, and target-compatible GPS. A RAK4631 fitted with
|
||||
RAK15001 in sensor slot C can instead use
|
||||
`RAK_4631_repeater_rak15001_slot_c_lora_ota` to retain the full sensor/GPS set
|
||||
and stage full images or deltas off-chip.
|
||||
|
||||
For the external Winbond breakout, use
|
||||
`RAK_4631_repeater_w25q16_lora_ota` on RAK4631 or
|
||||
`RAK_3401_repeater_rak13302_w25q16_lora_ota` on RAK3401 + RAK13302. They retain
|
||||
the full sensor/GPS recipe and require exactly a 2 MiB `EF4015` W25Q16 plus the
|
||||
bootloader for that same core/radio/flash combination. Install
|
||||
`wiscore_rak4631_w25q16` for RAK4631 or
|
||||
`wiscore_rak3401_rak13302_w25q16` for RAK3401 + RAK13302 as a one-time
|
||||
prerequisite. The physical wiring is shared, but the two firmware identities
|
||||
are deliberately different and cannot be substituted for one another.
|
||||
+65
-86
@@ -2,105 +2,84 @@
|
||||
<p class="meshcore-hosted-doc-link"><a href="https://mikecarper.github.io/MeshCore/releases/1.18.0.1/">View this page on MeshCore Docs</a>.</p>
|
||||
<!-- meshcore-hosted-doc-link:end -->
|
||||
|
||||
# MeshCore 1.18.0.1 USA Cascade
|
||||
# MeshCore 1.18.0.1 - USA Cascade
|
||||
|
||||
Firmware source: `03214a16df2bd09d3272dfb001d2d322c6740f60`.
|
||||
**Stable release.** Meshtext chat, simpler ESP32 administration and new repeater
|
||||
controls. Changes below are relative to **1.17.1.9**.
|
||||
|
||||
USA Cascade defaults are **910.525 MHz, 62.5 kHz bandwidth, SF7 and CR5**.
|
||||
Saved radio settings take precedence. Choose the exact board, radio, storage
|
||||
layout and role in the [firmware picker](../firmware_picker.md).
|
||||
[Choose your firmware](../firmware_picker.md) | [Update instructions](../ota_user_guide.md)
|
||||
|
||||
Download the [1.18.0.1 release family](https://github.com/mikecarper/MeshCore/releases/tag/v1.18.0.1-halo-keymind-cascade-dev-03214a16)
|
||||
and its [migration and bootloader utilities](https://github.com/mikecarper/MeshCore/releases/tag/utility-v1.18.0.1-halo-keymind-cascade-dev-03214a16).
|
||||
The picker, Mesh America and the Keymind choices in meshfirmware select these
|
||||
same exact release assets.
|
||||
## New
|
||||
|
||||
## Changes since 1.17.1.9
|
||||
- **Meshtext chat on supported Full Companions**, including T1000-E.
|
||||
Use channels such as `#mt-longfast`; see [Meshtext setup](../radio_profiles.md#meshtext-channel-chat).
|
||||
- **WiFi repeater bridge:** connect up to eight peers by IP on an existing
|
||||
network. [WiFi setup](../udp_bridge_setup.md).
|
||||
[ESP-NOW](../espnow_bridge_setup.md) and [RS232](../rs232_bridge_setup.md)
|
||||
also gain status, counters and link tests.
|
||||
- **One ESP32 admin password** for device setup, browser administration and
|
||||
WiFi firmware uploads. Router WiFi passwords and Bluetooth PINs stay separate.
|
||||
[Password details](../WiFi.md)
|
||||
- **Telemetry choices:** turn individual packet types on or off. All types
|
||||
are selected by default; sending telemetry still requires enabling it.
|
||||
[Telemetry controls](../cli_commands.md#read-repeater-telemetry-history)
|
||||
- **Low-battery forwarding limits:** optionally stop repeating below 10% and
|
||||
flooding below 20%, or set your own thresholds. Both limits default off.
|
||||
[Battery controls](../cli_commands.md#pause-forwarding-when-the-battery-is-low)
|
||||
- **Radio2 setup warns about overlapping channels** and suggests a clearer
|
||||
center frequency. [Channel spacing](../radio_profiles.md#channel-spacing).
|
||||
Supported boards also gain [faster switching and saved tuning controls](../radio_profiles.md#saved-switching-controls).
|
||||
- **T114 automatic screen detection:** one image for boards with or without
|
||||
the supported display.
|
||||
- **Optional nRF52 bootloader update included** in supported Repeater and
|
||||
Room Server images. These carry the exact board's OTAFIX 2.4.12 bootloader.
|
||||
[Installation requirements](../nrf52_embedded_bootloader.md#install-and-activate)
|
||||
|
||||
- Supported nRF52 Repeater and Room Server targets have separate application
|
||||
images carrying their exact-board **OTAFIX 2.4.12** bootloader. Ordinary
|
||||
applications remain available, together with standalone bootloader files.
|
||||
- Full Companion includes Meshtext on all supported board families. Message
|
||||
retries are bounded; repeated traffic does not become a new local message.
|
||||
- [ESP-NOW](../espnow_bridge_setup.md) and
|
||||
[RS232](../rs232_bridge_setup.md) bridges provide runtime status, counters
|
||||
and link probes. The [WiFi UDP bridge](../udp_bridge_setup.md) supports eight
|
||||
authenticated IP peers per repeater on an existing station network.
|
||||
- [Telemetry packet selections](../cli_commands.md#read-repeater-telemetry-history)
|
||||
independently control temperature, battery, external I2C voltage, main-radio
|
||||
noise and radio2 noise snapshots. All five selections default on; the
|
||||
telemetry transmitter itself remains off until enabled.
|
||||
- Optional [battery forwarding thresholds](../cli_commands.md) can stop repeat
|
||||
and flood forwarding independently. Both controls default off; their
|
||||
percentages and supported voltage calibration are saved settings.
|
||||
- Supported radios expose saved `radio.fast` acceleration controls and
|
||||
`radio.fast.spi` choices. A `9` MHz selection uses approximately 8.889 MHz
|
||||
where the controller supports that rate. Read `get radio.fast.caps` for the
|
||||
actual board's options.
|
||||
- Board profiles consolidate supported display and transport choices, including
|
||||
T114 automatic display detection. Exact V4 hardware and storage variants
|
||||
remain distinct where their wiring requires a different image.
|
||||
- T1000-E Companion gives an enumerated USB data connection priority over
|
||||
Bluetooth. Bluetooth resumes after USB disconnects if it is enabled;
|
||||
battery and a charge-only wall supply allow Bluetooth. Pairing and the saved
|
||||
Bluetooth setting are retained.
|
||||
- Release capacity fixes retain the qualified feature sets with compact help,
|
||||
shared buffers and board-specific memory placement. Every image includes its
|
||||
own capability and memory reports; capacities still differ between boards.
|
||||
## Fixed
|
||||
|
||||
See [feature controls](../role_feature_switches.md), the
|
||||
[Full Companion guide](../full_companion_features.md) and
|
||||
[CLI reference](../cli_commands.md) for supported commands and defaults.
|
||||
- G3 startup and radio pin/slot handling.
|
||||
- XIAO nRF52 external-flash startup, storage alignment and Bluetooth handling.
|
||||
- V4 USB logging idle/reopen failures and ESP32 Bluetooth/power-saving recovery.
|
||||
|
||||
## Choose an installation
|
||||
## Choose a download
|
||||
|
||||
For ESP32, the merged `.bin` installs bootloader, partitions and application
|
||||
over USB. An app-only `.bin` requires a compatible existing partition layout.
|
||||
When expansion is needed over WiFi or LoRa, use the exact board/role migration
|
||||
ZIP in this release family's utility page and install its supplied Full
|
||||
application. Follow the included README; an app-only image cannot expand
|
||||
partitions. `get storage.layout` reports the live layout where supported.
|
||||
Use the **[firmware picker](../firmware_picker.md)** to match your exact board
|
||||
and role. The GitHub pages below contain the **same version**, split to fit
|
||||
GitHub's download limits.
|
||||
|
||||
Ordinary nRF52 UF2 and Serial DFU ZIP files install the application and preserve
|
||||
the installed bootloader. Repeater, Room Server and Sensor retain separately
|
||||
qualified **Full supported sensors + LoRa OTA** and
|
||||
**Reduced sensors + LoRa OTA** choices. These keep the exact OTA target and
|
||||
storage layout; sensor policy is not a different radio identity.
|
||||
| What you run | Download page |
|
||||
| --- | --- |
|
||||
| A radio connected to your phone or computer | [Companion](https://github.com/mikecarper/MeshCore/releases/tag/v1.18.0.1-halo-keymind-cascade-dev-03214a16) |
|
||||
| An ESP32 Repeater, Room Server or Sensor | [ESP32 infrastructure](https://github.com/mikecarper/MeshCore/releases/tag/full-profiles-v1.18.0.1-halo-keymind-cascade-dev-03214a16) |
|
||||
| An nRF52 Repeater, Room Server or Sensor | [Part 1](https://github.com/mikecarper/MeshCore/releases/tag/lora-ota-v1.18.0.1-halo-keymind-cascade-dev-03214a16), [Part 2](https://github.com/mikecarper/MeshCore/releases/tag/lora-ota-2-v1.18.0.1-halo-keymind-cascade-dev-03214a16), [Part 3](https://github.com/mikecarper/MeshCore/releases/tag/lora-ota-3-v1.18.0.1-halo-keymind-cascade-dev-03214a16) - use the picker to find your board |
|
||||
| A partition migration or separate bootloader update | [Update utilities](https://github.com/mikecarper/MeshCore/releases/tag/utility-v1.18.0.1-halo-keymind-cascade-dev-03214a16) |
|
||||
|
||||
Separate `with-bootloader-2.4.12` Repeater and Room Server applications carry a
|
||||
board-matched bootloader. Leave the application powered for at least 70 seconds
|
||||
after installation. It checks once when radio and OTA activity are idle and
|
||||
updates a recognized compatible older bootloader; matching current or newer
|
||||
versions are skipped. Recovery or unrecognized bootloaders require their
|
||||
documented local migration route. Check `get bootloader.ver` afterward. See
|
||||
[embedded bootloader installation](../nrf52_embedded_bootloader.md).
|
||||
**Full Companion** combines supported connections and features in one image.
|
||||
**Full / Reduced sensors** selects optional sensor drivers on nRF52 infrastructure.
|
||||
**With bootloader** includes the matched bootloader update.
|
||||
|
||||
The utility release also supplies exact-board bootloader-update UF2,
|
||||
SoftDevice/bootloader DFU ZIP and SWD HEX files for 23 published OTAFIX profiles
|
||||
covering 40 hardware aliases. The SoftDevice/bootloader DFU package requires
|
||||
reinstalling the application. Pending, blocked and retired board mappings are
|
||||
identified rather than replaced by another board's image.
|
||||
## Before updating
|
||||
|
||||
LoRa OTA reception requires the matching bootloader, target identity, storage
|
||||
layout and radio settings. Full Companion can send a host-supplied update to
|
||||
another node; it does not install that LoRa transfer onto itself.
|
||||
- Match the exact board and storage layout. ESP32 USB installs use a merged
|
||||
image; WiFi updates use an app-only image and a compatible partition layout.
|
||||
[Update guide](../ota_user_guide.md)
|
||||
- An included nRF52 bootloader checks for a compatible older version after
|
||||
70 seconds. It is not a recovery tool for an unrecognized bootloader.
|
||||
[Bootloader guide](../nrf52_embedded_bootloader.md)
|
||||
- Fresh USA Cascade radio defaults: **910.525 MHz / BW62.5 / SF7 / CR5**.
|
||||
Existing saved radio settings take precedence.
|
||||
|
||||
## Verification scope
|
||||
## Tested and limitations
|
||||
|
||||
The complete release has **589 qualified firmware packages**: 435 ordinary
|
||||
packages and 154 embedded-bootloader variants. The latter cover 77 logical
|
||||
Repeater/Room targets with both sensor policies. It also includes **69
|
||||
standalone bootloader files**, **96 exact ESP32 board/role migration packages**
|
||||
and **26 migration utility builds**.
|
||||
The complete release passed build, memory and package checks, and
|
||||
[release-source CI](https://github.com/mikecarper/MeshCore/actions/runs/40101490838).
|
||||
[Hardware reports](../test-results/index.md) cover USB, Bluetooth, contact sync,
|
||||
LoRa and updates at the revisions recorded. The final build has not been
|
||||
physically tested on every board.
|
||||
|
||||
The completed matrix passed exact target inventory, source provenance,
|
||||
checksums, packaged OTA identity, native DFU, firmware size, runtime RAM,
|
||||
sensor-pair, bootloader mapping and migration-layout validation. All 14 jobs in
|
||||
the [source revision's CI run](https://github.com/mikecarper/MeshCore/actions/runs/40101490838)
|
||||
passed.
|
||||
- **T1000-E:** Bluetooth pauses while connected to a USB data host and resumes
|
||||
after unplugging if enabled. Bluetooth works on battery or a charge-only supply.
|
||||
- **Radio2:** two profiles share one radio; simultaneous reception is not guaranteed.
|
||||
- **Morse receive:** noise can still produce false letters.
|
||||
|
||||
Physical results remain tied to the hardware, revision and installation route
|
||||
recorded in the [test reports](../test-results/index.md). Building every target
|
||||
does not establish every board's physical USB, Bluetooth, WiFi, RF, sleep or
|
||||
update behavior. The release does not qualify every starting firmware or
|
||||
bootloader migration path.
|
||||
Firmware source: [03214a16](https://github.com/mikecarper/MeshCore/commit/03214a16df2bd09d3272dfb001d2d322c6740f60).
|
||||
@@ -2,9 +2,10 @@
|
||||
<p class="meshcore-hosted-doc-link"><a href="https://mikecarper.github.io/MeshCore/role_feature_switches/">View this page on MeshCore Docs</a>.</p>
|
||||
<!-- meshcore-hosted-doc-link:end -->
|
||||
|
||||
# Feature switches by role - 1.17.1.5 USA Cascade
|
||||
# Feature controls by role
|
||||
|
||||
Use these settings with the exact board's canonical release image. Former
|
||||
Use these settings with the exact board's image from the
|
||||
[current release](releases/1.18.0.1.md). Former
|
||||
logging, power-saving, FEM-gain, and rotated-display variants are now runtime
|
||||
choices where the hardware supports them. A setting cannot add missing radio
|
||||
hardware, MQTT code, storage, or an OTA partition. Check the download's
|
||||
|
||||
+4
-4
@@ -104,12 +104,12 @@ nav:
|
||||
- docs.md
|
||||
- Research: research/index.md
|
||||
- Releases:
|
||||
- Current release:
|
||||
- 1.18.0.1 USA Cascade: releases/1.18.0.1.md
|
||||
- Current - 1.18.0.1 USA Cascade: releases/1.18.0.1.md
|
||||
- Previous releases:
|
||||
- 1.17.1.9 USA Cascade: releases/1.17.1.9.md
|
||||
- 1.17.1.8 USA Cascade: releases/1.17.1.8.md
|
||||
- Test Results: test-results/index.md
|
||||
- Old Releases: old-releases/index.md
|
||||
- Older releases: old-releases/index.md
|
||||
- Test Results: test-results/index.md
|
||||
|
||||
theme:
|
||||
name: material
|
||||
|
||||
@@ -345,6 +345,65 @@ def category(record):
|
||||
return "repeater-room"
|
||||
|
||||
|
||||
def joined_labels(values, conjunction="and"):
|
||||
if len(values) < 2:
|
||||
return "".join(values)
|
||||
return ", ".join(values[:-1]) + " " + conjunction + " " + values[-1]
|
||||
|
||||
|
||||
def release_group_description(name, records, extras=()):
|
||||
"""Describe actual page contents without assuming every matrix is current."""
|
||||
manifests = [record["manifest"] for record in records]
|
||||
platforms = {manifest["platform"] for manifest in manifests}
|
||||
platform = ({"NRF52_PLATFORM": "nRF52", "ESP32_PLATFORM": "ESP32"}
|
||||
.get(next(iter(platforms)), "") if len(platforms) == 1 else "")
|
||||
role_names = []
|
||||
for pattern, label in ((r"_repeater(?:[_-]|$)", "Repeater"),
|
||||
(r"_room_(?:server|svr)(?:[_-]|$)", "Room Server"),
|
||||
(r"_sensor(?:[_-]|$)", "Sensor"),
|
||||
(r"_terminal(?:[_-]|$)", "Terminal")):
|
||||
if any(re.search(pattern, manifest["target"], re.I) for manifest in manifests):
|
||||
role_names.append(label)
|
||||
roles = joined_labels(role_names) or "Radio"
|
||||
operating_roles = joined_labels(["a " + role.lower() for role in role_names], "or")
|
||||
radio = ("an " if platform == "ESP32" else "a ") + platform + " radio" if platform else "a radio"
|
||||
if platform == "nRF52":
|
||||
radio = "an nRF52 radio"
|
||||
if name == "companion":
|
||||
return "Companion firmware", "Connect a radio to a phone or computer using the Companion mode supported by its hardware."
|
||||
if name == "lora-ota":
|
||||
lora = bool(manifests) and all("lora" in manifest.get("ota_update_methods", []) for manifest in manifests)
|
||||
title = platform + " " + roles + " firmware" if platform else (
|
||||
"LoRa OTA firmware" if lora else "Wireless update firmware")
|
||||
purpose = ("Run " + radio + " as " + operating_roles if operating_roles
|
||||
else "Firmware for your exact radio")
|
||||
return title, purpose + (" with LoRa OTA reception." if lora else " with wireless updates.")
|
||||
if name == "full-profiles":
|
||||
title = (platform + " " if platform else "Full ") + roles + " firmware"
|
||||
return title, ("Full firmware for " + radio + " running as " + operating_roles + "." if operating_roles
|
||||
else "Choose the Full firmware for your exact radio and role.")
|
||||
if name == "logging":
|
||||
return "USB packet logging firmware", "Use these images when the chosen radio role needs USB packet logging."
|
||||
if name == "utility":
|
||||
names = [path.name.lower() for path in extras]
|
||||
migration = any(filename.endswith("-migration.zip") or filename.startswith("esp32-partition-migration-")
|
||||
for filename in names)
|
||||
bootloader = any("bootloader" in filename for filename in names)
|
||||
tools = joined_labels((["migration"] if migration else []) + (["bootloader"] if bootloader else []))
|
||||
if records:
|
||||
title = roles + " firmware" + (" and upgrade tools" if extras else "")
|
||||
return title, "Applications for " + (operating_roles or "your radio") + (
|
||||
", plus exact-board " + (tools or "upgrade") + " tools." if extras else ".")
|
||||
return (tools.capitalize() if tools else "Upgrade") + " tools", (
|
||||
"Use the exact board/role migration package or board/storage bootloader file for an update or recovery."
|
||||
if migration and bootloader else
|
||||
"Use the exact board and role package to migrate an ESP32 partition layout." if migration else
|
||||
"Use the exact board/storage bootloader file for an update or recovery." if bootloader else
|
||||
"Use the exact hardware package and follow its included instructions.")
|
||||
return roles + " firmware", ("Run " + radio + " as " + operating_roles + "." if operating_roles
|
||||
else "Firmware for the exact radio hardware and role selected in the picker.")
|
||||
|
||||
|
||||
def sha256(path):
|
||||
digest = hashlib.sha256()
|
||||
with path.open("rb") as stream:
|
||||
@@ -554,10 +613,8 @@ def main():
|
||||
raise ValueError("staging directory must be empty; existing releases are never overwritten")
|
||||
base_tag = version
|
||||
groups = []
|
||||
titles = {"companion": "Companion builds", "repeater-room": "Repeater and Room Server builds",
|
||||
"utility": "Sensor and Terminal utilities", "logging": "USB packet logging builds",
|
||||
"lora-ota": "LoRa OTA builds", "full-profiles": "Expanded FULL ESP32 profiles"}
|
||||
for name in titles:
|
||||
descriptions = {}
|
||||
for name in ("companion", "repeater-room", "utility", "logging", "lora-ota", "full-profiles"):
|
||||
current = []
|
||||
count = 0
|
||||
chunks = []
|
||||
@@ -572,16 +629,25 @@ def main():
|
||||
for index, chunk in enumerate(chunks):
|
||||
key = name + (f"-{index + 1}" if index else "")
|
||||
tag = base_tag if key == "companion" else f"{key}-{base_tag}"
|
||||
title = f"MeshCore {args.version}{'' if args.stable else ' Dev'} - {titles[name]}"
|
||||
if index:
|
||||
title += f" (part {index + 1})"
|
||||
label, purpose = release_group_description(name, chunk, extras if key == "utility" else [])
|
||||
if len(chunks) > 1:
|
||||
label += f" (part {index + 1} of {len(chunks)})"
|
||||
title = f"MeshCore {args.version}{'' if args.stable else ' Dev'} - {label}"
|
||||
descriptions[key] = {"label": label, "purpose": purpose, "parts": len(chunks)}
|
||||
groups.append({"key": key, "tag": tag, "title": title, "prerelease": not args.stable, "records": chunk})
|
||||
if extras and not any(g['key'] == 'utility' for g in groups):
|
||||
label, purpose = release_group_description("utility", [], extras)
|
||||
groups.append({'key': 'utility', 'tag': 'utility-' + base_tag,
|
||||
'title': f'MeshCore {args.version} - Migration utilities',
|
||||
'title': f'MeshCore {args.version}{"" if args.stable else " Dev"} - {label}',
|
||||
'prerelease': not args.stable, 'records': []})
|
||||
links = "\n".join(f"- [{g['key']}](https://github.com/{args.repo}/releases/tag/{g['tag']})" for g in groups)
|
||||
descriptions["utility"] = {"label": label, "purpose": purpose, "parts": 1}
|
||||
links = "\n".join(f"- [{descriptions[g['key']]['label']}](https://github.com/{args.repo}/releases/tag/{g['tag']})"
|
||||
for g in groups)
|
||||
source_url = f"https://github.com/{args.repo}/blob/{args.commit}"
|
||||
owner, repository = args.repo.split("/", 1)
|
||||
docs_url = f"https://{owner}.github.io/" + ("" if repository.lower() == owner.lower() + ".github.io"
|
||||
else quote(repository, safe="") + "/")
|
||||
release_guide = docs_url + f"releases/{args.version}/"
|
||||
rows = []
|
||||
for group in groups:
|
||||
destination = args.output / group["key"]
|
||||
@@ -656,15 +722,26 @@ def main():
|
||||
partial_note = (f"**Partial matrix:** {len(failures)} build attempt(s) failed and await repair. "
|
||||
f"Only individually qualified firmware is published. [Missing builds]({report_url}).\n\n")
|
||||
channel = 'Stable release' if args.stable else 'Development prerelease'
|
||||
body = (f"> **{channel}.** Firmware identifier: **{base_tag}**.\n\n"
|
||||
f"# MeshCore {args.version} - USA Cascade\n\n"
|
||||
f"Source: `{args.commit}`. USA/Canada: **{radio['frequency']} MHz, BW{radio['bandwidth']}, SF{radio['sf']}, CR{radio['cr']}**; Cascade defaults.\n\n"
|
||||
f"This page contains **{len(summaries)} qualified firmware profiles**. Full Companions send MOTA and normally update over USB. Infrastructure has a verified wireless update path; see each capability manifest.\n\n"
|
||||
f"[Feature on/off and update directions]({source_url}/docs/full_companion_features.md) | "
|
||||
f"[Release details]({source_url}/docs/releases/{args.version}.md)\n\n"
|
||||
"Match the exact board, radio, display, and storage variant. ESP32 WiFi updates use the application `.bin`; the merged image installs boot/partition data over USB. nRF52 firmware `.zip` files are native application DFU packages. Separate `with-bootloader-2.4.12` firmware embeds its exact-board OTAFIX image and checks it for installation after 70 seconds; ordinary firmware preserves the installed bootloader. Standalone bootloader downloads are separate utilities. LoRa MOTA installation requires an exact destination package and matching bootloader. Full Companions do not LoRa-install onto themselves.\n\n"
|
||||
"Firmware and capability checks passed in the build matrix. Hardware update testing across every board was not performed.\n\n"
|
||||
+ partial_note + portable_note + links + "\n")
|
||||
description = descriptions[group["key"]]
|
||||
split_note = ("These pages are split for download limits and contain the same firmware version; "
|
||||
"the picker finds the correct page for your board.\n\n" if description["parts"] > 1 else "")
|
||||
body = (f"[Open the firmware picker]({docs_url}firmware_picker/) | "
|
||||
f"[What's new in {args.version}]({release_guide})\n\n"
|
||||
f"# {group['title']}\n\n"
|
||||
f"> **{channel}.** USA Cascade.\n\n"
|
||||
+ description["purpose"] + "\n\n"
|
||||
"Select the exact board, radio, storage and role in the picker.\n\n"
|
||||
+ split_note + partial_note + portable_note
|
||||
+ f"[Installation and upgrade guide]({release_guide}) | "
|
||||
f"[Feature controls]({docs_url}role_feature_switches/) | "
|
||||
f"[Full Companion guide]({docs_url}full_companion_features/)\n\n"
|
||||
"**Testing:** Published images passed build, capability and memory checks. "
|
||||
"Physical coverage varies by board and update route; "
|
||||
f"see the [release guide]({release_guide}).\n\n"
|
||||
"Other firmware and tools:\n\n" + links + "\n\n"
|
||||
f"USA Cascade defaults: **{radio['frequency']} MHz, BW{radio['bandwidth']}, "
|
||||
f"SF{radio['sf']}, CR{radio['cr']}**. Saved radio settings take precedence.\n\n"
|
||||
f"Firmware identifier: `{base_tag}`. Source: `{args.commit}`.\n")
|
||||
(args.output / (group["key"] + "-notes.md")).write_text(body)
|
||||
(destination / "BUILD-NOTES.txt").write_text(body)
|
||||
picker = ("<!doctype html><meta charset=utf-8><meta name=viewport content='width=device-width'>"
|
||||
|
||||
@@ -326,6 +326,111 @@ class ReleasePublicationTest(unittest.TestCase):
|
||||
self.assertRaisesRegex(ValueError, "another source"):
|
||||
package.main()
|
||||
|
||||
def test_page_descriptions_follow_actual_platforms_roles_and_tool_types(self):
|
||||
def record(target, platform="ESP32_PLATFORM", methods=("lora",)):
|
||||
return {"manifest": {"target": target, "platform": platform,
|
||||
"ota_update_methods": list(methods)}}
|
||||
|
||||
nrf = [record("sample_repeater_lora_ota", "NRF52_PLATFORM"),
|
||||
record("sample_room_server_lora_ota", "NRF52_PLATFORM"),
|
||||
record("sample_sensor_lora_ota", "NRF52_PLATFORM")]
|
||||
label, purpose = package.release_group_description("lora-ota", nrf)
|
||||
self.assertEqual(label, "nRF52 Repeater, Room Server and Sensor firmware")
|
||||
self.assertIn("LoRa OTA reception", purpose)
|
||||
# Historical matrices also had ESP32 and mixed-platform LoRa pages.
|
||||
esp = [record("legacy_repeater_lora_ota")]
|
||||
self.assertEqual(package.release_group_description("lora-ota", esp)[0], "ESP32 Repeater firmware")
|
||||
self.assertEqual(package.release_group_description("lora-ota", esp + nrf)[0], "LoRa OTA firmware")
|
||||
self.assertNotIn("LoRa", package.release_group_description("lora-ota", [
|
||||
record("legacy_repeater_lora_ota", methods=("wifi",))])[1])
|
||||
full = [record("sample_repeater"), record("sample_room_server"), record("sample_sensor")]
|
||||
self.assertEqual(package.release_group_description("full-profiles", full)[0],
|
||||
"ESP32 Repeater, Room Server and Sensor firmware")
|
||||
for files, title in (([Path("board-migration.zip")], "Migration tools"),
|
||||
([Path("board_bootloader.hex")], "Bootloader tools"),
|
||||
([Path("board-migration.zip"), Path("board_bootloader.hex")],
|
||||
"Migration and bootloader tools")):
|
||||
with self.subTest(title=title):
|
||||
self.assertEqual(package.release_group_description("utility", [], files)[0], title)
|
||||
utility = [record("sample_sensor"), record("sample_terminal_chat")]
|
||||
self.assertEqual(package.release_group_description("utility", utility)[0], "Sensor and Terminal firmware")
|
||||
self.assertEqual(package.release_group_description("utility", utility, [Path("board-migration.zip")])[0],
|
||||
"Sensor and Terminal firmware and upgrade tools")
|
||||
|
||||
def test_staged_notes_lead_with_picker_and_link_human_role_choices(self):
|
||||
with tempfile.TemporaryDirectory() as temp:
|
||||
base = Path(temp)
|
||||
companion, companion_files = self.record(base / "input", "Station_G2_companion_radio_full")
|
||||
repeater, repeater_files = self.record(base / "input", "Station_G2_repeater", build_profile="full")
|
||||
records = [{"manifest": companion, "files": companion_files},
|
||||
{"manifest": repeater, "files": repeater_files}]
|
||||
extras = [base / "board-migration.zip", base / "board_bootloader.hex"]
|
||||
for path in extras:
|
||||
path.write_bytes(b"exact-board tool fixture\n")
|
||||
before = {path: path.read_bytes() for path in companion_files + repeater_files + extras}
|
||||
output = base / "stage"
|
||||
argv = ["package", "--input", str(base / "input"), "--output", str(output),
|
||||
"--local-release", "--stable", "--version", "1.17.1.9", "--commit", SOURCE]
|
||||
with patch.object(sys, "argv", argv), patch.object(package, "collect_local_release",
|
||||
return_value=(records, extras,
|
||||
{"frequency": "910.525", "bandwidth": "62.5", "sf": "7", "cr": "5"})):
|
||||
package.main()
|
||||
plan = json.loads((output / "release-plan.json").read_text())
|
||||
self.assertEqual([group["key"] for group in plan["groups"]], ["companion", "full-profiles", "utility"])
|
||||
guide = "https://mikecarper.github.io/MeshCore/releases/1.17.1.9/"
|
||||
for group in plan["groups"]:
|
||||
notes = (output / (group["key"] + "-notes.md")).read_text(encoding="ascii")
|
||||
self.assertTrue(notes.startswith("[Open the firmware picker](https://mikecarper.github.io/MeshCore/firmware_picker/)"))
|
||||
self.assertIn("[What's new in 1.17.1.9](" + guide + ")", notes)
|
||||
self.assertIn("[Installation and upgrade guide](" + guide + ")", notes)
|
||||
self.assertIn("[Companion firmware](https://github.com/mikecarper/MeshCore/releases/tag/" + FAMILY + ")", notes)
|
||||
self.assertIn("[ESP32 Repeater firmware](https://github.com/mikecarper/MeshCore/releases/tag/full-profiles-" + FAMILY + ")", notes)
|
||||
self.assertIn("[Migration and bootloader tools](https://github.com/mikecarper/MeshCore/releases/tag/utility-" + FAMILY + ")", notes)
|
||||
self.assertNotIn("[full-profiles]", notes)
|
||||
self.assertNotIn("qualified firmware profiles", notes)
|
||||
self.assertIn("**Testing:**", notes)
|
||||
self.assertIn("Physical coverage varies by board and update route", notes)
|
||||
self.assertIn("Saved radio settings take precedence", notes)
|
||||
self.assertIn(SOURCE, notes)
|
||||
self.assertIn(FAMILY, notes)
|
||||
self.assertEqual((output / group["key"] / "BUILD-NOTES.txt").read_text(), notes)
|
||||
for line in (output / group["key"] / "SHA256SUMS.txt").read_text().splitlines():
|
||||
expected, name = line.split(" ", 1)
|
||||
self.assertEqual(hashlib.sha256((output / group["key"] / name).read_bytes()).hexdigest(), expected)
|
||||
self.assertEqual({path: path.read_bytes() for path in before}, before)
|
||||
|
||||
def test_split_pages_keep_tags_and_explain_one_version_with_human_links(self):
|
||||
with tempfile.TemporaryDirectory() as temp:
|
||||
base = Path(temp)
|
||||
records = []
|
||||
for index in range(3):
|
||||
target = f"board_{index}_repeater_lora_ota"
|
||||
row, files = self.record(base / "input", target, platform="NRF52_PLATFORM")
|
||||
# Exercise the real 900-file split with many tiny report assets.
|
||||
for number in range(447):
|
||||
path = base / "input" / f"{target}-report-{number}.txt"
|
||||
path.write_bytes(b"qualification report fixture\n")
|
||||
files.append(path)
|
||||
self.assertEqual(len(files), 451)
|
||||
records.append({"manifest": row, "files": files})
|
||||
output = base / "stage"
|
||||
argv = ["package", "--input", str(base / "input"), "--output", str(output),
|
||||
"--local-release", "--stable", "--version", "1.17.1.9", "--commit", SOURCE]
|
||||
with patch.object(sys, "argv", argv), patch.object(package, "collect_local_release",
|
||||
return_value=(records, [],
|
||||
{"frequency": "910.525", "bandwidth": "62.5", "sf": "7", "cr": "5"})):
|
||||
package.main()
|
||||
plan = json.loads((output / "release-plan.json").read_text())
|
||||
self.assertEqual([group["key"] for group in plan["groups"]], ["lora-ota", "lora-ota-2", "lora-ota-3"])
|
||||
for number, group in enumerate(plan["groups"], 1):
|
||||
self.assertEqual(group["tag"], group["key"] + "-" + FAMILY)
|
||||
self.assertEqual(group["title"], f"MeshCore 1.17.1.9 - nRF52 Repeater firmware (part {number} of 3)")
|
||||
notes = (output / (group["key"] + "-notes.md")).read_text(encoding="ascii")
|
||||
self.assertIn("split for download limits and contain the same firmware version", notes)
|
||||
for other in range(1, 4):
|
||||
self.assertIn(f"[nRF52 Repeater firmware (part {other} of 3)]", notes)
|
||||
self.assertEqual(group["asset_count"], 457)
|
||||
|
||||
def test_local_release_preserves_selected_profiles_and_verifies_complete_inventory(self):
|
||||
with tempfile.TemporaryDirectory() as temp:
|
||||
directory = Path(temp)
|
||||
|
||||
Reference in new issue
Block a user