blob: a1da607d07d3b4109d58b126269debd9495f8f3c [file]
# Copyright (c) 2021 Project CHIP Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import logging
import os
import re
import shutil
import time
from pathlib import Path
from enum import Enum, auto
from runner.runner import Runner
from .builder import Builder, BuilderOutput, OutDirLock, lock_output_dir
from .gn import GnBuilder
log = logging.getLogger(__name__)
class BouffalolabApp(Enum):
LIGHT = auto()
CONTACT = auto()
def ExampleName(self):
if self == BouffalolabApp.LIGHT:
return 'lighting-app'
if self == BouffalolabApp.CONTACT:
return 'contact-sensor-app'
raise Exception('Unknown app type: %r' % self)
def AppNamePrefix(self, chip_name):
if self == BouffalolabApp.LIGHT:
return ('chip-%s-lighting-example' % chip_name)
if self == BouffalolabApp.CONTACT:
return ('chip-%s-contact-sensor-example' % chip_name)
raise Exception('Unknown app type: %r' % self)
class BouffalolabBoard(Enum):
BL602DK = auto()
BL616DK = auto()
BL616CLDK = auto()
BL704LDK = auto()
BL706DK = auto()
BL602_NIGHT_LIGHT = auto()
BL706_NIGHT_LIGHT = auto()
def GnArgName(self):
if self == BouffalolabBoard.BL602DK:
return 'BL602DK'
if self == BouffalolabBoard.BL616DK:
return 'BL616DK'
if self == BouffalolabBoard.BL616CLDK:
return 'BL616CLDK'
if self == BouffalolabBoard.BL704LDK:
return 'BL704LDK'
if self == BouffalolabBoard.BL706DK:
return 'BL706DK'
if self == BouffalolabBoard.BL602_NIGHT_LIGHT:
return 'BL602-NIGHT-LIGHT'
if self == BouffalolabBoard.BL706_NIGHT_LIGHT:
return 'BL706-NIGHT-LIGHT'
raise Exception('Unknown board #: %r' % self)
class BouffalolabThreadType(Enum):
NONE = auto()
THREAD_FTD = auto()
THREAD_MTD = auto()
def _AutoOtaEnabled():
value = os.environ.get("BOUFFALOLAB_AUTO_OTA", "1").strip().lower()
return value not in ("0", "false", "no", "off")
def _ProjectConfigPath(chip_root, app, chip_name):
config_dir = "bflb" if chip_name in ("bl616", "bl616cl") else chip_name
return os.path.join(chip_root, "examples", app.ExampleName(), "bouffalolab", config_dir, "CHIPProjectConfig.h")
def _RunAutoOta(builder, mode, app, chip_name, **kwargs):
if not _AutoOtaEnabled():
log.info("Bouffalo auto OTA generation disabled by BOUFFALOLAB_AUTO_OTA")
return
script = os.path.join(builder.chip_dir, "scripts", "tools", "bouffalolab", "bouffalolab_ota_image.py")
cmd = [
"python3",
script,
"--mode",
mode,
"--project-config",
_ProjectConfigPath(builder.chip_dir, app, chip_name),
]
for key, value in kwargs.items():
cmd.extend(["--%s" % key.replace("_", "-"), value])
builder._Execute(cmd, title="Generating Bouffalo Matter OTA image")
def _MatterOtaOutputs(output_dir):
ota_dir = Path(output_dir) / "ota_images"
if not ota_dir.is_dir():
return []
return sorted(ota_dir.glob("*.matter"))
class _BouffalolabGnBuilder(GnBuilder):
def __init__(self,
root: str,
runner: Runner,
output_dir_lock: OutDirLock,
app: BouffalolabApp = BouffalolabApp.LIGHT,
board: BouffalolabBoard = BouffalolabBoard.BL616DK,
enable_rpcs: bool = False,
module_type: str = "BL706C-22",
baudrate=2000000,
enable_shell: bool = False,
enable_cdc: bool = False,
enable_rotating_device_id: bool = False,
enable_mfd: bool = False,
enable_ethernet: bool = False,
enable_wifi: bool = False,
enable_thread_type: BouffalolabThreadType = BouffalolabThreadType.NONE,
enable_heap_monitoring: bool = False,
use_matter_openthread: bool = False,
enable_easyflash: bool = False,
enable_littlefs: bool = False,
enable_pds: bool = False,
enable_debug_coredump: bool = False,
):
if module_type == 'BL602':
bouffalo_chip = 'bl602'
elif module_type == 'BL704L':
bouffalo_chip = 'bl702l'
elif "BL70" in module_type:
bouffalo_chip = 'bl702'
elif module_type == "BL616":
bouffalo_chip = "bl616"
else:
raise Exception(f"module_type {module_type} is not supported")
super().__init__(
root=os.path.join(root, 'examples',
app.ExampleName(), 'bouffalolab', bouffalo_chip),
runner=runner,
output_dir_lock=output_dir_lock
)
self.argsOpt = []
self.chip_name = bouffalo_chip
self.app = app
self.board = board
toolchain = os.path.join(root, os.path.split(os.path.realpath(__file__))[0], '../../../config/bouffalolab/toolchain')
toolchain = f'custom_toolchain="{toolchain}:riscv_gcc"'
if toolchain:
self.argsOpt.append(toolchain)
self.argsOpt.append(f'board="{self.board.GnArgName()}"')
self.argsOpt.append(f'baudrate="{baudrate}"')
enable_thread = enable_thread_type != BouffalolabThreadType.NONE
if not (enable_wifi or enable_thread or enable_ethernet):
# decide default connectivity for each chip
if bouffalo_chip == "bl602":
enable_wifi, enable_thread, enable_ethernet = True, False, False
elif bouffalo_chip == "bl702":
enable_wifi, enable_thread, enable_ethernet = False, True, False
elif bouffalo_chip == "bl702l":
enable_wifi, enable_thread, enable_ethernet = False, True, False
elif bouffalo_chip == "bl616":
# contact-sensor on bl616 only supports WiFi
if enable_pds:
enable_wifi = True
else:
raise Exception("Must select one of wifi and thread to build.")
if [enable_wifi, enable_thread, enable_ethernet].count(True) > 1:
raise Exception('Currently, only one of wifi, thread and ethernet supports.')
# hardware connectivity support check
if bouffalo_chip == "bl602":
if enable_ethernet or enable_thread:
raise Exception(f"SoC {bouffalo_chip} does NOT support connectivity Ethernet/Thread.")
elif bouffalo_chip == "bl702":
self.argsOpt.append(f'module_type="{module_type}"')
if board != BouffalolabBoard.BL706DK:
if enable_ethernet or enable_wifi:
raise Exception(f"Board {self.board.GnArgName()} does NOT support connectivity Ethernet/Wi-Fi.")
elif bouffalo_chip == "bl702l":
if enable_ethernet or enable_wifi:
raise Exception(f"SoC {bouffalo_chip} does NOT support connectivity Ethernet/Wi-Fi currently.")
elif bouffalo_chip == "bl616":
sdk_path = os.path.join(root, os.path.split(os.path.realpath(__file__))[
0], '../../../third_party/bouffalolab/repo_bouffalo_sdk/VERSION')
x, y, z = self.extract_sdk_version(sdk_path)
self.argsOpt.append(f'app_ver_x={x}')
self.argsOpt.append(f'app_ver_y={y}')
self.argsOpt.append(f'app_ver_z={z}')
if enable_thread:
chip_mdns = "platform"
elif enable_ethernet or enable_wifi:
chip_mdns = "minimal"
self.argsOpt.append(f'chip_enable_ethernet={str(enable_ethernet).lower()}')
self.argsOpt.append(f'chip_enable_wifi={str(enable_wifi).lower()}')
self.argsOpt.append(f'chip_enable_thread={str(enable_thread).lower()}')
# for enable_ethernet, do not need ble for commissioning
self.argsOpt.append(f'chip_config_network_layer_ble={str(enable_wifi or enable_thread).lower()}')
self.argsOpt.append(f'chip_mdns="{chip_mdns}"')
self.argsOpt.append(f'chip_inet_config_enable_ipv4={str(enable_ethernet or enable_wifi).lower()}')
if enable_easyflash and enable_littlefs:
raise Exception("Only one of easyflash and littlefs can be enabled.")
if bouffalo_chip == "bl616":
if enable_easyflash:
raise Exception("BL616 doesn't support easyflash.")
enable_littlefs = True
else:
if not enable_easyflash and not enable_littlefs:
log.fatal('*' * 80)
log.fatal('littlefs is added to support for flash storage access.')
log.fatal('Please consider and select one of easyflash and littlefs to use.')
log.fatal('*' * 80)
raise Exception("None of easyflash and littlefs select to build.")
self.argsOpt.append(f'bouffalo_sdk_component_easyflash_enabled={"false" if enable_littlefs else "true"}')
if enable_thread:
self.argsOpt.append('chip_system_config_use_openthread_inet_endpoints=true')
self.argsOpt.append('chip_with_lwip=false')
self.argsOpt.append('openthread_project_core_config_file="openthread-core-proj-config.h"')
if enable_thread_type == BouffalolabThreadType.THREAD_FTD:
self.argsOpt.append('chip_openthread_ftd=true')
else:
self.argsOpt.append('chip_openthread_ftd=false')
if not use_matter_openthread:
if bouffalo_chip in {"bl702", "bl702l"}:
self.argsOpt.append('openthread_package_version="7e32165be"')
self.argsOpt.append(
'openthread_root="//third_party/connectedhomeip/third_party/bouffalolab/repo/components/network/thread/openthread"')
else:
self.argsOpt.append('openthread_package_version="ed6235304"')
self.argsOpt.append(
'openthread_root="//third_party/connectedhomeip/third_party/bouffalolab/repo_bouffalo_sdk/components/wireless/thread/openthread"')
if enable_cdc and enable_rpcs:
raise Exception("Bouffalo USB CDC is not supported with RPC; RPC uses UART.")
if enable_cdc:
if bouffalo_chip != "bl702":
raise Exception(f'SoC {bouffalo_chip} does NOT support USB CDC')
if enable_ethernet:
raise Exception(f'SoC {bouffalo_chip} can NOT have both of USB CDC and Ethernet functions together.')
self.argsOpt.append('enable_cdc_module=true')
if enable_rpcs:
self.argsOpt.append('import("//with_pw_rpc.gni")')
elif enable_shell:
self.argsOpt.append('chip_build_libshell=true')
if enable_rotating_device_id:
self.argsOpt.append('chip_enable_additional_data_advertising=true')
self.argsOpt.append('chip_enable_rotating_device_id=true')
if enable_mfd:
self.argsOpt.append("chip_enable_factory_data=true")
if enable_pds:
self.argsOpt.append("enable_pds=true")
self.argsOpt.append(f"enable_heap_monitoring={str(enable_heap_monitoring).lower()}")
if enable_debug_coredump:
self.argsOpt.append("enable_debug_coredump=true")
self.argsOpt.append(f"coredump_binary_id={int(time.time())}")
self.argsOpt.append("chip_generate_link_map_file=true")
try:
self.argsOpt.append('bouffalolab_sdk_root="%s"' % os.environ['BOUFFALOLAB_SDK_ROOT'])
except KeyError as err:
self.print_enviroment_error()
raise err
def print_enviroment_error(self):
log.fatal('*' * 80)
log.error('Flashtool is not installed, or environment variable BOUFFALOLAB_SDK_ROOT is not exported.')
log.fatal('\tPlease make sure Bouffalo Lab SDK installs as below:')
log.fatal('\t\t./integrations/docker/images/stage-2/chip-build-bouffalolab/setup.sh')
log.fatal('\tPlease make sure BOUFFALOLAB_SDK_ROOT exports before building as below:')
log.fatal('\t\texport BOUFFALOLAB_SDK_ROOT="your install path"')
log.fatal('*' * 80)
def extract_sdk_version(self, filepath):
pattern = r'PROJECT_SDK_VERSION\s+"([^"]+)"'
try:
with open(filepath, encoding='utf-8') as f:
content = f.read()
match = re.search(pattern, content)
if match:
ver = tuple(int(v) for v in match.group(1).strip().split("."))
if len(ver) != 3:
raise Exception('Invalid version format')
return ver
raise Exception('Invalid version format')
except Exception as err:
log.error("Failed to extract SDK version: %s", err)
return (2, 1, 0)
def GnBuildArgs(self):
args = super().GnBuildArgs()
args.extend(self.argsOpt)
return args
@lock_output_dir
def build_outputs(self):
extensions = ["out"]
if self.options.enable_link_map_file:
extensions.append("out.map")
for ext in extensions:
name = f"{self.app.AppNamePrefix(self.chip_name)}.{ext}"
yield BuilderOutput(os.path.join(self.output_dir, name), name)
for image in _MatterOtaOutputs(self.output_dir):
yield BuilderOutput(str(image), os.path.join('ota_images', image.name))
@lock_output_dir
def PreBuildCommand(self):
os.system("rm -rf {}/config".format(self.output_dir))
os.system("rm -rf {}/ota_images".format(self.output_dir))
os.system("rm -rf {}".format(os.path.join(self.output_dir, 'boot2*.bin')))
os.system("rm -rf {}".format(os.path.join(self.output_dir, '%s*' % self.app.AppNamePrefix(self.chip_name))))
@lock_output_dir
def PostBuildCommand(self):
if self.chip_name in ["bl616"]:
abs_path_fw = os.path.join(self.output_dir, self.app.AppNamePrefix(self.chip_name) + ".raw")
else:
abs_path_fw = os.path.join(self.output_dir, self.app.AppNamePrefix(self.chip_name) + ".bin")
if os.path.isfile(abs_path_fw):
target_dir = self.output_dir.replace(self.chip_dir, "").strip("/")
path_fw = os.path.join(target_dir, self.app.AppNamePrefix(self.chip_name) + ".bin")
path_flash_script = os.path.join(target_dir, self.app.AppNamePrefix(self.chip_name) + ".flash.py")
_RunAutoOta(
self,
"iot-sdk",
self.app,
self.chip_name,
flash_script=os.path.join(self.output_dir, self.app.AppNamePrefix(self.chip_name) + ".flash.py"),
)
log.info("*" * 80)
log.info("Firmware is built out at: %s", path_fw)
log.info("Command to generate ota image: ")
log.info("./%s --build-ota --vendor-id <vendor id> --product-id <product id> "
"--version <version> --version-str <version string> "
"--digest-algorithm <digest algorithm>", path_flash_script)
log.info("Command to generate and sign ota image: ")
log.info("./%s --build-ota --vendor-id <vendor id> --product-id <product id> "
"--version <version> --version-str <version string> "
"--digest-algorithm <digest algorithm> --sk <private key>", path_flash_script)
log.info("*" * 80)
def BouffalolabBuilder(root, runner,
module_type: str = "BL706C-22",
enable_wifi: bool = False,
enable_ethernet: bool = False,
enable_thread_type: BouffalolabThreadType = BouffalolabThreadType.NONE,
enable_shell: bool = False,
enable_mfd: bool = False,
enable_easyflash: bool = False,
enable_rotating_device_id: bool = False,
enable_heap_monitoring: bool = False,
enable_debug_coredump: bool = False,
app: BouffalolabApp = BouffalolabApp.LIGHT,
**kwargs):
"""Factory: BL616/BL616CL → cmake-hybrid bflb builder; all other chips → GN builder."""
if module_type in ("BL616", "BL616CL"):
if enable_easyflash:
raise Exception("BL616 bflb build does not support easyflash; use -littlefs instead.")
enable_thread = enable_thread_type != BouffalolabThreadType.NONE
enable_thread_ftd = enable_thread_type != BouffalolabThreadType.THREAD_MTD
return BouffalolabBflbBuilder(
root=root, runner=runner,
app=app,
module_type=module_type,
enable_wifi=enable_wifi,
enable_thread=enable_thread,
enable_ethernet=enable_ethernet,
enable_shell=enable_shell,
enable_mfd=enable_mfd,
enable_thread_ftd=enable_thread_ftd,
enable_rotating_device_id=enable_rotating_device_id,
enable_heap_monitoring=enable_heap_monitoring,
enable_debug_coredump=enable_debug_coredump,
)
return _BouffalolabGnBuilder(
root=root, runner=runner,
app=app,
module_type=module_type,
enable_wifi=enable_wifi,
enable_ethernet=enable_ethernet,
enable_thread_type=enable_thread_type,
enable_shell=enable_shell,
enable_mfd=enable_mfd,
enable_easyflash=enable_easyflash,
enable_rotating_device_id=enable_rotating_device_id,
enable_heap_monitoring=enable_heap_monitoring,
enable_debug_coredump=enable_debug_coredump,
**kwargs
)
class BouffalolabBflbBuilder(Builder):
"""BL616 cmake-hybrid builder for examples/lighting-app/bouffalolab/.
Wraps the Makefile-driven cmake+ninja build. Exactly one of enable_wifi,
enable_thread, enable_ethernet must be True.
Supported make variables (map 1-to-1 from Makefile):
CONFIG_WIFI / CONFIG_THREAD / CONFIG_ETHERNET — network interface
CONFIG_SHELL — Matter interactive shell
CONFIG_MFD — factory data (chip_enable_factory_data)
OT_FTD — 1=FTD (default), 0=MTD (only when CONFIG_THREAD=y)
"""
def __init__(self,
root,
runner,
app: BouffalolabApp = BouffalolabApp.LIGHT,
module_type: str = "BL616",
enable_wifi: bool = False,
enable_thread: bool = False,
enable_ethernet: bool = False,
enable_shell: bool = False,
enable_mfd: bool = True,
enable_thread_ftd: bool = True,
enable_rotating_device_id: bool = False,
enable_heap_monitoring: bool = False,
enable_debug_coredump: bool = False,
enable_pds: bool = False,
):
if app == BouffalolabApp.CONTACT and not enable_wifi:
raise Exception('contact-sensor-app bflb build only supports WiFi.')
if [enable_wifi, enable_thread, enable_ethernet].count(True) != 1:
raise Exception(
'Exactly one of wifi/thread/ethernet must be enabled for the bflb build.')
app_dir = {
BouffalolabApp.LIGHT: 'lighting-app',
BouffalolabApp.CONTACT: 'contact-sensor-app',
}[app]
bflb_dir = os.path.join(
root, 'examples', app_dir, 'bouffalolab')
super().__init__(root=bflb_dir, runner=runner)
self.app = app
self.chip_name = module_type.lower()
self.board_name = {
'bl616': 'bl616dk',
'bl616cl': 'bl616cldk',
}.get(self.chip_name, "%sdk" % self.chip_name)
self.enable_wifi = enable_wifi
self.enable_thread = enable_thread
self.enable_ethernet = enable_ethernet
self.enable_shell = enable_shell
self.enable_mfd = enable_mfd
self.enable_thread_ftd = enable_thread_ftd
self.enable_rotating_device_id = enable_rotating_device_id
self.enable_heap_monitoring = enable_heap_monitoring
self.enable_debug_coredump = enable_debug_coredump
def _make_args(self):
args = [
'CHIP=%s' % self.chip_name,
'BOARD=%s' % self.board_name,
'CROSS_COMPILE=%s' % self._cross_compile_prefix(),
'CONFIG_WIFI=%s' % ('y' if self.enable_wifi else 'n'),
'CONFIG_THREAD=%s' % ('y' if self.enable_thread else 'n'),
'CONFIG_ETHERNET=%s' % ('y' if self.enable_ethernet else 'n'),
'CONFIG_SHELL=%s' % ('y' if self.enable_shell else 'n'),
'CONFIG_MFD=%s' % ('y' if self.enable_mfd else 'n'),
'CONFIG_CHIP_ROTATING_DEVICE_ID=%s' % ('y' if self.enable_rotating_device_id else 'n'),
'CONFIG_CHIP_HEAP_MONITOR=%s' % ('y' if self.enable_heap_monitoring else 'n'),
'CONFIG_COREDUMP=%s' % ('y' if self.enable_debug_coredump else 'n'),
]
if self.enable_thread and not self.enable_thread_ftd:
args.append('OT_FTD=0')
return args
def _cross_compile_prefix(self):
sdk_root = os.environ.get('BOUFFALOLAB_SDK_ROOT')
prefixes = []
if sdk_root:
prefixes.extend([
os.path.join(sdk_root, 'toolchain', 't-head-riscv', 'gcc_t-head_v2.6.1', 'bin', 'riscv64-unknown-elf-'),
os.path.join(sdk_root, 'toolchain', 'riscv', 'Linux', 'bin', 'riscv64-unknown-elf-'),
])
for prefix in prefixes:
if os.path.isfile(prefix + 'gcc'):
return prefix
return 'riscv64-unknown-elf-'
def _toolchain_path(self):
prefix = self._cross_compile_prefix()
if os.path.isabs(prefix):
toolchain_bin = os.path.dirname(prefix.rstrip(os.sep))
return '%s%s%s' % (toolchain_bin, os.pathsep, os.environ.get('PATH', ''))
return os.environ.get('PATH', '')
def _build_path(self):
base_path = self._toolchain_path()
ninja_path = shutil.which('ninja', path=base_path)
if not ninja_path:
return base_path
tools_dir = os.path.join(self.output_dir, 'tools')
os.makedirs(tools_dir, exist_ok=True)
wrapper_path = os.path.join(tools_dir, 'ninja')
with open(wrapper_path, 'w') as wrapper:
wrapper.write('#!/bin/sh\n')
wrapper.write('unset MAKEFLAGS\n')
wrapper.write('exec "%s" "$@"\n' % ninja_path)
os.chmod(wrapper_path, 0o755)
return '%s%s%s' % (tools_dir, os.pathsep, base_path)
def _sdk_build_dir(self):
return os.path.join('build', self.identifier)
def generate(self):
# cmake configuration is invoked by the Makefile; no separate step needed.
pass
def _build(self):
# The runner runs from the Matter repo root. -C self.root changes to
# examples/lighting-app/bouffalolab/ where $(abspath .) evaluates correctly.
# BUILD_DIR is target-specific and relative to that dir:
# cmake binary dir = examples/<app>/bouffalolab/build/<target>/
# SDK output dir = examples/<app>/bouffalolab/build/<target>/build_out/
# self.output_dir (set by the framework) is out/<target> and is used in
# _post_build() for symlinks so the output layout matches GN builds.
build_dir = self._sdk_build_dir()
stale_shared_build_dir = os.path.join(self.root, 'build', 'build_out')
if os.path.isdir(stale_shared_build_dir):
shutil.rmtree(stale_shared_build_dir)
log.info('Building %s cmake-hybrid bflb at %s', self.chip_name, self.root)
self._Execute(
['env', 'PATH=%s' % self._build_path(),
'make', '-C', self.root, 'BUILD_DIR=%s' % build_dir] + self._make_args(),
title='Building %s bflb %s' % (self.chip_name, self.app.ExampleName()),
)
self._post_build()
def _post_build(self):
"""Symlink SDK outputs into self.output_dir (out/<target>) with GN-style
names, then generate chip-<chip>-<app>.flash.py next to them.
"""
chip_name = self.chip_name
sdk_proj_name = {
BouffalolabApp.LIGHT: 'chip-bflb-lighting-example',
BouffalolabApp.CONTACT: 'chip-bflb-contact-sensor-example',
}[self.app]
# SDK produces: self.root/<build_dir>/build_out/<proj_name>_<chip>.{bin,elf}
sdk_out = os.path.join(self.root, self._sdk_build_dir(), 'build_out')
sdk_bin = os.path.join(sdk_out, '%s_%s.bin' % (sdk_proj_name, chip_name))
if not os.path.isfile(sdk_bin):
return
# GN-style name: chip-<chip>-<app-example>.{bin,elf}
app_prefix = self.app.AppNamePrefix(chip_name)
# Create symlinks in self.output_dir (out/<target>) so copy-artifacts
# and users find GN-consistent names alongside the GN builder layout.
os.makedirs(self.output_dir, exist_ok=True)
for ext in ('bin', 'elf'):
gn_name = '%s.%s' % (app_prefix, ext)
gn_link = os.path.join(self.output_dir, gn_name)
sdk_file = os.path.join(sdk_out, '%s_%s.%s' % (sdk_proj_name, chip_name, ext))
try:
if os.path.islink(gn_link) or os.path.isfile(gn_link):
os.remove(gn_link)
os.symlink(sdk_file, gn_link)
except OSError:
pass
# Generate flash.py that references the GN-style bin name.
matter_root = os.path.dirname(os.path.dirname(os.path.dirname(self.root)))
gen_script = os.path.join(matter_root, 'scripts', 'flashing', 'gen_flashing_script.py')
flash_py_name = '%s.flash.py' % app_prefix
flash_py_path = os.path.join(self.output_dir, flash_py_name)
flash_args = [
'python3', gen_script, 'bouffalolab',
'--chipname', chip_name,
'--baudrate', '2000000',
'--application', os.path.join(self.output_dir, '%s.bin' % app_prefix),
'--output', flash_py_path,
]
if chip_name in ('bl616', 'bl616cl'):
config_dir = os.path.join(self.output_dir, 'config')
board_config = {
'bl616': ('bl_factory_params_IoTKitA_auto.dts', 'boot2_bl616_isp_release_v8.1.8.bin'),
'bl616cl': ('bl_factory_params_IoTKitA_auto.dts', 'boot2_bl616cl_isp_release_v8.2.1.bin'),
}[chip_name]
flash_args.extend([
'--config', os.path.join(self.output_dir, 'flash_prog_cfg.ini'),
'--pt', os.path.join(config_dir, 'partition_cfg_4M.toml'),
'--dts', os.path.join(config_dir, board_config[0]),
'--boot2', os.path.join(config_dir, board_config[1]),
])
self._Execute(flash_args, title='Generating flash.py wrapper')
flashing_dir = os.path.join(matter_root, 'scripts', 'flashing')
for runtime in ('bouffalolab_firmware_utils.py', 'firmware_utils.py'):
shutil.copy2(os.path.join(flashing_dir, runtime), self.output_dir)
bl616_config = {
'bl616': ('bl616dk', 'boot2_bl616_isp_release_v8.1.8.bin'),
'bl616cl': ('bl616cldk', 'boot2_bl616cl_isp_release_v8.2.1.bin'),
}
if chip_name in bl616_config:
board_name, boot2_name = bl616_config[chip_name]
config_dir = os.path.join(self.output_dir, 'config')
os.makedirs(config_dir, exist_ok=True)
board_config_dir = os.path.join(
matter_root, 'third_party', 'bouffalolab', 'repo_bouffalo_sdk', 'bsp', 'board', board_name, 'config')
shutil.copy2(
os.path.join(matter_root, 'examples', 'platform', 'bouffalolab', 'bflb', 'flash_config',
'partition_cfg_4M.toml'),
config_dir)
for config_file in ('bl_factory_params_IoTKitA_auto.dts', boot2_name):
shutil.copy2(os.path.join(board_config_dir, config_file), config_dir)
rel = os.path.relpath(flash_py_path, matter_root)
gn_bin_rel = os.path.relpath(os.path.join(self.output_dir, '%s.bin' % app_prefix), matter_root)
log.info('*' * 80)
log.info('Firmware: %s', gn_bin_rel)
log.info('Flash script: %s', rel)
log.info('Flash to device: python3 %s --port /dev/ttyUSB0', rel)
log.info('*' * 80)
sdk_ota_dir = os.path.join(self.root, self._sdk_build_dir(), 'build_out', 'ota_images')
if os.path.isdir(sdk_ota_dir):
out_ota_dir = os.path.join(self.output_dir, 'ota_images')
if os.path.isdir(out_ota_dir):
shutil.rmtree(out_ota_dir)
os.makedirs(out_ota_dir, exist_ok=True)
for image in sorted(Path(sdk_ota_dir).glob("*.matter")):
target = os.path.join(out_ota_dir, os.path.basename(image))
try:
if os.path.islink(target) or os.path.isfile(target):
os.remove(target)
os.symlink(image, target)
except OSError:
shutil.copy2(image, target)
def build_outputs(self):
# Yield GN-consistent names from self.output_dir (out/<target>).
# Symlinks are created in _post_build() so these files always exist.
chip_name = self.chip_name
app_prefix = self.app.AppNamePrefix(chip_name)
for ext in ('bin', 'elf'):
name = '%s.%s' % (app_prefix, ext)
yield BuilderOutput(os.path.join(self.output_dir, name), name)
for image in _MatterOtaOutputs(self.output_dir):
yield BuilderOutput(str(image), os.path.join('ota_images', image.name))