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()
|
||||
96
tools/buildprog/fw_info_data.py
Normal file
96
tools/buildprog/fw_info_data.py
Normal file
@@ -0,0 +1,96 @@
|
||||
#
|
||||
# Copyright (c) 2022 Nordic Semiconductor ASA
|
||||
#
|
||||
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
|
||||
"""
|
||||
Generate fw_info for B0N container from .config
|
||||
"""
|
||||
|
||||
from intelhex import IntelHex
|
||||
|
||||
import argparse
|
||||
import struct
|
||||
|
||||
|
||||
def get_fw_info(input_hex, offset, magic_value, fw_version, fw_valid_val):
|
||||
# 0x0c start of fw_info_total_size
|
||||
# 0x10 start of flash_used
|
||||
# 0x14 start of fw_version
|
||||
# 0x18 the address of the start of the image
|
||||
# 0x1c the address of the boot point (vector table) of the firmware
|
||||
# 0x20 the address Value that can be modified to invalidate the firmware
|
||||
|
||||
fw_info_bytes = magic_value
|
||||
for i in range(0xc, 0x14):
|
||||
fw_info_bytes += input_hex[offset + i].to_bytes(1, byteorder='little')
|
||||
fw_info_bytes += struct.pack('<I', fw_version)
|
||||
for i in range(0x18, 0x20):
|
||||
fw_info_bytes += input_hex[offset + i].to_bytes(1, byteorder='little')
|
||||
fw_info_bytes += fw_valid_val
|
||||
return fw_info_bytes
|
||||
|
||||
|
||||
def inject_fw_info(input_file, offset, output_hex, magic_value, fw_version, fw_valid_val):
|
||||
ih = IntelHex(input_file)
|
||||
# OBJCOPY incorrectly inserts x86 specific records, remove the start_addr as it is wrong.
|
||||
ih.start_addr = None
|
||||
|
||||
# Parse comma-separated string of uint32s into hex string. Each is encoded in little-endian byte order
|
||||
parsed_magic_value = b''.join(
|
||||
[struct.pack('<I', int(m, 0)) for m in magic_value.split(',')])
|
||||
# Parse string of uint32s into hex string. Each is encoded in little-endian byte order
|
||||
parsed_fw_valid_val = struct.pack('<I', fw_valid_val)
|
||||
parsed_fw_version = '0x%08X' % fw_version
|
||||
print(parsed_fw_version)
|
||||
fw_info_data = get_fw_info(input_hex=ih,
|
||||
offset=offset,
|
||||
magic_value=parsed_magic_value,
|
||||
fw_version=fw_version,
|
||||
fw_valid_val=parsed_fw_valid_val)
|
||||
fw_info_data_data_hex = IntelHex()
|
||||
|
||||
fw_info_data_data_hex.frombytes(fw_info_data, offset)
|
||||
ih.merge(fw_info_data_data_hex, overlap='replace')
|
||||
ih.write_hex_file(output_hex)
|
||||
|
||||
|
||||
def parse_args():
|
||||
parser = argparse.ArgumentParser(
|
||||
description='Inject fw info metadata at specified offset. Generate HEX file',
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
allow_abbrev=False)
|
||||
|
||||
parser.add_argument('-i', '--input', required=True, type=argparse.FileType('r', encoding='UTF-8'),
|
||||
help='Input hex file.')
|
||||
parser.add_argument('--offset', required=True, type=lambda x: int(x, 0),
|
||||
help='Offset to store validation metadata at.', default=0x01008A00)
|
||||
parser.add_argument('-m', '--magic-value', required=True,
|
||||
help='ASCII representation of magic value.')
|
||||
parser.add_argument('-v', '--fw-version', required=True, type=int,
|
||||
help='Fw version.')
|
||||
parser.add_argument('-l', '--fw-valid-val', required=True, type=lambda x: int(x, 0),
|
||||
help='ASCII representation of fw valid val.')
|
||||
parser.add_argument('-o', '--output-hex', required=False, default=None, type=argparse.FileType('w'),
|
||||
help='.hex output file name. Default is to overwrite --input.')
|
||||
|
||||
args = parser.parse_args()
|
||||
if args.output_hex is None:
|
||||
args.output_hex = args.input
|
||||
return args
|
||||
|
||||
|
||||
def main():
|
||||
|
||||
args = parse_args()
|
||||
|
||||
inject_fw_info(input_file=args.input,
|
||||
offset=args.offset,
|
||||
output_hex=args.output_hex,
|
||||
magic_value=args.magic_value,
|
||||
fw_version=args.fw_version,
|
||||
fw_valid_val=args.fw_valid_val)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
17
tools/buildprog/nrf5340_audio_dk_devices.json
Normal file
17
tools/buildprog/nrf5340_audio_dk_devices.json
Normal file
@@ -0,0 +1,17 @@
|
||||
[
|
||||
{
|
||||
"nrf5340_audio_dk_snr": 1000,
|
||||
"nrf5340_audio_dk_dev": "headset",
|
||||
"channel": "left"
|
||||
},
|
||||
{
|
||||
"nrf5340_audio_dk_snr": 1000,
|
||||
"nrf5340_audio_dk_dev": "gateway",
|
||||
"channel": "NA"
|
||||
},
|
||||
{
|
||||
"nrf5340_audio_dk_snr": 1000,
|
||||
"nrf5340_audio_dk_dev": "headset",
|
||||
"channel": "right"
|
||||
}
|
||||
]
|
||||
107
tools/buildprog/nrf5340_audio_dk_devices.py
Normal file
107
tools/buildprog/nrf5340_audio_dk_devices.py
Normal file
@@ -0,0 +1,107 @@
|
||||
#
|
||||
# Copyright (c) 2018 Nordic Semiconductor ASA
|
||||
#
|
||||
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
#
|
||||
|
||||
"""
|
||||
Settings for building and flashing nRF5340 Audio DK for different targets.
|
||||
"""
|
||||
from dataclasses import InitVar, dataclass, field
|
||||
from enum import auto, Enum
|
||||
from pathlib import Path
|
||||
from typing import List
|
||||
|
||||
|
||||
class SelectFlags(str, Enum):
|
||||
"""Holds the available status flags"""
|
||||
NOT = "Not selected"
|
||||
TBD = "Selected"
|
||||
DONE = "Done"
|
||||
FAIL = "Failed"
|
||||
|
||||
|
||||
class Core(str, Enum):
|
||||
"""SoC core"""
|
||||
app = "app"
|
||||
net = "net"
|
||||
both = "both"
|
||||
|
||||
|
||||
class AudioDevice(str, Enum):
|
||||
"""Audio device"""
|
||||
headset = "headset"
|
||||
gateway = "gateway"
|
||||
both = "both"
|
||||
|
||||
|
||||
class BuildType(str, Enum):
|
||||
"""Release or debug build"""
|
||||
release = "release"
|
||||
debug = "debug"
|
||||
|
||||
|
||||
class Channel(Enum):
|
||||
"""Left or right Value represents UICR channel"""
|
||||
left = 0
|
||||
right = 1
|
||||
NA = auto()
|
||||
|
||||
class Transport(str, Enum):
|
||||
"""Transport type"""
|
||||
broadcast = "broadcast"
|
||||
unicast = "unicast"
|
||||
|
||||
|
||||
@dataclass
|
||||
class DeviceConf:
|
||||
"""This config is populated according to connected SEGGER serial numbers
|
||||
(snr) and command line arguments"""
|
||||
|
||||
# Constructor variables
|
||||
nrf5340_audio_dk_snr: int
|
||||
channel: Channel
|
||||
snr_connected: bool
|
||||
nrf5340_audio_dk_dev: AudioDevice
|
||||
recover_on_fail: bool
|
||||
|
||||
cores: InitVar[List[Core]]
|
||||
devices: InitVar[List[AudioDevice]]
|
||||
_only_reboot: InitVar[SelectFlags]
|
||||
# Post init variables
|
||||
only_reboot: SelectFlags = field(init=False, default=SelectFlags.NOT)
|
||||
hex_path_app: Path = field(init=False, default=None)
|
||||
core_app_programmed: SelectFlags = field(
|
||||
init=False, default=SelectFlags.NOT)
|
||||
hex_path_net: Path = field(init=False, default=None)
|
||||
core_net_programmed: SelectFlags = field(
|
||||
init=False, default=SelectFlags.NOT)
|
||||
|
||||
def __post_init__(
|
||||
self, cores: List[Core], devices: List[AudioDevice], _only_reboot: SelectFlags,
|
||||
):
|
||||
device_selected = self.nrf5340_audio_dk_dev in devices
|
||||
self.only_reboot = _only_reboot if device_selected else SelectFlags.NOT
|
||||
if self.only_reboot == SelectFlags.TBD:
|
||||
return
|
||||
|
||||
if (Core.app in cores) and device_selected:
|
||||
self.core_app_programmed = SelectFlags.TBD
|
||||
if (Core.net in cores) and device_selected:
|
||||
self.core_net_programmed = SelectFlags.TBD
|
||||
|
||||
def __str__(self):
|
||||
result = f"{self.nrf5340_audio_dk_snr} {self.nrf5340_audio_dk_dev.name}"
|
||||
if self.nrf5340_audio_dk_dev == AudioDevice.headset:
|
||||
result += f" {self.channel.name}"
|
||||
return result
|
||||
|
||||
|
||||
@dataclass
|
||||
class BuildConf:
|
||||
"""Build config"""
|
||||
|
||||
core: Core
|
||||
device: AudioDevice
|
||||
build: BuildType
|
||||
pristine: bool
|
||||
135
tools/buildprog/program.py
Normal file
135
tools/buildprog/program.py
Normal file
@@ -0,0 +1,135 @@
|
||||
#
|
||||
# Copyright (c) 2018 Nordic Semiconductor ASA
|
||||
#
|
||||
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
#
|
||||
|
||||
""" Tools to program multiple nRF5340 Audio DKs """
|
||||
|
||||
from threading import Thread
|
||||
from os import system, path
|
||||
from typing import List
|
||||
from nrf5340_audio_dk_devices import DeviceConf, SelectFlags, AudioDevice
|
||||
|
||||
MEM_ADDR_UICR_SNR = 0x00FF80F0
|
||||
MEM_ADDR_UICR_CH = 0x00FF80F4
|
||||
|
||||
|
||||
def __populate_uicr(dev):
|
||||
"""Program UICR in device with information from JSON file"""
|
||||
if dev.nrf5340_audio_dk_dev == AudioDevice.headset:
|
||||
cmd = (f"nrfjprog --memwr {MEM_ADDR_UICR_CH} --val {dev.channel.value} "
|
||||
f"--snr {dev.nrf5340_audio_dk_snr}")
|
||||
# Write channel information to UICR
|
||||
print("Programming UICR")
|
||||
ret_val = system(cmd)
|
||||
|
||||
if ret_val:
|
||||
return False
|
||||
|
||||
cmd = (f"nrfjprog --memwr {MEM_ADDR_UICR_SNR} --val {dev.nrf5340_audio_dk_snr} "
|
||||
f"--snr {dev.nrf5340_audio_dk_snr}")
|
||||
|
||||
# Write segger nr to UICR
|
||||
ret_val = system(cmd)
|
||||
if ret_val:
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
|
||||
def _program_cores(dev: DeviceConf) -> int:
|
||||
if dev.core_net_programmed == SelectFlags.TBD:
|
||||
if not path.isfile(dev.hex_path_net):
|
||||
print(f"NET core hex not found. Built only for APP core. {dev.hex_path_net}")
|
||||
else:
|
||||
print(f"Programming net core on: {dev}")
|
||||
cmd = (f"nrfjprog --program {dev.hex_path_net} -f NRF53 -q "
|
||||
f"--snr {dev.nrf5340_audio_dk_snr} --sectorerase --coprocessor CP_NETWORK")
|
||||
ret_val = system(cmd)
|
||||
if ret_val != 0:
|
||||
if not dev.recover_on_fail:
|
||||
dev.core_net_programmed = SelectFlags.FAIL
|
||||
return ret_val
|
||||
else:
|
||||
dev.core_net_programmed = SelectFlags.DONE
|
||||
|
||||
if dev.core_app_programmed == SelectFlags.TBD:
|
||||
if not path.isfile(dev.hex_path_app):
|
||||
print(f"APP core hex not found. Built only for NET core. {dev.hex_path_app}")
|
||||
return 1
|
||||
else:
|
||||
print(f"Programming app core on: {dev}")
|
||||
cmd = (f"nrfjprog --program {dev.hex_path_app} -f NRF53 -q "
|
||||
f"--snr {dev.nrf5340_audio_dk_snr} --chiperase --coprocessor CP_APPLICATION")
|
||||
ret_val = system(cmd)
|
||||
if ret_val != 0:
|
||||
if not dev.recover_on_fail:
|
||||
dev.core_app_programmed = SelectFlags.FAIL
|
||||
return ret_val
|
||||
else:
|
||||
dev.core_app_programmed = SelectFlags.DONE
|
||||
|
||||
# Populate UICR data matching the JSON file
|
||||
if not __populate_uicr(dev):
|
||||
dev.core_app_programmed = SelectFlags.FAIL
|
||||
return 1
|
||||
|
||||
if dev.core_net_programmed != SelectFlags.NOT or dev.core_app_programmed != SelectFlags.NOT:
|
||||
print(f"Resetting {dev}")
|
||||
cmd = f"nrfjprog -r --snr {dev.nrf5340_audio_dk_snr}"
|
||||
ret_val = system(cmd)
|
||||
if ret_val != 0:
|
||||
return ret_val
|
||||
return 0
|
||||
|
||||
|
||||
def _recover(dev: DeviceConf):
|
||||
print(f"Recovering device: {dev}")
|
||||
ret_val = system(
|
||||
f"nrfjprog --recover --coprocessor CP_NETWORK --snr {dev.nrf5340_audio_dk_snr}"
|
||||
)
|
||||
if ret_val != 0:
|
||||
dev.core_net_programmed = SelectFlags.FAIL
|
||||
|
||||
ret_val = system(
|
||||
f"nrfjprog --recover --coprocessor CP_APPLICATION --snr {dev.nrf5340_audio_dk_snr}"
|
||||
)
|
||||
if ret_val != 0:
|
||||
dev.core_app_programmed = SelectFlags.FAIL
|
||||
|
||||
|
||||
def __program_thread(dev: DeviceConf):
|
||||
if dev.only_reboot == SelectFlags.TBD:
|
||||
print(f"Resetting {dev}")
|
||||
cmd = f"nrfjprog -r --snr {dev.nrf5340_audio_dk_snr}"
|
||||
ret_val = system(cmd)
|
||||
dev.only_reboot = SelectFlags.FAIL if ret_val else SelectFlags.DONE
|
||||
return
|
||||
|
||||
return_code = _program_cores(dev)
|
||||
if return_code != 0 and dev.recover_on_fail:
|
||||
_recover(dev)
|
||||
_program_cores(dev)
|
||||
|
||||
|
||||
def program_threads_run(devices_list: List[DeviceConf], sequential: bool = False):
|
||||
"""Program devices in parallel"""
|
||||
threads = []
|
||||
# First program net cores if applicable
|
||||
for dev in devices_list:
|
||||
if not dev.snr_connected:
|
||||
dev.only_reboot = SelectFlags.NOT
|
||||
dev.core_app_programmed = SelectFlags.NOT
|
||||
dev.core_net_programmed = SelectFlags.NOT
|
||||
continue
|
||||
thread = Thread(target=__program_thread, args=(dev,))
|
||||
threads.append(thread)
|
||||
thread.start()
|
||||
if sequential:
|
||||
thread.join()
|
||||
|
||||
for thread in threads:
|
||||
thread.join()
|
||||
|
||||
threads.clear()
|
||||
28
tools/uart_terminal/scripts/get_serial_ports.py
Normal file
28
tools/uart_terminal/scripts/get_serial_ports.py
Normal file
@@ -0,0 +1,28 @@
|
||||
#
|
||||
# Copyright (c) 2022 Nordic Semiconductor ASA
|
||||
#
|
||||
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
#
|
||||
|
||||
import sys
|
||||
import subprocess
|
||||
|
||||
def get_serial_ports():
|
||||
nrfjprog_com = subprocess.Popen(["nrfjprog", "--com"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
nrfjprog_com.wait()
|
||||
|
||||
if nrfjprog_com.returncode != 0:
|
||||
sys.exit("'nrfjprog --com' failed")
|
||||
|
||||
output = nrfjprog_com.communicate()
|
||||
output_decoded = output[0].decode()
|
||||
output_decoded_lines = output_decoded.splitlines()
|
||||
|
||||
ports = list()
|
||||
|
||||
for line in output_decoded_lines:
|
||||
if "VCOM0" in line:
|
||||
info = line.split(" ")
|
||||
ports.append(info[1])
|
||||
|
||||
return ports
|
||||
62
tools/uart_terminal/scripts/linux_terminator_config
Normal file
62
tools/uart_terminal/scripts/linux_terminator_config
Normal file
@@ -0,0 +1,62 @@
|
||||
[global_config]
|
||||
suppress_multiple_term_dialog = True
|
||||
[keybindings]
|
||||
[profiles]
|
||||
[[default]]
|
||||
cursor_color = "#aaaaaa"
|
||||
scrollback_infinite = True
|
||||
[layouts]
|
||||
[[default]]
|
||||
[[[child0]]]
|
||||
type = Window
|
||||
parent = ""
|
||||
order = 0
|
||||
position = 72:35
|
||||
maximised = False
|
||||
fullscreen = False
|
||||
size = 2000, 1000
|
||||
title = nRF5340 Audio DK
|
||||
last_active_window = True
|
||||
[[[child1]]]
|
||||
type = VPaned
|
||||
parent = child0
|
||||
order = 0
|
||||
position = 540
|
||||
ratio = 0.5
|
||||
[[[child2]]]
|
||||
type = HPaned
|
||||
parent = child1
|
||||
order = 0
|
||||
position = 600
|
||||
ratio = 0.5
|
||||
[[[terminal3]]]
|
||||
type = Terminal
|
||||
parent = child2
|
||||
order = 0
|
||||
profile = default
|
||||
command = python3 scripts/open_terminator.py 0; sh
|
||||
[[[terminal4]]]
|
||||
type = Terminal
|
||||
parent = child2
|
||||
order = 1
|
||||
profile = default
|
||||
command = python3 scripts/open_terminator.py 1; sh
|
||||
[[[child5]]]
|
||||
type = HPaned
|
||||
parent = child1
|
||||
order = 1
|
||||
position = 600
|
||||
ratio = 0.5
|
||||
[[[terminal6]]]
|
||||
type = Terminal
|
||||
parent = child5
|
||||
order = 0
|
||||
profile = default
|
||||
command = python3 scripts/open_terminator.py 2; sh
|
||||
[[[terminal7]]]
|
||||
type = Terminal
|
||||
parent = child5
|
||||
order = 1
|
||||
profile = default
|
||||
command = echo Available ttyACM devices: && cd /dev/ && ls -l | grep "ttyACM"; bash
|
||||
[plugins]
|
||||
15
tools/uart_terminal/scripts/open_putty.py
Normal file
15
tools/uart_terminal/scripts/open_putty.py
Normal file
@@ -0,0 +1,15 @@
|
||||
#
|
||||
# Copyright (c) 2022 Nordic Semiconductor ASA
|
||||
#
|
||||
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
#
|
||||
|
||||
import subprocess
|
||||
from get_serial_ports import get_serial_ports
|
||||
|
||||
|
||||
def open_putty():
|
||||
ports = get_serial_ports()
|
||||
|
||||
for port in ports:
|
||||
subprocess.Popen("putty -serial " + port + " -sercfg 115200,8,n,1,N")
|
||||
16
tools/uart_terminal/scripts/open_terminator.py
Normal file
16
tools/uart_terminal/scripts/open_terminator.py
Normal file
@@ -0,0 +1,16 @@
|
||||
#
|
||||
# Copyright (c) 2022 Nordic Semiconductor ASA
|
||||
#
|
||||
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
#
|
||||
|
||||
import sys
|
||||
import subprocess
|
||||
from get_serial_ports import get_serial_ports
|
||||
|
||||
ports = get_serial_ports()
|
||||
|
||||
if int(sys.argv[1]) < len(ports):
|
||||
subprocess.Popen(["minicom", "--color=on", "-b 115200", "-8", "-D " + ports[int(sys.argv[1])]])
|
||||
else:
|
||||
print("Not enough boards connected")
|
||||
19
tools/uart_terminal/uart_terminal.py
Normal file
19
tools/uart_terminal/uart_terminal.py
Normal file
@@ -0,0 +1,19 @@
|
||||
#
|
||||
# Copyright (c) 2022 Nordic Semiconductor ASA
|
||||
#
|
||||
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
|
||||
#
|
||||
|
||||
import sys
|
||||
import subprocess
|
||||
|
||||
sys.path.append("./scripts")
|
||||
|
||||
from open_putty import open_putty
|
||||
|
||||
if sys.platform == "linux":
|
||||
terminator = subprocess.Popen(["terminator", "--config=scripts/linux_terminator_config"], stderr=subprocess.PIPE)
|
||||
elif sys.platform == "win32":
|
||||
open_putty()
|
||||
else:
|
||||
print("OS not supported")
|
||||
Reference in New Issue
Block a user