1228 lines
32 KiB
Bash
Executable File
1228 lines
32 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
|
|
ALL_PIO_ENVS=()
|
|
PIO_CONFIG_JSON=""
|
|
MENU_CHOICE=""
|
|
SELECTED_TARGET=""
|
|
SELECTED_COMMAND_ARGS=()
|
|
MESHDEBUG_OVERRIDE=""
|
|
PACKET_LOGGING_OVERRIDE=""
|
|
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=""
|
|
WIFI_SSID_OVERRIDE=""
|
|
WIFI_PWD_OVERRIDE=""
|
|
WIFI_DEBUG_LOGGING_OVERRIDE=""
|
|
|
|
ENV_VARIANT_SUFFIX_PATTERN='companion_radio_serial|companion_radio_wifi|companion_radio_usb|comp_radio_usb|companion_usb|companion_radio_ble|companion_ble|repeater_bridge_rs232_serial1|repeater_bridge_rs232_serial2|repeater_bridge_rs232|repeater_bridge_espnow|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"
|
|
BOARD_MODIFIER_EINK="_eink"
|
|
BOARD_MODIFIER_EINK_SUFFIX="Eink"
|
|
BOARD_LABEL_WITHOUT_DISPLAY="without_display"
|
|
BOARD_LABEL_LOGGING="logging"
|
|
BOARD_LABEL_TFT="tft"
|
|
BOARD_LABEL_EINK="eink"
|
|
DEFAULT_VARIANT_LABEL="default"
|
|
TAG_PREFIX_ROOM_SERVER="room-server"
|
|
TAG_PREFIX_COMPANION="companion"
|
|
TAG_PREFIX_REPEATER="repeater"
|
|
BULK_BUILD_SUFFIX_REPEATER="_repeater"
|
|
BULK_BUILD_SUFFIX_COMPANION_USB="_companion_radio_usb"
|
|
BULK_BUILD_SUFFIX_COMPANION_BLE="_companion_radio_ble"
|
|
BULK_BUILD_SUFFIX_ROOM_SERVER="_room_server"
|
|
SUPPORTED_PLATFORM_PATTERN='ESP32_PLATFORM|NRF52_PLATFORM|STM32_PLATFORM|RP2040_PLATFORM'
|
|
OUTPUT_DIR="out"
|
|
FALLBACK_VERSION_PREFIX="dev"
|
|
FALLBACK_VERSION_DATE_FORMAT='+%Y-%m-%d-%H-%M'
|
|
|
|
# External programs invoked by this script:
|
|
# bash, cat, cp, date, git, grep, head, mkdir, pio, python3, rm, sed, sort
|
|
# Keep this list in sync when adding or removing non-builtin command usage.
|
|
|
|
global_usage() {
|
|
cat - <<EOF
|
|
Usage:
|
|
bash build.sh <command> [target]
|
|
|
|
Commands:
|
|
help|usage|-h|--help: Shows this message.
|
|
list|-l: List firmwares available to build.
|
|
build-firmware <target>: Build the firmware for the given build target.
|
|
build-firmwares: Build all firmwares for all targets.
|
|
build-matching-firmwares <build-match-spec>: Build all firmwares for build targets containing the string given for <build-match-spec>.
|
|
build-companion-firmwares: Build all companion firmwares for all build targets.
|
|
build-repeater-firmwares: Build all repeater firmwares for all build targets.
|
|
build-room-server-firmwares: Build all chat room server firmwares for all build targets.
|
|
|
|
Examples:
|
|
Build firmware for the "RAK_4631_repeater" device target
|
|
$ bash build.sh build-firmware RAK_4631_repeater
|
|
|
|
Run without arguments to choose an interactive build action/target, debug options, radio settings, and (when applicable) Wi-Fi settings
|
|
$ bash build.sh
|
|
|
|
Build all firmwares for device targets containing the string "RAK_4631"
|
|
$ bash build.sh build-matching-firmwares <build-match-spec>
|
|
|
|
Build all companion firmwares
|
|
$ bash build.sh build-companion-firmwares
|
|
|
|
Build all repeater firmwares
|
|
$ bash build.sh build-repeater-firmwares
|
|
|
|
Build all chat room server firmwares
|
|
$ bash build.sh build-room-server-firmwares
|
|
|
|
Environment Variables:
|
|
FIRMWARE_VERSION=vX.Y.Z: Firmware version to embed in the build output.
|
|
If not set, build.sh derives a default from the latest matching git tag and appends "-dev".
|
|
DISABLE_DEBUG=1: Disables all debug logging flags (MESH_DEBUG, MESH_PACKET_LOGGING, etc.)
|
|
If not set, debug flags from variant platformio.ini files are used.
|
|
|
|
Examples:
|
|
Build without debug logging:
|
|
$ export FIRMWARE_VERSION=v1.0.0
|
|
$ export DISABLE_DEBUG=1
|
|
$ bash build.sh build-firmware RAK_4631_repeater
|
|
|
|
Build with debug logging (default, uses flags from variant files):
|
|
$ export FIRMWARE_VERSION=v1.0.0
|
|
$ bash build.sh build-firmware RAK_4631_repeater
|
|
|
|
Build with the derived default version from git tags:
|
|
$ unset FIRMWARE_VERSION
|
|
$ bash build.sh
|
|
EOF
|
|
}
|
|
|
|
init_project_context() {
|
|
if [ ${#ALL_PIO_ENVS[@]} -eq 0 ]; then
|
|
mapfile -t ALL_PIO_ENVS < <(pio project config | grep 'env:' | sed 's/env://')
|
|
fi
|
|
|
|
if [ -z "$PIO_CONFIG_JSON" ]; then
|
|
PIO_CONFIG_JSON=$(pio project config --json-output)
|
|
fi
|
|
}
|
|
|
|
get_pio_envs() {
|
|
if [ ${#ALL_PIO_ENVS[@]} -gt 0 ]; then
|
|
printf '%s\n' "${ALL_PIO_ENVS[@]}"
|
|
else
|
|
pio project config | grep 'env:' | sed 's/env://'
|
|
fi
|
|
}
|
|
|
|
canonicalize_variant_suffix() {
|
|
local variant_suffix=$1
|
|
|
|
case "${variant_suffix,,}" in
|
|
comp_radio_usb|companion_usb|companion_radio_usb)
|
|
echo "companion_radio_usb"
|
|
;;
|
|
companion_ble|companion_radio_ble)
|
|
echo "companion_radio_ble"
|
|
;;
|
|
room_svr|room_server)
|
|
echo "room_server"
|
|
;;
|
|
repeatr|repeater)
|
|
echo "repeater"
|
|
;;
|
|
*)
|
|
echo "${variant_suffix,,}"
|
|
;;
|
|
esac
|
|
}
|
|
|
|
trim_trailing_underscores() {
|
|
local value=$1
|
|
|
|
while [[ "$value" == *_ ]]; do
|
|
value=${value%_}
|
|
done
|
|
|
|
echo "$value"
|
|
}
|
|
|
|
sort_lines_case_insensitive() {
|
|
sort -f
|
|
}
|
|
|
|
print_numbered_menu() {
|
|
local items=("$@")
|
|
local i
|
|
|
|
for i in "${!items[@]}"; do
|
|
printf '%d) %s\n' "$((i + 1))" "${items[$i]}"
|
|
done
|
|
}
|
|
|
|
prompt_menu_choice() {
|
|
local prompt_label=$1
|
|
local max_choice=$2
|
|
local allow_back=${3:-0}
|
|
local choice
|
|
|
|
while true; do
|
|
if [ "$allow_back" -eq 1 ]; then
|
|
read -r -p "${prompt_label} [1-${max_choice}, B=Back, Q=Quit]: " choice
|
|
else
|
|
read -r -p "${prompt_label} [1-${max_choice}, Q=Quit]: " choice
|
|
fi
|
|
|
|
case "${choice^^}" in
|
|
Q)
|
|
MENU_CHOICE="QUIT"
|
|
return 0
|
|
;;
|
|
B)
|
|
if [ "$allow_back" -eq 1 ]; then
|
|
MENU_CHOICE="BACK"
|
|
return 0
|
|
fi
|
|
echo "Invalid selection."
|
|
;;
|
|
*)
|
|
if [[ "$choice" =~ ^[0-9]+$ ]] && [ "$choice" -ge 1 ] && [ "$choice" -le "$max_choice" ]; then
|
|
MENU_CHOICE="$choice"
|
|
return 0
|
|
fi
|
|
echo "Invalid selection."
|
|
;;
|
|
esac
|
|
done
|
|
}
|
|
|
|
prompt_on_off_choice() {
|
|
local prompt_label=$1
|
|
local default_choice=$2
|
|
local normalized_default
|
|
local choice
|
|
|
|
normalized_default=${default_choice,,}
|
|
case "$normalized_default" in
|
|
1) normalized_default="on" ;;
|
|
0) normalized_default="off" ;;
|
|
esac
|
|
|
|
while true; do
|
|
read -r -p "${prompt_label} [on(1)/off(0)] (default: ${normalized_default}): " choice
|
|
choice=${choice,,}
|
|
if [ -z "$choice" ]; then
|
|
choice=$normalized_default
|
|
fi
|
|
|
|
case "$choice" in
|
|
on|1)
|
|
MENU_CHOICE="on"
|
|
return 0
|
|
;;
|
|
off|0)
|
|
MENU_CHOICE="off"
|
|
return 0
|
|
;;
|
|
*)
|
|
echo "Invalid selection. Choose on(1) or off(0)."
|
|
;;
|
|
esac
|
|
done
|
|
}
|
|
|
|
prompt_for_build_mode() {
|
|
local options=(
|
|
"Build one firmware target"
|
|
"Build all firmwares"
|
|
"Build all repeater firmwares"
|
|
"Build all companion firmwares"
|
|
"Build all chat room server firmwares"
|
|
)
|
|
|
|
echo "No command provided. Select a build action:"
|
|
while true; do
|
|
print_numbered_menu "${options[@]}"
|
|
prompt_menu_choice "Build action" "${#options[@]}"
|
|
if [ "$MENU_CHOICE" == "QUIT" ]; then
|
|
echo "Cancelled."
|
|
exit 1
|
|
fi
|
|
|
|
case "$MENU_CHOICE" in
|
|
1)
|
|
prompt_for_board_target
|
|
SELECTED_COMMAND_ARGS=(build-firmware "$SELECTED_TARGET")
|
|
return 0
|
|
;;
|
|
2)
|
|
SELECTED_COMMAND_ARGS=(build-firmwares)
|
|
return 0
|
|
;;
|
|
3)
|
|
SELECTED_COMMAND_ARGS=(build-repeater-firmwares)
|
|
return 0
|
|
;;
|
|
4)
|
|
SELECTED_COMMAND_ARGS=(build-companion-firmwares)
|
|
return 0
|
|
;;
|
|
5)
|
|
SELECTED_COMMAND_ARGS=(build-room-server-firmwares)
|
|
return 0
|
|
;;
|
|
esac
|
|
done
|
|
}
|
|
|
|
prompt_for_debug_build_settings() {
|
|
echo "Set debug build options:"
|
|
prompt_on_off_choice "Mesh debug (MESH_DEBUG)" "off"
|
|
MESHDEBUG_OVERRIDE="$MENU_CHOICE"
|
|
|
|
prompt_on_off_choice "Packet logging (MESH_PACKET_LOGGING)" "off"
|
|
PACKET_LOGGING_OVERRIDE="$MENU_CHOICE"
|
|
|
|
echo "Using debug options: meshdebug=${MESHDEBUG_OVERRIDE}, packet_logging=${PACKET_LOGGING_OVERRIDE}"
|
|
}
|
|
|
|
clear_radio_overrides() {
|
|
RADIO_SETTING_TITLE=""
|
|
RADIO_FREQ_OVERRIDE=""
|
|
RADIO_BW_OVERRIDE=""
|
|
RADIO_SF_OVERRIDE=""
|
|
RADIO_CR_OVERRIDE=""
|
|
}
|
|
|
|
clear_firmware_profile_overrides() {
|
|
FIRMWARE_PROFILE_OVERRIDE=""
|
|
}
|
|
|
|
set_radio_overrides() {
|
|
RADIO_SETTING_TITLE=$1
|
|
RADIO_FREQ_OVERRIDE=$2
|
|
RADIO_BW_OVERRIDE=$3
|
|
RADIO_SF_OVERRIDE=$4
|
|
RADIO_CR_OVERRIDE=$5
|
|
}
|
|
|
|
fetch_suggested_radio_settings() {
|
|
python3 - "$RADIO_SETTINGS_API_URL" <<'PY'
|
|
import json
|
|
import sys
|
|
import urllib.error
|
|
import urllib.request
|
|
|
|
url = sys.argv[1]
|
|
header_sets = [
|
|
{
|
|
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36",
|
|
"Accept": "application/json,text/plain,*/*",
|
|
"Accept-Language": "en-US,en;q=0.9",
|
|
"Referer": "https://meshcore.nz/",
|
|
"Origin": "https://meshcore.nz",
|
|
},
|
|
{
|
|
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:125.0) Gecko/20100101 Firefox/125.0",
|
|
"Accept": "application/json,text/plain,*/*",
|
|
"Accept-Language": "en-US,en;q=0.9",
|
|
"Referer": "https://meshcore.nz/",
|
|
"Origin": "https://meshcore.nz",
|
|
},
|
|
]
|
|
|
|
payload = None
|
|
errors = []
|
|
|
|
for index, headers in enumerate(header_sets, start=1):
|
|
req = urllib.request.Request(url, headers=headers)
|
|
try:
|
|
with urllib.request.urlopen(req, timeout=8) as response:
|
|
payload = json.load(response)
|
|
break
|
|
except urllib.error.HTTPError as exc:
|
|
errors.append(f"attempt {index}: HTTP {exc.code}")
|
|
continue
|
|
except Exception as exc:
|
|
errors.append(f"attempt {index}: {type(exc).__name__}")
|
|
continue
|
|
|
|
if payload is None:
|
|
summary = "; ".join(errors) if errors else "unknown error"
|
|
print(f"Failed to fetch radio presets from {url} ({summary})", file=sys.stderr)
|
|
raise SystemExit(1)
|
|
|
|
entries = (
|
|
payload.get("config", {})
|
|
.get("suggested_radio_settings", {})
|
|
.get("entries", [])
|
|
)
|
|
|
|
for entry in entries:
|
|
title = str(entry.get("title", "")).strip()
|
|
description = str(entry.get("description", "")).strip()
|
|
freq = str(entry.get("frequency", "")).strip()
|
|
sf = str(entry.get("spreading_factor", "")).strip()
|
|
bw = str(entry.get("bandwidth", "")).strip()
|
|
cr = str(entry.get("coding_rate", "")).strip()
|
|
if title and freq and sf and bw and cr:
|
|
print("\t".join([title, description, freq, bw, sf, cr]))
|
|
PY
|
|
}
|
|
|
|
is_valid_custom_radio_bandwidth() {
|
|
python3 - "$1" <<'PY'
|
|
import sys
|
|
|
|
allowed = [7.81, 10.42, 15.63, 20.83, 31.25, 41.67, 62.5, 125.0, 250.0, 500.0]
|
|
try:
|
|
value = float(sys.argv[1])
|
|
except Exception:
|
|
raise SystemExit(1)
|
|
|
|
raise SystemExit(0 if any(abs(value - option) < 1e-6 for option in allowed) else 1)
|
|
PY
|
|
}
|
|
|
|
prompt_for_custom_radio_setting() {
|
|
local freq
|
|
local sf
|
|
local bw
|
|
local cr
|
|
|
|
echo
|
|
echo "Custom radio settings:"
|
|
|
|
while true; do
|
|
read -r -p "Center frequency (MHz, e.g. 915.000): " freq
|
|
if [[ "$freq" =~ ^[0-9]+([.][0-9]+)?$ ]]; then
|
|
break
|
|
fi
|
|
echo "Please enter a numeric MHz value (e.g. 915.000)."
|
|
done
|
|
|
|
echo "Spreading factor options: 5, 6, 7, 8, 9, 10, 11, 12"
|
|
while true; do
|
|
read -r -p "SF (5-12): " sf
|
|
if [[ "$sf" =~ ^[0-9]+$ ]] && [ "$sf" -ge 5 ] && [ "$sf" -le 12 ]; then
|
|
break
|
|
fi
|
|
echo "Please enter 5, 6, 7, 8, 9, 10, 11, or 12."
|
|
done
|
|
|
|
echo "Bandwidth options (kHz): 7.81 10.42 15.63 20.83 31.25 41.67 62.5 125 250 500"
|
|
while true; do
|
|
read -r -p "BW (kHz): " bw
|
|
if [[ "$bw" =~ ^[0-9]+([.][0-9]+)?$ ]] && is_valid_custom_radio_bandwidth "$bw"; then
|
|
break
|
|
fi
|
|
echo "Please enter one of: 7.81 10.42 15.63 20.83 31.25 41.67 62.5 125 250 500."
|
|
done
|
|
|
|
echo "Coding rate options: CR5, CR6, CR7, CR8"
|
|
while true; do
|
|
read -r -p "CR (5-8): " cr
|
|
if [[ "$cr" =~ ^[0-9]+$ ]] && [ "$cr" -ge 5 ] && [ "$cr" -le 8 ]; then
|
|
break
|
|
fi
|
|
echo "Please enter 5, 6, 7, or 8."
|
|
done
|
|
|
|
set_radio_overrides "Custom" "$freq" "$bw" "$sf" "$cr"
|
|
}
|
|
|
|
prompt_for_cascadia_profile_enable() {
|
|
clear_firmware_profile_overrides
|
|
echo
|
|
echo "Cascadia profile changes:"
|
|
echo " - rxdelay: 1"
|
|
echo " - agc.reset.interval: 8"
|
|
echo " - advert.interval: 0"
|
|
echo " - flood.advert.interval: 83"
|
|
echo " - multi.acks: 1"
|
|
echo " - path.hash.mode: 2"
|
|
echo " - loop.detect: minimal"
|
|
prompt_on_off_choice "Enable Cascadia profile overrides" "on"
|
|
if [ "$MENU_CHOICE" == "on" ]; then
|
|
FIRMWARE_PROFILE_OVERRIDE="cascadia"
|
|
echo "Using firmware profile override: ${FIRMWARE_PROFILE_OVERRIDE}"
|
|
return 0
|
|
fi
|
|
|
|
echo "Using target default firmware profile settings."
|
|
return 0
|
|
}
|
|
|
|
prompt_for_radio_build_settings() {
|
|
local -a preset_rows=()
|
|
local -a options=("Keep target defaults (no radio override)")
|
|
local row
|
|
local title
|
|
local description
|
|
local freq
|
|
local bw
|
|
local sf
|
|
local cr
|
|
local preset_index
|
|
local choice_index
|
|
local custom_index
|
|
|
|
clear_radio_overrides
|
|
|
|
if mapfile -t preset_rows < <(fetch_suggested_radio_settings); then
|
|
for row in "${preset_rows[@]}"; do
|
|
IFS=$'\t' read -r title description freq bw sf cr <<< "$row"
|
|
options+=("${title}: ${description}")
|
|
done
|
|
else
|
|
echo "Could not fetch radio presets from ${RADIO_SETTINGS_API_URL}."
|
|
preset_rows=()
|
|
fi
|
|
|
|
options+=("Custom")
|
|
custom_index=${#options[@]}
|
|
|
|
echo "Set radio build options:"
|
|
while true; do
|
|
print_numbered_menu "${options[@]}"
|
|
prompt_menu_choice "Radio setting" "${#options[@]}"
|
|
if [ "$MENU_CHOICE" == "QUIT" ]; then
|
|
echo "Cancelled."
|
|
exit 1
|
|
fi
|
|
|
|
choice_index=$MENU_CHOICE
|
|
if [ "$choice_index" -eq 1 ]; then
|
|
echo "Using target default radio settings."
|
|
return 0
|
|
fi
|
|
|
|
if [ "$choice_index" -eq "$custom_index" ]; then
|
|
prompt_for_custom_radio_setting
|
|
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
|
|
|
|
preset_index=$((choice_index - 2))
|
|
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"
|
|
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
|
|
done
|
|
}
|
|
|
|
clear_wifi_overrides() {
|
|
WIFI_SSID_OVERRIDE=""
|
|
WIFI_PWD_OVERRIDE=""
|
|
WIFI_DEBUG_LOGGING_OVERRIDE=""
|
|
}
|
|
|
|
is_wifi_build_target() {
|
|
local env_name=$1
|
|
local is_wifi=1
|
|
|
|
shopt -s nocasematch
|
|
if [[ "$env_name" == *companion_radio_wifi* ]]; then
|
|
is_wifi=0
|
|
fi
|
|
shopt -u nocasematch
|
|
|
|
return "$is_wifi"
|
|
}
|
|
|
|
selected_command_uses_wifi_target() {
|
|
case "${SELECTED_COMMAND_ARGS[0]:-}" in
|
|
build-firmware)
|
|
is_wifi_build_target "${SELECTED_COMMAND_ARGS[1]:-}"
|
|
return $?
|
|
;;
|
|
*)
|
|
return 1
|
|
;;
|
|
esac
|
|
}
|
|
|
|
prompt_for_wifi_build_settings() {
|
|
local -a options=(
|
|
"Keep target defaults (no Wi-Fi override)"
|
|
"Custom Wi-Fi SSID/password"
|
|
)
|
|
local choice_index
|
|
|
|
clear_wifi_overrides
|
|
|
|
echo "Set Wi-Fi build options:"
|
|
while true; do
|
|
print_numbered_menu "${options[@]}"
|
|
prompt_menu_choice "Wi-Fi setting" "${#options[@]}"
|
|
if [ "$MENU_CHOICE" == "QUIT" ]; then
|
|
echo "Cancelled."
|
|
exit 1
|
|
fi
|
|
|
|
choice_index=$MENU_CHOICE
|
|
case "$choice_index" in
|
|
1)
|
|
echo "Using target default Wi-Fi settings."
|
|
return 0
|
|
;;
|
|
2)
|
|
read -r -p "Wi-Fi SSID: " WIFI_SSID_OVERRIDE
|
|
read -r -p "Wi-Fi password (blank allowed): " WIFI_PWD_OVERRIDE
|
|
prompt_on_off_choice "Wi-Fi debug logging (WIFI_DEBUG_LOGGING)" "off"
|
|
WIFI_DEBUG_LOGGING_OVERRIDE="$MENU_CHOICE"
|
|
echo "Using Wi-Fi overrides: ssid='${WIFI_SSID_OVERRIDE}', wifi_debug=${WIFI_DEBUG_LOGGING_OVERRIDE}"
|
|
return 0
|
|
;;
|
|
esac
|
|
done
|
|
}
|
|
|
|
escape_cpp_string_literal() {
|
|
local value=$1
|
|
|
|
value=${value//\\/\\\\}
|
|
value=${value//\"/\\\"}
|
|
printf '%s' "$value"
|
|
}
|
|
|
|
get_env_metadata() {
|
|
local env_name=$1
|
|
local trimmed_env_name
|
|
local board_part
|
|
local variant_part
|
|
local board_family
|
|
local board_modifier
|
|
local variant_label
|
|
local tag_prefix
|
|
|
|
trimmed_env_name=$(trim_trailing_underscores "$env_name")
|
|
board_part=$trimmed_env_name
|
|
variant_part=""
|
|
|
|
shopt -s nocasematch
|
|
# Split a raw env name into board and variant pieces using the normalized
|
|
# suffix vocabulary defined near the top of the file.
|
|
if [[ "$trimmed_env_name" =~ ^(.+)[_-](${ENV_VARIANT_SUFFIX_PATTERN})$ ]]; then
|
|
board_part=${BASH_REMATCH[1]}
|
|
variant_part=$(canonicalize_variant_suffix "${BASH_REMATCH[2]}")
|
|
fi
|
|
|
|
# Fold display and form-factor suffixes into the variant label so related
|
|
# boards share one first-level menu entry.
|
|
case "$board_part" in
|
|
*"$BOARD_MODIFIER_WITHOUT_DISPLAY")
|
|
board_family=${board_part%"$BOARD_MODIFIER_WITHOUT_DISPLAY"}
|
|
board_modifier="$BOARD_LABEL_WITHOUT_DISPLAY"
|
|
;;
|
|
*"$BOARD_MODIFIER_LOGGING")
|
|
board_family=${board_part%"$BOARD_MODIFIER_LOGGING"}
|
|
board_modifier="$BOARD_LABEL_LOGGING"
|
|
;;
|
|
*"$BOARD_MODIFIER_TFT")
|
|
board_family=${board_part%"$BOARD_MODIFIER_TFT"}
|
|
board_modifier="$BOARD_LABEL_TFT"
|
|
;;
|
|
*"$BOARD_MODIFIER_EINK")
|
|
board_family=${board_part%"$BOARD_MODIFIER_EINK"}
|
|
board_modifier="$BOARD_LABEL_EINK"
|
|
;;
|
|
*"$BOARD_MODIFIER_EINK_SUFFIX")
|
|
board_family=${board_part%"$BOARD_MODIFIER_EINK_SUFFIX"}
|
|
board_modifier="$BOARD_LABEL_EINK"
|
|
;;
|
|
*)
|
|
board_family=$board_part
|
|
board_modifier=""
|
|
;;
|
|
esac
|
|
shopt -u nocasematch
|
|
|
|
variant_label="$variant_part"
|
|
if [ -n "$board_modifier" ]; then
|
|
if [ -n "$variant_label" ]; then
|
|
variant_label="${board_modifier}_${variant_label}"
|
|
else
|
|
variant_label="$board_modifier"
|
|
fi
|
|
fi
|
|
|
|
if [ -z "$variant_label" ]; then
|
|
variant_label="$DEFAULT_VARIANT_LABEL"
|
|
fi
|
|
|
|
case "$variant_part" in
|
|
room_server)
|
|
tag_prefix="$TAG_PREFIX_ROOM_SERVER"
|
|
;;
|
|
companion_radio_*)
|
|
tag_prefix="$TAG_PREFIX_COMPANION"
|
|
;;
|
|
repeater*)
|
|
tag_prefix="$TAG_PREFIX_REPEATER"
|
|
;;
|
|
*)
|
|
tag_prefix=""
|
|
;;
|
|
esac
|
|
|
|
printf '%s\t%s\t%s\n' "$board_family" "$variant_label" "$tag_prefix"
|
|
}
|
|
|
|
get_metadata_field() {
|
|
local env_name=$1
|
|
local field_index=$2
|
|
local metadata
|
|
|
|
metadata=$(get_env_metadata "$env_name")
|
|
case "$field_index" in
|
|
1)
|
|
echo "${metadata%%$'\t'*}"
|
|
;;
|
|
2)
|
|
metadata=${metadata#*$'\t'}
|
|
echo "${metadata%%$'\t'*}"
|
|
;;
|
|
3)
|
|
echo "${metadata##*$'\t'}"
|
|
;;
|
|
esac
|
|
}
|
|
|
|
get_board_family_for_env() {
|
|
get_metadata_field "$1" 1
|
|
}
|
|
|
|
get_variant_name_for_env() {
|
|
get_metadata_field "$1" 2
|
|
}
|
|
|
|
get_release_tag_prefix_for_env() {
|
|
get_metadata_field "$1" 3
|
|
}
|
|
|
|
get_variants_for_board() {
|
|
local board_family=$1
|
|
local env
|
|
|
|
for env in "${ALL_PIO_ENVS[@]}"; do
|
|
if [ "$(get_board_family_for_env "$env")" == "$board_family" ]; then
|
|
echo "$env"
|
|
fi
|
|
done | sort_lines_case_insensitive
|
|
}
|
|
|
|
prompt_for_variant_for_board() {
|
|
local board=$1
|
|
local -A seen_variant_labels=()
|
|
local variants
|
|
local variant_labels
|
|
local i
|
|
local j
|
|
|
|
mapfile -t variants < <(get_variants_for_board "$board")
|
|
if [ ${#variants[@]} -eq 0 ]; then
|
|
echo "No firmware variants were found for ${board}."
|
|
return 1
|
|
fi
|
|
|
|
if [ ${#variants[@]} -eq 1 ]; then
|
|
SELECTED_TARGET="${variants[0]}"
|
|
return 0
|
|
fi
|
|
|
|
variant_labels=()
|
|
for i in "${!variants[@]}"; do
|
|
variant_labels[i]=$(get_variant_name_for_env "${variants[$i]}")
|
|
seen_variant_labels["${variant_labels[$i]}"]=$(( ${seen_variant_labels["${variant_labels[$i]}"]:-0} + 1 ))
|
|
done
|
|
|
|
# Stop early if normalization would present the user with ambiguous labels.
|
|
for i in "${!variant_labels[@]}"; do
|
|
if [ "${seen_variant_labels["${variant_labels[$i]}"]}" -gt 1 ]; then
|
|
echo "Ambiguous firmware variants detected for ${board}: ${variant_labels[$i]}"
|
|
echo "The normalized menu labels are not unique for this board family."
|
|
for j in "${!variants[@]}"; do
|
|
echo " ${variants[$j]}"
|
|
done
|
|
exit 1
|
|
fi
|
|
done
|
|
|
|
echo "Select a firmware variant for ${board}:"
|
|
while true; do
|
|
print_numbered_menu "${variant_labels[@]}"
|
|
prompt_menu_choice "Variant selection" "${#variant_labels[@]}" 1
|
|
if [ "$MENU_CHOICE" == "BACK" ]; then
|
|
return 1
|
|
fi
|
|
if [ "$MENU_CHOICE" == "QUIT" ]; then
|
|
echo "Cancelled."
|
|
exit 1
|
|
fi
|
|
|
|
SELECTED_TARGET="${variants[$((MENU_CHOICE - 1))]}"
|
|
return 0
|
|
done
|
|
}
|
|
|
|
prompt_for_board_target() {
|
|
local -A seen_boards=()
|
|
local boards=()
|
|
local board
|
|
local env
|
|
|
|
if ! [ -t 0 ]; then
|
|
echo "No command provided and no interactive terminal is available."
|
|
global_usage
|
|
exit 1
|
|
fi
|
|
|
|
if [ ${#ALL_PIO_ENVS[@]} -eq 0 ]; then
|
|
echo "No PlatformIO environments were found."
|
|
exit 1
|
|
fi
|
|
|
|
for env in "${ALL_PIO_ENVS[@]}"; do
|
|
board=$(get_board_family_for_env "$env")
|
|
if [ -z "${seen_boards[$board]}" ]; then
|
|
seen_boards["$board"]=1
|
|
boards+=("$board")
|
|
fi
|
|
done
|
|
|
|
mapfile -t boards < <(printf '%s\n' "${boards[@]}" | sort_lines_case_insensitive)
|
|
|
|
echo "Select a board family:"
|
|
while true; do
|
|
print_numbered_menu "${boards[@]}"
|
|
prompt_menu_choice "Board selection" "${#boards[@]}"
|
|
if [ "$MENU_CHOICE" == "QUIT" ]; then
|
|
echo "Cancelled."
|
|
exit 1
|
|
fi
|
|
|
|
board=${boards[$((MENU_CHOICE - 1))]}
|
|
if prompt_for_variant_for_board "$board"; then
|
|
echo "Building firmware for ${SELECTED_TARGET}"
|
|
return 0
|
|
fi
|
|
done
|
|
}
|
|
|
|
get_latest_version_from_tags() {
|
|
local env_name=$1
|
|
local tag_prefix
|
|
local latest_tag
|
|
local fallback_version
|
|
|
|
fallback_version="${FALLBACK_VERSION_PREFIX}-$(date "${FALLBACK_VERSION_DATE_FORMAT}")"
|
|
tag_prefix=$(get_release_tag_prefix_for_env "$env_name")
|
|
if [ -z "$tag_prefix" ]; then
|
|
echo "$fallback_version"
|
|
return 0
|
|
fi
|
|
|
|
latest_tag=$(git tag --list "${tag_prefix}-v*" --sort=-version:refname | head -n 1)
|
|
if [ -z "$latest_tag" ]; then
|
|
echo "$fallback_version"
|
|
return 0
|
|
fi
|
|
|
|
echo "${latest_tag#"${tag_prefix}"-}"
|
|
}
|
|
|
|
derive_default_firmware_version() {
|
|
local env_name=$1
|
|
local base_version
|
|
|
|
base_version=$(get_latest_version_from_tags "$env_name")
|
|
case "$base_version" in
|
|
*-dev|dev-*)
|
|
echo "$base_version"
|
|
;;
|
|
*)
|
|
echo "${base_version}-dev"
|
|
;;
|
|
esac
|
|
}
|
|
|
|
prompt_for_firmware_version() {
|
|
local env_name=$1
|
|
local suggested_version
|
|
local entered_version
|
|
|
|
suggested_version=$(derive_default_firmware_version "$env_name")
|
|
|
|
if ! [ -t 0 ]; then
|
|
FIRMWARE_VERSION="$suggested_version"
|
|
echo "FIRMWARE_VERSION not set, using derived default: ${FIRMWARE_VERSION}"
|
|
return 0
|
|
fi
|
|
|
|
echo "Suggested firmware version for ${env_name}: ${suggested_version}"
|
|
read -r -e -i "${suggested_version}" -p "Firmware version: " entered_version
|
|
FIRMWARE_VERSION="${entered_version:-$suggested_version}"
|
|
}
|
|
|
|
get_pio_envs_containing_string() {
|
|
local env
|
|
|
|
shopt -s nocasematch
|
|
for env in "${ALL_PIO_ENVS[@]}"; do
|
|
if [[ "$env" == *${1}* ]]; then
|
|
echo "$env"
|
|
fi
|
|
done
|
|
shopt -u nocasematch
|
|
}
|
|
|
|
get_pio_envs_ending_with_string() {
|
|
local env
|
|
|
|
shopt -s nocasematch
|
|
for env in "${ALL_PIO_ENVS[@]}"; do
|
|
if [[ "$env" == *${1} ]]; then
|
|
echo "$env"
|
|
fi
|
|
done
|
|
shopt -u nocasematch
|
|
}
|
|
|
|
get_platform_for_env() {
|
|
local env_name=$1
|
|
|
|
# PlatformIO exposes project config as JSON; scan the selected env's
|
|
# build_flags to recover the platform token used for artifact collection.
|
|
# Feed the cached JSON via stdin to avoid shell echo quirks and argv/env size limits.
|
|
python3 -c "
|
|
import sys, json, re
|
|
data = json.load(sys.stdin)
|
|
for section, options in data:
|
|
if section == 'env:$env_name':
|
|
for key, value in options:
|
|
if key == 'build_flags':
|
|
for flag in value:
|
|
match = re.search(r'($SUPPORTED_PLATFORM_PATTERN)', flag)
|
|
if match:
|
|
print(match.group(1))
|
|
sys.exit(0)
|
|
" <<<"$PIO_CONFIG_JSON"
|
|
}
|
|
|
|
is_supported_platform() {
|
|
local env_platform=$1
|
|
|
|
[[ "$env_platform" =~ ^(${SUPPORTED_PLATFORM_PATTERN})$ ]]
|
|
}
|
|
|
|
disable_debug_flags() {
|
|
if [ "$DISABLE_DEBUG" == "1" ]; then
|
|
export PLATFORMIO_BUILD_FLAGS="${PLATFORMIO_BUILD_FLAGS} -UMESH_DEBUG -UBLE_DEBUG_LOGGING -UWIFI_DEBUG_LOGGING -UBRIDGE_DEBUG -UGPS_NMEA_DEBUG -UCORE_DEBUG_LEVEL -UESPNOW_DEBUG_LOGGING -UDEBUG_RP2040_WIRE -UDEBUG_RP2040_SPI -UDEBUG_RP2040_CORE -UDEBUG_RP2040_PORT -URADIOLIB_DEBUG_SPI -UCFG_DEBUG -URADIOLIB_DEBUG_BASIC -URADIOLIB_DEBUG_PROTOCOL"
|
|
fi
|
|
}
|
|
|
|
apply_debug_overrides() {
|
|
case "${MESHDEBUG_OVERRIDE,,}" in
|
|
on)
|
|
export PLATFORMIO_BUILD_FLAGS="${PLATFORMIO_BUILD_FLAGS} -UMESH_DEBUG -DMESH_DEBUG=1"
|
|
;;
|
|
off)
|
|
export PLATFORMIO_BUILD_FLAGS="${PLATFORMIO_BUILD_FLAGS} -UMESH_DEBUG"
|
|
;;
|
|
esac
|
|
|
|
case "${PACKET_LOGGING_OVERRIDE,,}" in
|
|
on)
|
|
export PLATFORMIO_BUILD_FLAGS="${PLATFORMIO_BUILD_FLAGS} -UMESH_PACKET_LOGGING -DMESH_PACKET_LOGGING=1"
|
|
;;
|
|
off)
|
|
export PLATFORMIO_BUILD_FLAGS="${PLATFORMIO_BUILD_FLAGS} -UMESH_PACKET_LOGGING"
|
|
;;
|
|
esac
|
|
}
|
|
|
|
apply_radio_overrides() {
|
|
if [ -n "$RADIO_FREQ_OVERRIDE" ] && [ -n "$RADIO_BW_OVERRIDE" ] && [ -n "$RADIO_SF_OVERRIDE" ] && [ -n "$RADIO_CR_OVERRIDE" ]; then
|
|
export PLATFORMIO_BUILD_FLAGS="${PLATFORMIO_BUILD_FLAGS} -DLORA_FREQ=${RADIO_FREQ_OVERRIDE} -DLORA_BW=${RADIO_BW_OVERRIDE} -DLORA_SF=${RADIO_SF_OVERRIDE} -DLORA_CR=${RADIO_CR_OVERRIDE}"
|
|
fi
|
|
}
|
|
|
|
apply_firmware_profile_overrides() {
|
|
case "${FIRMWARE_PROFILE_OVERRIDE,,}" in
|
|
cascadia)
|
|
export PLATFORMIO_BUILD_FLAGS="${PLATFORMIO_BUILD_FLAGS} -DCASCADIA_PROFILE=1 -DDEFAULT_RX_DELAY_BASE=1.0f -DDEFAULT_LOOP_DETECT=1 -DDEFAULT_AGC_RESET_INTERVAL=2 -DDEFAULT_ADVERT_INTERVAL=0 -DDEFAULT_FLOOD_ADVERT_INTERVAL=83 -DDEFAULT_MULTI_ACKS=1 -DDEFAULT_PATH_HASH_MODE=2"
|
|
;;
|
|
esac
|
|
}
|
|
|
|
apply_wifi_overrides() {
|
|
local env_name=$1
|
|
local ssid_escaped
|
|
local pwd_escaped
|
|
|
|
if ! is_wifi_build_target "$env_name"; then
|
|
return 0
|
|
fi
|
|
|
|
if [ -n "$WIFI_SSID_OVERRIDE" ]; then
|
|
ssid_escaped=$(escape_cpp_string_literal "$WIFI_SSID_OVERRIDE")
|
|
export PLATFORMIO_BUILD_FLAGS="${PLATFORMIO_BUILD_FLAGS} -D WIFI_SSID='\"${ssid_escaped}\"'"
|
|
fi
|
|
|
|
if [ -n "$WIFI_SSID_OVERRIDE" ] || [ -n "$WIFI_PWD_OVERRIDE" ]; then
|
|
pwd_escaped=$(escape_cpp_string_literal "$WIFI_PWD_OVERRIDE")
|
|
export PLATFORMIO_BUILD_FLAGS="${PLATFORMIO_BUILD_FLAGS} -D WIFI_PWD='\"${pwd_escaped}\"'"
|
|
fi
|
|
|
|
case "${WIFI_DEBUG_LOGGING_OVERRIDE,,}" in
|
|
on)
|
|
export PLATFORMIO_BUILD_FLAGS="${PLATFORMIO_BUILD_FLAGS} -D WIFI_DEBUG_LOGGING=1"
|
|
;;
|
|
off)
|
|
if [ -n "$WIFI_SSID_OVERRIDE" ] || [ -n "$WIFI_PWD_OVERRIDE" ]; then
|
|
export PLATFORMIO_BUILD_FLAGS="${PLATFORMIO_BUILD_FLAGS} -D WIFI_DEBUG_LOGGING=0"
|
|
fi
|
|
;;
|
|
esac
|
|
}
|
|
|
|
copy_build_output() {
|
|
local source_path=$1
|
|
local output_path=$2
|
|
|
|
if [ -f "$source_path" ]; then
|
|
cp -- "$source_path" "$output_path"
|
|
fi
|
|
}
|
|
|
|
collect_esp32_artifacts() {
|
|
local env_name=$1
|
|
local firmware_filename=$2
|
|
|
|
pio run -t mergebin -e "$env_name"
|
|
copy_build_output ".pio/build/${env_name}/firmware.bin" "out/${firmware_filename}.bin"
|
|
copy_build_output ".pio/build/${env_name}/firmware-merged.bin" "out/${firmware_filename}-merged.bin"
|
|
}
|
|
|
|
collect_nrf52_artifacts() {
|
|
local env_name=$1
|
|
local firmware_filename=$2
|
|
|
|
python3 bin/uf2conv/uf2conv.py ".pio/build/${env_name}/firmware.hex" -c -o ".pio/build/${env_name}/firmware.uf2" -f 0xADA52840
|
|
copy_build_output ".pio/build/${env_name}/firmware.uf2" "out/${firmware_filename}.uf2"
|
|
copy_build_output ".pio/build/${env_name}/firmware.zip" "out/${firmware_filename}.zip"
|
|
}
|
|
|
|
collect_stm32_artifacts() {
|
|
local env_name=$1
|
|
local firmware_filename=$2
|
|
|
|
copy_build_output ".pio/build/${env_name}/firmware.bin" "out/${firmware_filename}.bin"
|
|
copy_build_output ".pio/build/${env_name}/firmware.hex" "out/${firmware_filename}.hex"
|
|
}
|
|
|
|
collect_rp2040_artifacts() {
|
|
local env_name=$1
|
|
local firmware_filename=$2
|
|
|
|
copy_build_output ".pio/build/${env_name}/firmware.bin" "out/${firmware_filename}.bin"
|
|
copy_build_output ".pio/build/${env_name}/firmware.uf2" "out/${firmware_filename}.uf2"
|
|
}
|
|
|
|
collect_build_artifacts() {
|
|
local env_name=$1
|
|
local env_platform=$2
|
|
local firmware_filename=$3
|
|
|
|
# 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"
|
|
;;
|
|
NRF52_PLATFORM)
|
|
collect_nrf52_artifacts "$env_name" "$firmware_filename"
|
|
;;
|
|
STM32_PLATFORM)
|
|
collect_stm32_artifacts "$env_name" "$firmware_filename"
|
|
;;
|
|
RP2040_PLATFORM)
|
|
collect_rp2040_artifacts "$env_name" "$firmware_filename"
|
|
;;
|
|
esac
|
|
}
|
|
|
|
build_firmware() {
|
|
local env_name=$1
|
|
local env_platform
|
|
local commit_hash
|
|
local firmware_build_date
|
|
local firmware_version_string
|
|
local firmware_filename
|
|
|
|
env_platform=$(get_platform_for_env "$env_name")
|
|
if ! is_supported_platform "$env_platform"; then
|
|
echo "Unsupported or unknown platform for env: $env_name"
|
|
exit 1
|
|
fi
|
|
|
|
commit_hash=$(git rev-parse --short HEAD)
|
|
firmware_build_date=$(date '+%d-%b-%Y')
|
|
|
|
if [ -z "$FIRMWARE_VERSION" ]; then
|
|
prompt_for_firmware_version "$env_name"
|
|
echo "Using firmware version: ${FIRMWARE_VERSION}"
|
|
fi
|
|
|
|
firmware_version_string="${FIRMWARE_VERSION}-${commit_hash}"
|
|
firmware_filename="${env_name}-${firmware_version_string}"
|
|
|
|
export PLATFORMIO_BUILD_FLAGS="${PLATFORMIO_BUILD_FLAGS} -DFIRMWARE_BUILD_DATE='\"${firmware_build_date}\"' -DFIRMWARE_VERSION='\"${firmware_version_string}\"'"
|
|
disable_debug_flags
|
|
apply_debug_overrides
|
|
apply_radio_overrides
|
|
apply_firmware_profile_overrides
|
|
apply_wifi_overrides "$env_name"
|
|
|
|
pio run -e "$env_name"
|
|
collect_build_artifacts "$env_name" "$env_platform" "$firmware_filename"
|
|
}
|
|
|
|
build_all_firmwares_matching() {
|
|
local envs
|
|
local env
|
|
|
|
mapfile -t envs < <(get_pio_envs_containing_string "$1")
|
|
for env in "${envs[@]}"; do
|
|
build_firmware "$env"
|
|
done
|
|
}
|
|
|
|
build_all_firmwares_by_suffix() {
|
|
local envs
|
|
local env
|
|
|
|
mapfile -t envs < <(get_pio_envs_ending_with_string "$1")
|
|
for env in "${envs[@]}"; do
|
|
build_firmware "$env"
|
|
done
|
|
}
|
|
|
|
build_repeater_firmwares() {
|
|
build_all_firmwares_by_suffix "$BULK_BUILD_SUFFIX_REPEATER"
|
|
}
|
|
|
|
build_companion_firmwares() {
|
|
build_all_firmwares_by_suffix "$BULK_BUILD_SUFFIX_COMPANION_USB"
|
|
build_all_firmwares_by_suffix "$BULK_BUILD_SUFFIX_COMPANION_BLE"
|
|
}
|
|
|
|
build_room_server_firmwares() {
|
|
build_all_firmwares_by_suffix "$BULK_BUILD_SUFFIX_ROOM_SERVER"
|
|
}
|
|
|
|
build_firmwares() {
|
|
build_companion_firmwares
|
|
build_repeater_firmwares
|
|
build_room_server_firmwares
|
|
}
|
|
|
|
prepare_output_dir() {
|
|
local output_dir="$OUTPUT_DIR"
|
|
|
|
if [ -z "$output_dir" ] || [ "$output_dir" == "/" ] || [ "$output_dir" == "." ]; then
|
|
echo "Refusing to clean unsafe output directory: $output_dir"
|
|
exit 1
|
|
fi
|
|
|
|
rm -rf -- "$output_dir"
|
|
mkdir -p -- "$output_dir"
|
|
}
|
|
|
|
run_build_firmware_command() {
|
|
local targets=("${@:2}")
|
|
local env
|
|
|
|
if [ ${#targets[@]} -eq 0 ]; then
|
|
echo "usage: $0 build-firmware <target>"
|
|
exit 1
|
|
fi
|
|
|
|
for env in "${targets[@]}"; do
|
|
build_firmware "$env"
|
|
done
|
|
}
|
|
|
|
run_command() {
|
|
case "$1" in
|
|
build-firmware)
|
|
run_build_firmware_command "$@"
|
|
;;
|
|
build-matching-firmwares)
|
|
if [ -n "$2" ]; then
|
|
build_all_firmwares_matching "$2"
|
|
else
|
|
echo "usage: $0 build-matching-firmwares <build-match-spec>"
|
|
exit 1
|
|
fi
|
|
;;
|
|
build-firmwares)
|
|
build_firmwares
|
|
;;
|
|
build-companion-firmwares)
|
|
build_companion_firmwares
|
|
;;
|
|
build-repeater-firmwares)
|
|
build_repeater_firmwares
|
|
;;
|
|
build-room-server-firmwares)
|
|
build_room_server_firmwares
|
|
;;
|
|
*)
|
|
global_usage
|
|
exit 1
|
|
;;
|
|
esac
|
|
}
|
|
|
|
main() {
|
|
case "${1:-}" in
|
|
help|usage|-h|--help)
|
|
global_usage
|
|
exit 0
|
|
;;
|
|
list|-l)
|
|
init_project_context
|
|
get_pio_envs
|
|
exit 0
|
|
;;
|
|
esac
|
|
|
|
init_project_context
|
|
|
|
if [ $# -eq 0 ]; then
|
|
prompt_for_build_mode
|
|
prompt_for_debug_build_settings
|
|
prompt_for_radio_build_settings
|
|
prompt_for_cascadia_profile_enable
|
|
if selected_command_uses_wifi_target; then
|
|
prompt_for_wifi_build_settings
|
|
else
|
|
clear_wifi_overrides
|
|
fi
|
|
set -- "${SELECTED_COMMAND_ARGS[@]}"
|
|
fi
|
|
|
|
prepare_output_dir
|
|
run_command "$@"
|
|
}
|
|
|
|
main "$@"
|