Add portable LoRa OTA repeater builds

This commit is contained in:
mikecarper committed 2026-07-22 10:05:52 -07:00
1 parent 371d86c4b1
commit 7abb5fb95b
7 files changed
+1323 -1169

No files matched your search

+170 -24
View File
@@ -5,6 +5,7 @@ SUPPORTED_PIO_ENVS=()
declare -A PIO_ENV_PLATFORM_BY_NAME=()
declare -A PIO_ENV_MQTT_BY_NAME=()
declare -A PIO_ENV_OTA_BY_NAME=()
declare -A PIO_ENV_BUILD_BASE_BY_NAME=()
PIO_CONFIG_JSON=""
MENU_CHOICE=""
SELECTED_TARGET=""
@@ -31,7 +32,7 @@ PARSED_COMMAND_ARGS=()
FIRMWARE_VERSION_EXPLICIT=0
OUTPUT_POLICY_EXPLICIT=0
ENV_VARIANT_SUFFIX_PATTERN='companion_radio_(wifi_mqtt|serial|wifi|usb|ble)(_ps)?(_fem(on|off))?|companion_radio_ethernet|comp_radio_usb|companion_usb|companion_ble|repeater_bridge_rs232_serial1_lora_ota_no_external_sensors|repeater_bridge_rs232_serial2_lora_ota_no_external_sensors|repeater_bridge_rs232_lora_ota_no_external_sensors|room_server_lora_ota_no_external_sensors|repeater_lora_ota_no_external_sensors|repeater_bridge_rs232_serial1|repeater_bridge_rs232_serial2|repeater_bridge_rs232|repeater_bridge_espnow|repeater_observer_mqtt|repeater_ethernet|room_server_observer_mqtt|room_server_ethernet|terminal_chat|room_server|room_svr|kiss_modem|sensor|repeatr|repeater'
ENV_VARIANT_SUFFIX_PATTERN='companion_radio_(wifi_mqtt|serial|wifi|usb|ble)(_ps)?(_fem(on|off))?|companion_radio_ethernet|comp_radio_usb|companion_usb|companion_ble|repeater_bridge_rs232_serial1_lora_ota_no_external_sensors|repeater_bridge_rs232_serial2_lora_ota_no_external_sensors|repeater_bridge_rs232_lora_ota_no_external_sensors|repeater_lora_ota_no_external_sensors|repeater_bridge_rs232_serial1|repeater_bridge_rs232_serial2|repeater_bridge_rs232|repeater_bridge_espnow|repeater_observer_mqtt|repeater_ethernet|room_server_observer_mqtt|room_server_ethernet|terminal_chat|room_server|room_svr|kiss_modem|sensor|repeatr|repeater'
BOARD_MODIFIER_WITHOUT_DISPLAY="_without_display"
BOARD_MODIFIER_LOGGING="_logging"
BOARD_MODIFIER_TFT="_tft"
@@ -49,6 +50,7 @@ TAG_PREFIX_REPEATER="repeater"
TAG_PREFIX_SENSOR="sensor"
SUPPORTED_PLATFORM_PATTERN='ESP32_PLATFORM|NRF52_PLATFORM|STM32_PLATFORM|RP2040_PLATFORM'
OUTPUT_DIR="out"
ESP32_LORA_OTA_APP_LIMIT=$((0x150000 - 0x10000))
FALLBACK_VERSION_PREFIX="dev"
FALLBACK_VERSION_DATE_FORMAT='+%Y-%m-%d-%H-%M'
@@ -183,6 +185,35 @@ for section, options in data:
print(f"{env_name}\t{platform}\t{1 if mqtt_enabled else 0}\t{1 if ota_enabled and not ota_disabled else 0}")
' "$SUPPORTED_PLATFORM_PATTERN" <<<"$PIO_CONFIG_JSON"
)
# Keep each ordinary repeater environment feature-rich (including external
# sensors), and expose a separately named no-external-sensors OTA build for
# every ESP32/nRF52 repeater role. These two platforms have a complete apply
# path; RP2040 and STM32 do not yet have the required bootloader/apply path.
local env_name ota_env
local -a base_envs=("${SUPPORTED_PIO_ENVS[@]}")
for env_name in "${base_envs[@]}"; do
case "${PIO_ENV_PLATFORM_BY_NAME[$env_name]}" in
ESP32_PLATFORM|NRF52_PLATFORM) ;;
*) continue ;;
esac
# Generate one lean LoRa-OTA image for each board's standalone repeater
# role. Observer, Ethernet, and bridge profiles are separate roles; any
# purpose-built OTA versions of those remain explicit PlatformIO targets.
case "${env_name,,}" in
*_repeater|*_repeater_|*_repeatr|*_repeatr_) ;;
*) continue ;;
esac
ota_env="${env_name%_}_lora_ota_no_external_sensors"
if [ -n "${PIO_ENV_PLATFORM_BY_NAME[$ota_env]+x}" ]; then
continue
fi
SUPPORTED_PIO_ENVS+=("$ota_env")
PIO_ENV_PLATFORM_BY_NAME["$ota_env"]="${PIO_ENV_PLATFORM_BY_NAME[$env_name]}"
PIO_ENV_MQTT_BY_NAME["$ota_env"]=0
PIO_ENV_OTA_BY_NAME["$ota_env"]=1
PIO_ENV_BUILD_BASE_BY_NAME["$ota_env"]="$env_name"
done
fi
}
@@ -1371,6 +1402,13 @@ is_known_pio_env() {
local env_name=$1
local env
# Synthetic LoRa-OTA environments build their recorded base PlatformIO
# environment with a constrained flag profile, so they intentionally do not
# appear in `pio project config`.
if [ -n "${PIO_ENV_BUILD_BASE_BY_NAME[$env_name]+x}" ]; then
return 0
fi
for env in "${ALL_PIO_ENVS[@]}"; do
if [ "$env" == "$env_name" ]; then
return 0
@@ -1386,6 +1424,11 @@ is_supported_build_env() {
[ -n "${PIO_ENV_PLATFORM_BY_NAME[$env_name]+x}" ]
}
get_pio_build_env() {
local env_name=$1
echo "${PIO_ENV_BUILD_BASE_BY_NAME[$env_name]:-$env_name}"
}
is_mqtt_bridge_target() {
[ "${PIO_ENV_MQTT_BY_NAME[$1]:-0}" == "1" ]
}
@@ -1527,8 +1570,14 @@ is_lora_ota_build() {
return 1
fi
if [[ "$env_name_lc" == *mqtt* ]] \
|| is_mqtt_bridge_target "$env_name" \
# OTA is deliberately opt-in. The standard repeater remains a normal,
# sensor-enabled build; its explicit _lora_ota_no_external_sensors sibling
# is the constrained image distributed over LoRa.
if [[ "$env_name_lc" != *lora_ota_no_external_sensors ]]; then
return 1
fi
if is_mqtt_bridge_target "$env_name" \
|| [ "${MQTT_BRIDGE_OVERRIDE,,}" == "on" ] \
|| [ "${MESHDEBUG_OVERRIDE,,}" == "on" ] \
|| [ "${PACKET_LOGGING_OVERRIDE,,}" == "on" ] \
@@ -1545,12 +1594,81 @@ is_lora_ota_build() {
esac
}
is_esp32_companion_build() {
case "${1,,}" in
*companion*|*comp_radio*) return 0 ;;
*) return 1 ;;
esac
}
requires_esp32_portable_app_slot() {
[ "${PIO_ENV_PLATFORM_BY_NAME[$1]:-}" = "ESP32_PLATFORM" ] \
&& ! is_esp32_companion_build "$1"
}
apply_esp32_lora_ota_size_profile() {
local env_name=$1
if ! requires_esp32_portable_app_slot "$env_name"; then
return 0
fi
# All non-companion ESP32 artifacts must remain installable into the legacy
# 0x10000..0x150000 app slot. The WebConfig portal is deliberately omitted.
# WiFi/MQTT observers retain their small WiFi updater, while radio-only roles
# avoid linking WiFi solely for that updater. Companions retain their target
# defaults because they are installed over USB.
export PLATFORMIO_BUILD_FLAGS="${PLATFORMIO_BUILD_FLAGS} -DWEBCONFIG_DISABLED=1"
if is_mqtt_bridge_target "$env_name"; then
export PLATFORMIO_BUILD_FLAGS="${PLATFORMIO_BUILD_FLAGS} -DLIGHTWEIGHT_WIFI_OTA=1"
else
append_platformio_build_unflags "-DLIGHTWEIGHT_WIFI_OTA=1"
export PLATFORMIO_BUILD_FLAGS="${PLATFORMIO_BUILD_FLAGS} -ULIGHTWEIGHT_WIFI_OTA -DDISABLE_WIFI_OTA=1"
fi
}
apply_lora_ota_no_external_sensors_profile() {
local env_name=$1
if ! is_lora_ota_build "$env_name"; then
return 0
fi
# The explicit LoRa-OTA sibling additionally drops optional external sensors.
# Its ordinary sibling remains sensor-enabled.
# Keep board-integrated GPS support. Several target implementations require
# their location provider even when optional external I2C sensors are absent.
append_platformio_build_unflags "-DENV_INCLUDE_AHTX0=1 -DENV_INCLUDE_BME280=1 -DENV_INCLUDE_BMP280=1 -DENV_INCLUDE_SHTC3=1 -DENV_INCLUDE_SHT4X=1 -DENV_INCLUDE_LPS22HB=1 -DENV_INCLUDE_INA3221=1 -DENV_INCLUDE_INA219=1 -DENV_INCLUDE_INA226=1 -DENV_INCLUDE_INA260=1 -DENV_INCLUDE_MLX90614=1 -DENV_INCLUDE_VL53L0X=1 -DENV_INCLUDE_BME680=1 -DENV_INCLUDE_BMP085=1 -DENV_INCLUDE_RAK12035=1 -DENV_INCLUDE_BME680_BSEC=1"
export PLATFORMIO_BUILD_FLAGS="${PLATFORMIO_BUILD_FLAGS} -UENV_INCLUDE_AHTX0 -UENV_INCLUDE_BME280 -UENV_INCLUDE_BMP280 -UENV_INCLUDE_SHTC3 -UENV_INCLUDE_SHT4X -UENV_INCLUDE_LPS22HB -UENV_INCLUDE_INA3221 -UENV_INCLUDE_INA219 -UENV_INCLUDE_INA226 -UENV_INCLUDE_INA260 -UENV_INCLUDE_MLX90614 -UENV_INCLUDE_VL53L0X -UENV_INCLUDE_BME680 -UENV_INCLUDE_BMP085 -UENV_INCLUDE_RAK12035 -UENV_INCLUDE_BME680_BSEC"
}
append_platformio_build_unflags() {
local flags=$1
local flag
local entry
for flag in $flags; do
case "$flag" in
-D*) entry="-D ${flag#-D}" ;;
*) entry="$flag" ;;
esac
if [ -n "${PLATFORMIO_BUILD_UNFLAGS:-}" ]; then
PLATFORMIO_BUILD_UNFLAGS+=$'\n'
fi
PLATFORMIO_BUILD_UNFLAGS+="$entry"
done
export PLATFORMIO_BUILD_UNFLAGS
}
apply_lora_ota_override() {
local env_name=$1
if is_lora_ota_build "$env_name"; then
export PLATFORMIO_BUILD_FLAGS="${PLATFORMIO_BUILD_FLAGS} -DENABLE_OTA=1"
append_platformio_build_unflags "-UENABLE_OTA -DDISABLE_LORA_OTA=1"
export PLATFORMIO_BUILD_FLAGS="${PLATFORMIO_BUILD_FLAGS} -UDISABLE_LORA_OTA -DENABLE_OTA=1 -DOTA_FLASH_STORE=1 -DOTA_FOLDER_SERIAL"
else
append_platformio_build_unflags "-DENABLE_OTA=1"
export PLATFORMIO_BUILD_FLAGS="${PLATFORMIO_BUILD_FLAGS} -UENABLE_OTA"
fi
}
@@ -1596,6 +1714,7 @@ for section, options in data:
break
env_flags = shlex.split(os.environ.get("PLATFORMIO_BUILD_FLAGS", ""))
env_unflags = os.environ.get("PLATFORMIO_BUILD_UNFLAGS", "").splitlines()
def print_flags(title, flags):
print(f" {title}:")
@@ -1607,6 +1726,7 @@ def print_flags(title, flags):
print_flags("platformio.ini build_flags", config_flags)
print_flags("PLATFORMIO_BUILD_FLAGS", env_flags)
print_flags("PLATFORMIO_BUILD_UNFLAGS", env_unflags)
' "$env_name" <<<"$PIO_CONFIG_JSON"
}
@@ -1624,32 +1744,40 @@ copy_build_output() {
collect_esp32_artifacts() {
local env_name=$1
local firmware_filename=$2
local pio_env_name=$2
local firmware_filename=$3
local -a size_check_args=(
".pio/build/${pio_env_name}/firmware.bin"
".pio/build/${pio_env_name}/partitions.bin"
)
python3 scripts/check_esp32_app_size.py \
".pio/build/${env_name}/firmware.bin" \
".pio/build/${env_name}/partitions.bin" || return $?
pio run -t mergebin -e "$env_name" || return $?
copy_build_output ".pio/build/${env_name}/firmware.bin" "${OUTPUT_DIR}/${firmware_filename}.bin" || return $?
copy_build_output ".pio/build/${env_name}/firmware-merged.bin" "${OUTPUT_DIR}/${firmware_filename}-merged.bin" || return $?
if requires_esp32_portable_app_slot "$env_name"; then
size_check_args+=("$ESP32_LORA_OTA_APP_LIMIT")
fi
python3 scripts/check_esp32_app_size.py "${size_check_args[@]}" || return $?
pio run -t mergebin -e "$pio_env_name" || return $?
copy_build_output ".pio/build/${pio_env_name}/firmware.bin" "${OUTPUT_DIR}/${firmware_filename}.bin" || return $?
copy_build_output ".pio/build/${pio_env_name}/firmware-merged.bin" "${OUTPUT_DIR}/${firmware_filename}-merged.bin" || return $?
# Emit the partition-table signature for OTA partition-compatibility checks.
# Keyed by env name so the slim-manifest generator can find it; the firmware
# computes the same signature at runtime from its flashed table. Best-effort:
# local builds without the script's deps just skip it.
if [ -f ".pio/build/${env_name}/partitions.bin" ]; then
python3 scripts/partition_signature.py ".pio/build/${env_name}/partitions.bin" > "${OUTPUT_DIR}/${env_name}.partsig" 2>/dev/null || true
if [ -f ".pio/build/${pio_env_name}/partitions.bin" ]; then
python3 scripts/partition_signature.py ".pio/build/${pio_env_name}/partitions.bin" > "${OUTPUT_DIR}/${env_name}.partsig" 2>/dev/null || true
fi
}
collect_nrf52_artifacts() {
local env_name=$1
local firmware_filename=$2
local pio_env_name=$2
local firmware_filename=$3
python3 bin/uf2conv/uf2conv.py ".pio/build/${env_name}/firmware.hex" -c -o ".pio/build/${env_name}/firmware.uf2" -f 0xADA52840 || return $?
copy_build_output ".pio/build/${env_name}/firmware.uf2" "${OUTPUT_DIR}/${firmware_filename}.uf2" || return $?
if [ -f ".pio/build/${env_name}/firmware.zip" ]; then
copy_build_output ".pio/build/${env_name}/firmware.zip" "${OUTPUT_DIR}/${firmware_filename}.zip" || return $?
python3 bin/uf2conv/uf2conv.py ".pio/build/${pio_env_name}/firmware.hex" -c -o ".pio/build/${pio_env_name}/firmware.uf2" -f 0xADA52840 || return $?
copy_build_output ".pio/build/${pio_env_name}/firmware.uf2" "${OUTPUT_DIR}/${firmware_filename}.uf2" || return $?
if [ -f ".pio/build/${pio_env_name}/firmware.zip" ]; then
copy_build_output ".pio/build/${pio_env_name}/firmware.zip" "${OUTPUT_DIR}/${firmware_filename}.zip" || return $?
fi
}
@@ -1702,16 +1830,17 @@ build_artifacts_exist() {
collect_build_artifacts() {
local env_name=$1
local env_platform=$2
local firmware_filename=$3
local pio_env_name=$3
local firmware_filename=$4
# Post-build outputs differ by platform, so dispatch to the matching
# collector after the main firmware build succeeds.
case "$env_platform" in
ESP32_PLATFORM)
collect_esp32_artifacts "$env_name" "$firmware_filename"
collect_esp32_artifacts "$env_name" "$pio_env_name" "$firmware_filename"
;;
NRF52_PLATFORM)
collect_nrf52_artifacts "$env_name" "$firmware_filename"
collect_nrf52_artifacts "$env_name" "$pio_env_name" "$firmware_filename"
;;
STM32_PLATFORM)
collect_stm32_artifacts "$env_name" "$firmware_filename"
@@ -1764,6 +1893,7 @@ restore_platformio_build_flags() {
build_firmware() {
local env_name=$1
local pio_env_name
local env_platform
local commit_hash
local firmware_build_date
@@ -1774,7 +1904,9 @@ build_firmware() {
local mota_target_id
local mota_target_flag=""
local original_platformio_build_flags
local original_platformio_build_unflags
local had_platformio_build_flags=0
local had_platformio_build_unflags=0
local build_status
env_platform=$(get_platform_for_env "$env_name")
@@ -1782,6 +1914,7 @@ build_firmware() {
echo "Unsupported or unknown platform for env: $env_name"
return 1
fi
pio_env_name=$(get_pio_build_env "$env_name")
commit_hash=$(git rev-parse --short HEAD)
firmware_build_date=$(date -u '+%d-%b-%Y')
@@ -1815,7 +1948,7 @@ build_firmware() {
# per-base published-build counter (FIRMWARE_BUILD_NUMBER) as a 4th version
# component so `ota check` can show how many builds behind a node is. The
# *filename* stays untagged/un-numbered so assets remain <env>-v<base>-<hash>.
# OTA_VARIANT is the env name — it selects the slim per-variant manifest
# OTA_VARIANT is the env name - it selects the slim per-variant manifest
# (<OTA_MANIFEST_BASE>/<OTA_VARIANT>.json) that the observer pull-OTA fetches.
local embedded_variant_tag=""
case "$env_name" in
@@ -1838,6 +1971,12 @@ build_firmware() {
else
original_platformio_build_flags=""
fi
if [ "${PLATFORMIO_BUILD_UNFLAGS+x}" ]; then
had_platformio_build_unflags=1
original_platformio_build_unflags=$PLATFORMIO_BUILD_UNFLAGS
else
original_platformio_build_unflags=""
fi
export PLATFORMIO_BUILD_FLAGS="${original_platformio_build_flags} -DFIRMWARE_BUILD_DATE='\"${firmware_build_date}\"' -DFIRMWARE_BUILD_EPOCH=${firmware_build_epoch} -DFIRMWARE_VERSION='\"${embedded_version_string}\"' -DOTA_VARIANT='\"${env_name}\"'${mota_target_flag}"
disable_debug_flags
@@ -1845,18 +1984,25 @@ build_firmware() {
apply_mqtt_bridge_override
disable_usb_logging_for_mqtt "$env_name"
apply_lora_ota_override "$env_name"
apply_esp32_lora_ota_size_profile "$env_name"
apply_lora_ota_no_external_sensors_profile "$env_name"
apply_radio_overrides
apply_firmware_profile_overrides
print_build_flags "$env_name"
pio run -e "$env_name"
pio run -e "$pio_env_name"
build_status=$?
if [ "$build_status" -eq 0 ]; then
collect_build_artifacts "$env_name" "$env_platform" "$firmware_filename"
collect_build_artifacts "$env_name" "$env_platform" "$pio_env_name" "$firmware_filename"
build_status=$?
fi
restore_platformio_build_flags "$had_platformio_build_flags" "$original_platformio_build_flags"
if [ "$had_platformio_build_unflags" -eq 1 ]; then
export PLATFORMIO_BUILD_UNFLAGS="$original_platformio_build_unflags"
else
unset PLATFORMIO_BUILD_UNFLAGS
fi
return "$build_status"
}
+10 -4
View File
@@ -38,15 +38,21 @@ location and change it when necessary.
Both paths require:
- An OTA-enabled repeater build whose artifact filename contains `-ota-` on the source, destination, and
every intermediate node. The `-ota-` stamp confirms that LoRa OTA is compiled into the build. Logging,
- An OTA-enabled repeater build whose artifact filename contains `-ota-` on the destination and every
intermediate repeater. The `-ota-` stamp confirms that LoRa OTA is compiled into the build. Logging,
MQTT, and untagged builds cannot perform LoRa OTA; use WiFi or USB to replace them first.
- A source node connected to the computer by USB serial.
- An ESP32 MeshCore companion connected to the computer by USB serial or WiFi as described below.
- Overlapping `tempradio` windows on the source, destination, and every repeater needed between them.
LoRa OTA packets are generated, received, and relayed only while `tempradio` is active. If any required
window closes, the transfer stops making progress and can resume during a later overlapping window.
`build.sh` provides a `*_repeater_lora_ota_no_external_sensors` build for every standalone ESP32 and nRF52
repeater target. The normal repeater build keeps its external-sensor support. The `-ota-` sibling omits
optional external I2C environmental sensors to preserve the update workspace, while retaining board-native
features such as its display, buttons, battery monitoring, and integrated GPS. RP2040 and STM32 repeaters do
not currently have a safe self-apply path and therefore cannot install LoRa firmware updates.
### Choose the source radio
Use an ESP32 **MeshCore companion** as the source node. It receives the update folder from the computer,
@@ -148,7 +154,7 @@ running application. The hash check in the next step proves that it is the right
On RAK4631 repeaters, use the
`RAK_4631_repeater_lora_ota_no_external_sensors` environment. It retains built-in battery monitoring but
omits optional external environmental/GPS sensor packages so the delta fits the safe in-place workspace.
omits optional external environmental sensor packages so the delta fits the safe in-place workspace.
### 3. Build and check the in-place delta
+8 -5
View File
@@ -90,8 +90,9 @@ EndF trailer (fixed 56 bytes):
off 24 32 hw_id NUL-padded ASCII hardware tag (brick-safety), e.g. "RAK4631" ("" = unknown)
```
- **Self-describing identity.** `pio_endf.py` computes `target_id` from the PlatformIO env name itself (so
it's correct even without `build.sh`'s `-D MOTA_TARGET_ID`), `hw_id` from `MOTA_HW_ID`, and `fw_version`
- **Self-describing identity.** `pio_endf.py` uses `build.sh`'s `MOTA_TARGET_ID` when present (required for
virtual LoRa-OTA build names), otherwise it computes `target_id` from the PlatformIO env name. It reads
`hw_id` from `MOTA_HW_ID` and `fw_version`
from `FIRMWARE_VERSION`. The device reads them back (`ota_self_firmware()`), so a node's advertised
identity is correct regardless of how it was built - and the packaging tool reads them straight from a raw
`.bin` (no `--target-env`/`--fw-version` flags, no reliance on filenames; Section 9, Section 13). A dev build with no
@@ -109,9 +110,11 @@ The "reconstructed image" referenced by the manifest is the full `BODY || EndF`
ESP32 companion firmware is installed over USB and is exempt from the portable-slot limit. Every other
ESP32 artifact, including room, sensor, and repeater roles, must fit the legacy slot from `0x10000` up to
`0x150000` (`0x140000`, 1,310,720 bytes), including the 56-byte `EndF` trailer. The build checks both that
limit and the target's actual app partition. For every ESP32 repeater, `build.sh` also exposes an explicit
`*_lora_ota_no_external_sensors` artifact: the ordinary repeater remains sensor-enabled, while that sibling
also disables optional external-sensor drivers for LoRa distribution.
limit and the target's actual app partition. For every standalone ESP32 and nRF52 repeater, `build.sh` also
exposes an explicit `*_lora_ota_no_external_sensors` artifact: the ordinary repeater remains sensor-enabled,
while that sibling disables optional external environmental-sensor drivers for LoRa distribution. Integrated
GPS and other board-native telemetry remain enabled. RP2040 and STM32 targets are not offered because those
platforms do not yet have a safe bootloader/apply path.
> **Implementer note:** the bootloader (and any non-Arduino consumer) MUST locate the body extent by
> scanning for `EndF`, never by trusting a stored size - see the bootloader contract in Section 12.
+25 -7
View File
@@ -1,5 +1,10 @@
#!/usr/bin/env python3
"""Fail when an ESP32 app image (including EndF) exceeds its app partition."""
"""Fail when an ESP32 app image (including EndF) exceeds its app partition.
An optional third argument additionally enforces a portable maximum image size.
MeshCore's LoRa-OTA ESP32 artifacts use 0x140000 bytes: the legacy app slot
starts at 0x10000 and the next OTA slot begins at 0x150000.
"""
from __future__ import annotations
@@ -34,12 +39,16 @@ def app_partition_size(table: bytes) -> tuple[str, int]:
def main() -> int:
if len(sys.argv) != 3:
print(f"usage: {Path(sys.argv[0]).name} FIRMWARE.BIN PARTITIONS.BIN", file=sys.stderr)
if len(sys.argv) not in (3, 4):
print(
f"usage: {Path(sys.argv[0]).name} FIRMWARE.BIN PARTITIONS.BIN [MAX_IMAGE_BYTES]",
file=sys.stderr,
)
return 2
firmware_path = Path(sys.argv[1])
partition_path = Path(sys.argv[2])
portable_limit = int(sys.argv[3], 0) if len(sys.argv) == 4 else None
try:
image_size = firmware_path.stat().st_size
label, limit = app_partition_size(partition_path.read_bytes())
@@ -55,10 +64,19 @@ def main() -> int:
)
return 1
print(
f"ESP32 app image fits {label}: {image_size}/{limit} bytes "
f"({limit - image_size} bytes free)"
)
if portable_limit is not None and image_size > portable_limit:
print(
f"ESP32 app image is {image_size} bytes, exceeding portable LoRa-OTA "
f"slot 0x10000..0x150000 ({portable_limit} bytes) by "
f"{image_size - portable_limit} bytes",
file=sys.stderr,
)
return 1
message = f"ESP32 app image fits {label}: {image_size}/{limit} bytes ({limit - image_size} bytes free)"
if portable_limit is not None:
message += f"; portable LoRa-OTA slot: {portable_limit - image_size} bytes free"
print(message)
return 0
File diff suppressed because it is too large. Load diff
+5 -1
View File
@@ -106,7 +106,11 @@ def _firmware_ident():
PlatformIO env name (so it's correct even without build.sh's -D MOTA_TARGET_ID), hw_id from MOTA_HW_ID,
fw_version from FIRMWARE_VERSION (a -D if set, else the example's header #define)."""
import re
target_id = ml.target_id_for_env(env["PIOENV"]) # noqa: F821
target_define = (_cppdef("MOTA_TARGET_ID") or "").strip()
try:
target_id = int(target_define, 0) if target_define else ml.target_id_for_env(env["PIOENV"]) # noqa: F821
except ValueError:
target_id = ml.target_id_for_env(env["PIOENV"]) # noqa: F821
hw_id = (_cppdef("MOTA_HW_ID") or "").replace("\\", "").strip().strip('"').strip("'")
if not hw_id:
hw_id = ml.hardware_id_for_env(env["PIOENV"]) # noqa: F821
-19
View File
@@ -224,25 +224,6 @@ build_src_filter = ${rak4631.build_src_filter}
+<helpers/ui/SSD1306Display.cpp>
+<../examples/simple_room_server>
; Explicit lean alternative to the full-sensor, non-OTA room server above.
[env:RAK_4631_room_server_lora_ota_no_external_sensors]
extends = rak4631
build_flags =
${rak4631.build_flags}
${nrf52_no_external_sensors.build_flags}
-D DISPLAY_CLASS=SSD1306Display
-D ADVERT_NAME='"Test Room"'
-D ADVERT_LAT=0.0
-D ADVERT_LON=0.0
-D ADMIN_PASSWORD='"password"'
-D ROOM_PASSWORD='"hello"'
build_src_filter = ${rak4631.build_src_filter}
+<helpers/ui/SSD1306Display.cpp>
+<../examples/simple_room_server>
lib_deps =
${nrf52_lora_ota.lib_deps}
adafruit/Adafruit SSD1306 @ ^2.5.13
[env:RAK_4631_room_server_ethernet]
extends = rak4631
build_flags =