Initial commit for nrf5340_audio
This commit is contained in:
418
tools/buildprog/buildprog.py
Normal file
418
tools/buildprog/buildprog.py
Normal file
@@ -0,0 +1,418 @@
|
||||
#
|
||||
# Copyright (c) 2018 Nordic Semiconductor ASA
|
||||
#
|
||||
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
#
|
||||
|
||||
"""
|
||||
Script to build and program the nRF5340 Audio project to multiple devices
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
import shutil
|
||||
import os
|
||||
import json
|
||||
import subprocess
|
||||
import re
|
||||
import getpass
|
||||
from pathlib import Path
|
||||
from colorama import Fore, Style
|
||||
from prettytable import PrettyTable
|
||||
from nrf5340_audio_dk_devices import (
|
||||
BuildType,
|
||||
Channel,
|
||||
DeviceConf,
|
||||
BuildConf,
|
||||
AudioDevice,
|
||||
SelectFlags,
|
||||
Core,
|
||||
Transport,
|
||||
)
|
||||
from program import program_threads_run
|
||||
|
||||
|
||||
BUILDPROG_FOLDER = Path(__file__).resolve().parent
|
||||
NRF5340_AUDIO_FOLDER = (BUILDPROG_FOLDER / "../..").resolve()
|
||||
NRF_FOLDER = (BUILDPROG_FOLDER / "../../../..").resolve()
|
||||
if os.getenv("AUDIO_KIT_SERIAL_NUMBERS_JSON") is None:
|
||||
AUDIO_KIT_SERIAL_NUMBERS_JSON = BUILDPROG_FOLDER / "nrf5340_audio_dk_devices.json"
|
||||
else:
|
||||
AUDIO_KIT_SERIAL_NUMBERS_JSON = Path(
|
||||
os.getenv("AUDIO_KIT_SERIAL_NUMBERS_JSON"))
|
||||
TARGET_BOARD_NRF5340_AUDIO_DK_APP_NAME = "nrf5340_audio_dk/nrf5340/cpuapp"
|
||||
|
||||
TARGET_AUDIO_FOLDER = NRF5340_AUDIO_FOLDER
|
||||
TARGET_AUDIO_BUILD_FOLDER = TARGET_AUDIO_FOLDER / "tools/build"
|
||||
|
||||
UNICAST_SERVER_OVERLAY = NRF5340_AUDIO_FOLDER / "unicast_server/overlay-unicast_server.conf"
|
||||
UNICAST_CLIENT_OVERLAY = NRF5340_AUDIO_FOLDER / "unicast_client/overlay-unicast_client.conf"
|
||||
BROADCAST_SINK_OVERLAY = NRF5340_AUDIO_FOLDER / "broadcast_sink/overlay-broadcast_sink.conf"
|
||||
BROADCAST_SOURCE_OVERLAY = NRF5340_AUDIO_FOLDER / "broadcast_source/overlay-broadcast_source.conf"
|
||||
|
||||
TARGET_RELEASE_FOLDER = "build_release"
|
||||
TARGET_DEBUG_FOLDER = "build_debug"
|
||||
|
||||
MAX_USER_NAME_LEN = 248 - len('\0')
|
||||
|
||||
|
||||
def __print_add_color(status):
|
||||
if status == SelectFlags.FAIL:
|
||||
return Fore.RED + status.value + Style.RESET_ALL
|
||||
elif status == SelectFlags.DONE:
|
||||
return Fore.GREEN + status.value + Style.RESET_ALL
|
||||
return status.value
|
||||
|
||||
|
||||
def __print_dev_conf(device_list):
|
||||
"""Print settings in a formatted manner"""
|
||||
table = PrettyTable()
|
||||
table.field_names = [
|
||||
"snr",
|
||||
"snr conn",
|
||||
"device",
|
||||
"only reboot",
|
||||
"core app programmed",
|
||||
"core net programmed",
|
||||
]
|
||||
for device in device_list:
|
||||
row = []
|
||||
row.append(device.nrf5340_audio_dk_snr)
|
||||
color = Fore.GREEN if device.snr_connected else Fore.YELLOW
|
||||
row.append(color + str(device.snr_connected) + Style.RESET_ALL)
|
||||
row.append(device.nrf5340_audio_dk_dev.value)
|
||||
row.append(__print_add_color(device.only_reboot))
|
||||
row.append(__print_add_color(device.core_app_programmed))
|
||||
row.append(__print_add_color(device.core_net_programmed))
|
||||
|
||||
table.add_row(row)
|
||||
print(table)
|
||||
|
||||
|
||||
def __build_cmd_get(core: Core, device: AudioDevice, build: BuildType,
|
||||
pristine, options):
|
||||
|
||||
build_cmd = (f"west build {TARGET_AUDIO_FOLDER} "
|
||||
f"-b {TARGET_BOARD_NRF5340_AUDIO_DK_APP_NAME} "
|
||||
f"--sysbuild")
|
||||
|
||||
if core == Core.app:
|
||||
build_cmd += " --domain nrf5340_audio"
|
||||
elif core == Core.net:
|
||||
build_cmd += " --domain ipc_radio"
|
||||
else:
|
||||
raise Exception("Invalid core!")
|
||||
|
||||
if build == BuildType.debug:
|
||||
release_flag = ""
|
||||
elif build == BuildType.release:
|
||||
release_flag = " -DFILE_SUFFIX=release"
|
||||
else:
|
||||
raise Exception("Invalid build type!")
|
||||
|
||||
device_flag = ""
|
||||
|
||||
if options.nrf21540:
|
||||
device_flag += " -Dnrf5340_audio_SHIELD=nrf21540ek"
|
||||
device_flag += " -Dipc_radio_SHIELD=nrf21540ek"
|
||||
if options.custom_bt_name is not None and options.user_bt_name:
|
||||
raise Exception(
|
||||
"User BT name option is invalid when custom BT name is set")
|
||||
if options.custom_bt_name is not None:
|
||||
custom_bt_name = "_".join(options.custom_bt_name)[
|
||||
:MAX_USER_NAME_LEN].upper()
|
||||
device_flag += " -DCONFIG_BT_DEVICE_NAME=\\\"" + custom_bt_name + "\\\""
|
||||
if options.user_bt_name:
|
||||
user_specific_bt_name = (
|
||||
"AUDIO_DEV_" + getpass.getuser())[:MAX_USER_NAME_LEN].upper()
|
||||
device_flag += " -DCONFIG_BT_DEVICE_NAME=\\\"" + user_specific_bt_name + "\\\""
|
||||
if options.transport == Transport.broadcast.name:
|
||||
if device == AudioDevice.headset:
|
||||
overlay_flag = f" -DEXTRA_CONF_FILE={BROADCAST_SINK_OVERLAY}"
|
||||
else:
|
||||
overlay_flag = f" -DEXTRA_CONF_FILE={BROADCAST_SOURCE_OVERLAY}"
|
||||
else:
|
||||
if device == AudioDevice.headset:
|
||||
overlay_flag = f" -DEXTRA_CONF_FILE={UNICAST_SERVER_OVERLAY}"
|
||||
else:
|
||||
overlay_flag = f" -DEXTRA_CONF_FILE={UNICAST_CLIENT_OVERLAY}"
|
||||
|
||||
if os.name == 'nt':
|
||||
release_flag = release_flag.replace('\\', '/')
|
||||
if pristine:
|
||||
build_cmd += " --pristine"
|
||||
|
||||
dest_folder = TARGET_AUDIO_BUILD_FOLDER / options.transport / device / core / build
|
||||
|
||||
return build_cmd, dest_folder, device_flag, release_flag, overlay_flag
|
||||
|
||||
|
||||
def __build_module(build_config, options):
|
||||
build_cmd, dest_folder, device_flag, release_flag, overlay_flag = __build_cmd_get(
|
||||
build_config.core,
|
||||
build_config.device,
|
||||
build_config.build,
|
||||
build_config.pristine,
|
||||
options,
|
||||
)
|
||||
west_str = f"{build_cmd} -d {dest_folder} "
|
||||
|
||||
if build_config.pristine and dest_folder.exists():
|
||||
shutil.rmtree(dest_folder)
|
||||
|
||||
# Only add compiler flags if folder doesn't exist already
|
||||
if not dest_folder.exists():
|
||||
west_str = west_str + device_flag + release_flag + overlay_flag
|
||||
|
||||
print("Run: " + west_str)
|
||||
|
||||
ret_val = os.system(west_str)
|
||||
|
||||
if ret_val:
|
||||
raise Exception("cmake error: " + str(ret_val))
|
||||
|
||||
|
||||
def __find_snr():
|
||||
"""Rebooting or programming requires connected programmer/debugger"""
|
||||
|
||||
# Use nrfjprog executable for WSL compatibility
|
||||
stdout = subprocess.check_output(
|
||||
"nrfjprog --ids", shell=True).decode("utf-8")
|
||||
snrs = re.findall(r"([\d]+)", stdout)
|
||||
|
||||
if not snrs:
|
||||
print("No programmer/debugger connected to PC")
|
||||
|
||||
return list(map(int, snrs))
|
||||
|
||||
|
||||
def __populate_hex_paths(dev, options):
|
||||
"""Poplulate hex paths where relevant"""
|
||||
|
||||
_, temp_dest_folder, _, _, _ = __build_cmd_get(Core.app, dev.nrf5340_audio_dk_dev, options.build, options.pristine, options)
|
||||
dev.hex_path_app = temp_dest_folder / "nrf5340_audio/zephyr/zephyr.hex"
|
||||
|
||||
_, temp_dest_folder, _, _, _ = __build_cmd_get(Core.net, dev.nrf5340_audio_dk_dev, options.build, options.pristine, options)
|
||||
dev.hex_path_net = temp_dest_folder / "ipc_radio/zephyr/zephyr.hex"
|
||||
|
||||
|
||||
def __finish(device_list):
|
||||
"""Finish script. Print report"""
|
||||
print("build_prog.py finished. Report:")
|
||||
__print_dev_conf(device_list)
|
||||
exit(0)
|
||||
|
||||
|
||||
def __main():
|
||||
parser = argparse.ArgumentParser(
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
description=(
|
||||
"This script builds and programs the nRF5340 "
|
||||
"Audio project on Windows and Linux"
|
||||
),
|
||||
epilog=("If there exists an environmental variable called \"AUDIO_KIT_SERIAL_NUMBERS_JSON\""
|
||||
"which contains the location of a json file,"
|
||||
"the program will use this file as a substitute for nrf5340_audio_dk_devices.json"),
|
||||
allow_abbrev=False
|
||||
)
|
||||
parser.add_argument(
|
||||
"-r",
|
||||
"--only_reboot",
|
||||
default=False,
|
||||
action="store_true",
|
||||
help="Only reboot, no building or programming",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-p",
|
||||
"--program",
|
||||
default=False,
|
||||
action="store_true",
|
||||
help="Will program and reboot nRF5340 Audio DK",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-c",
|
||||
"--core",
|
||||
type=str,
|
||||
choices=[i.name for i in Core],
|
||||
help="Select which cores to include in build",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--pristine",
|
||||
default=False,
|
||||
action="store_true",
|
||||
help="Will build cleanly"
|
||||
)
|
||||
parser.add_argument(
|
||||
"-b",
|
||||
"--build",
|
||||
required="-p" in sys.argv or "--program" in sys.argv,
|
||||
choices=[i.name for i in BuildType],
|
||||
help="Select the build type",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-d",
|
||||
"--device",
|
||||
required=("-r" in sys.argv or "--only_reboot" in sys.argv)
|
||||
or (
|
||||
("-b" in sys.argv or "--build" in sys.argv)
|
||||
and ("both" in sys.argv or "app" in sys.argv)
|
||||
),
|
||||
choices=[i.name for i in AudioDevice],
|
||||
help=(
|
||||
"nRF5340 Audio on the application core can be "
|
||||
"built for either ordinary headset "
|
||||
"(earbuds/headphone..) use or gateway (USB dongle)"
|
||||
),
|
||||
)
|
||||
parser.add_argument(
|
||||
"-s",
|
||||
"--sequential",
|
||||
action="store_true",
|
||||
dest="sequential_prog",
|
||||
default=False,
|
||||
help="Run nrfjprog sequentially instead of in parallel",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-f",
|
||||
"--recover_on_fail",
|
||||
action="store_true",
|
||||
dest="recover_on_fail",
|
||||
default=False,
|
||||
help="Recover device if programming fails",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--nrf21540",
|
||||
action="store_true",
|
||||
dest="nrf21540",
|
||||
default=False,
|
||||
help="Set when using nRF21540 for extra TX power",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-cn",
|
||||
"--custom_bt_name",
|
||||
nargs='*',
|
||||
dest="custom_bt_name",
|
||||
default=None,
|
||||
help="Use custom Bluetooth device name",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-u",
|
||||
"--user_bt_name",
|
||||
action="store_true",
|
||||
dest="user_bt_name",
|
||||
default=False,
|
||||
help="Set to generate a user specific Bluetooth device name.\
|
||||
Note that this will put the computer user name on air in clear text",
|
||||
)
|
||||
parser.add_argument(
|
||||
"-t",
|
||||
"--transport",
|
||||
required=True,
|
||||
choices=[i.name for i in Transport],
|
||||
default=Transport.unicast.name,
|
||||
help="Select the transport type",
|
||||
)
|
||||
|
||||
options = parser.parse_args(args=sys.argv[1:])
|
||||
|
||||
# Post processing for Enums
|
||||
if options.core is None:
|
||||
cores = []
|
||||
elif options.core == "both":
|
||||
cores = [Core.app, Core.net]
|
||||
else:
|
||||
cores = [Core[options.core]]
|
||||
|
||||
if options.device is None:
|
||||
devices = []
|
||||
elif options.device == "both":
|
||||
devices = [AudioDevice.gateway, AudioDevice.headset]
|
||||
else:
|
||||
devices = [AudioDevice[options.device]]
|
||||
|
||||
options.build = BuildType[options.build] if options.build else None
|
||||
|
||||
options.only_reboot = SelectFlags.TBD if options.only_reboot else SelectFlags.NOT
|
||||
|
||||
boards_snr_connected = __find_snr()
|
||||
if not boards_snr_connected:
|
||||
print("No snrs connected")
|
||||
|
||||
# Update device list
|
||||
# This JSON file should be altered by the developer.
|
||||
# Then run git update-index --skip-worktree FILENAME to avoid changes
|
||||
# being pushed
|
||||
with AUDIO_KIT_SERIAL_NUMBERS_JSON.open() as f:
|
||||
dev_arr = json.load(f)
|
||||
device_list = [
|
||||
DeviceConf(
|
||||
nrf5340_audio_dk_snr=dev["nrf5340_audio_dk_snr"],
|
||||
channel=Channel[dev["channel"]],
|
||||
snr_connected=(dev["nrf5340_audio_dk_snr"]
|
||||
in boards_snr_connected),
|
||||
recover_on_fail=options.recover_on_fail,
|
||||
nrf5340_audio_dk_dev=AudioDevice[dev["nrf5340_audio_dk_dev"]],
|
||||
cores=cores,
|
||||
devices=devices,
|
||||
_only_reboot=options.only_reboot,
|
||||
)
|
||||
for dev in dev_arr
|
||||
]
|
||||
|
||||
__print_dev_conf(device_list)
|
||||
|
||||
# Initialization step finsihed
|
||||
# Reboot step start
|
||||
|
||||
if options.only_reboot == SelectFlags.TBD:
|
||||
program_threads_run(device_list, sequential=options.sequential_prog)
|
||||
__finish(device_list)
|
||||
|
||||
# Reboot step finished
|
||||
# Build step start
|
||||
|
||||
if options.build is not None:
|
||||
print("Invoking build step")
|
||||
build_configs = []
|
||||
|
||||
if AudioDevice.headset in devices:
|
||||
for c in cores:
|
||||
build_configs.append(
|
||||
BuildConf(
|
||||
core=c,
|
||||
device=AudioDevice.headset,
|
||||
pristine=options.pristine,
|
||||
build=options.build,
|
||||
)
|
||||
)
|
||||
if AudioDevice.gateway in devices:
|
||||
for c in cores:
|
||||
build_configs.append(
|
||||
BuildConf(
|
||||
core=c,
|
||||
device=AudioDevice.gateway,
|
||||
pristine=options.pristine,
|
||||
build=options.build,
|
||||
)
|
||||
)
|
||||
|
||||
for build_cfg in build_configs:
|
||||
__build_module(build_cfg, options)
|
||||
|
||||
# Build step finished
|
||||
# Program step start
|
||||
|
||||
if options.program:
|
||||
for dev in device_list:
|
||||
if dev.snr_connected:
|
||||
__populate_hex_paths(dev, options)
|
||||
|
||||
program_threads_run(device_list, sequential=options.sequential_prog)
|
||||
|
||||
# Program step finished
|
||||
|
||||
__finish(device_list)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
__main()
|
||||
Reference in New Issue
Block a user