blob: 4e92ae134eec8c6c801c8f6ab7ed53b2a74eba90 [file] [log] [blame]
# Copyright (c) 2021-2025 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 importlib.util
import logging
import os
from enum import Enum, auto
from .builder import BuilderOutput
from .gn import GnBuilder
class NxpOsUsed(Enum):
FREERTOS = auto()
ZEPHYR = auto()
def OsEnv(self):
if self == NxpOsUsed.ZEPHYR:
return 'zephyr'
elif self == NxpOsUsed.FREERTOS:
return 'freertos'
else:
raise Exception('Unknown OS type: %r' % self)
class NxpBuildSystem(Enum):
GN = auto()
CMAKE = auto()
def BuildSystem(self):
if self == NxpBuildSystem.GN:
return 'gn'
elif self == NxpBuildSystem.CMAKE:
return 'cmake'
else:
raise Exception('Unknown build system: %r' % self)
class NxpBoard(Enum):
RT1060 = auto()
RT1170 = auto()
RW61X = auto()
MCXW71 = auto()
MCXW72 = auto()
def Name(self, os_env):
if self == NxpBoard.RT1060:
return 'rt1060'
elif self == NxpBoard.RT1170:
return 'rt1170'
elif self == NxpBoard.RW61X:
if os_env == NxpOsUsed.ZEPHYR:
return 'frdm_rw612'
else:
return 'rw61x'
elif self == NxpBoard.MCXW71:
return 'mcxw71'
elif self == NxpBoard.MCXW72:
return 'mcxw72'
else:
raise Exception('Unknown board type: %r' % self)
def FolderName(self, os_env):
if self == NxpBoard.RT1060:
return 'rt/rt1060'
elif self == NxpBoard.RT1170:
return 'rt/rt1170'
elif self == NxpBoard.RW61X:
if os_env == NxpOsUsed.ZEPHYR:
return 'zephyr'
else:
return 'rt/rw61x'
elif self == NxpBoard.MCXW71:
return 'mcxw71'
elif self == NxpBoard.MCXW72:
return 'mcxw72'
else:
raise Exception('Unknown board type: %r' % self)
class NxpBoardVariant(Enum):
FRDM = auto()
EVKC = auto()
EVKB = auto()
class NxpApp(Enum):
LIGHTING = auto()
CONTACT = auto()
ALLCLUSTERS = auto()
LAUNDRYWASHER = auto()
THERMOSTAT = auto()
LOCK_APP = auto()
def ExampleName(self):
if self == NxpApp.LIGHTING:
return 'lighting-app'
elif self == NxpApp.CONTACT:
return "contact-sensor-app"
elif self == NxpApp.ALLCLUSTERS:
return "all-clusters-app"
elif self == NxpApp.LAUNDRYWASHER:
return "laundry-washer-app"
elif self == NxpApp.THERMOSTAT:
return "thermostat"
elif self == NxpApp.LOCK_APP:
return "lock-app"
else:
raise Exception('Unknown app type: %r' % self)
def NameSuffix(self):
if self == NxpApp.LIGHTING:
return 'light-example'
elif self == NxpApp.CONTACT:
return 'contact-example'
elif self == NxpApp.ALLCLUSTERS:
return "all-cluster-example"
elif self == NxpApp.LAUNDRYWASHER:
return "laundry-washer-example"
elif self == NxpApp.THERMOSTAT:
return "thermostat-example"
elif self == NxpApp.LOCK_APP:
return "lock-example"
else:
raise Exception('Unknown app type: %r' % self)
def BuildRoot(self, root, board, os_env, build_system):
if ((os_env == NxpOsUsed.FREERTOS) and (build_system == NxpBuildSystem.CMAKE)):
return os.path.join(root, 'examples', self.ExampleName(), 'nxp')
else:
return os.path.join(root, 'examples', self.ExampleName(), 'nxp', board.FolderName(os_env))
class NxpLogLevel(Enum):
DEFAULT = auto() # default everything
ALL = auto() # enable all logging
PROGRESS = auto() # progress and above
ERROR = auto() # error and above
NONE = auto() # no chip_logging at all
class NxpBuilder(GnBuilder):
def __init__(self,
root,
runner,
app: NxpApp = NxpApp.LIGHTING,
board: NxpBoard = NxpBoard.MCXW71,
board_variant: NxpBoardVariant = None,
os_env: NxpOsUsed = NxpOsUsed.FREERTOS,
build_system: NxpBuildSystem = NxpBuildSystem.GN,
low_power: bool = False,
smu2: bool = False,
enable_factory_data: bool = False,
convert_dac_pk: bool = False,
enable_lit: bool = False,
enable_rotating_id: bool = False,
has_sw_version_2: bool = False,
disable_ble: bool = False,
enable_thread: bool = False,
enable_wifi: bool = False,
enable_ethernet: bool = False,
enable_shell: bool = False,
enable_ota: bool = False,
enable_factory_data_build: bool = False,
enable_mtd: bool = False,
disable_pairing_autostart: bool = False,
iw416_transceiver: bool = False,
w8801_transceiver: bool = False,
iwx12_transceiver: bool = False,
iw610_transceiver: bool = False,
se05x_enable: bool = False,
log_level: NxpLogLevel = NxpLogLevel.DEFAULT,
):
super(NxpBuilder, self).__init__(
root=app.BuildRoot(root, board, os_env, build_system),
runner=runner)
self.code_root = root
self.app = app
self.board = board
self.os_env = os_env
if os_env is NxpOsUsed.ZEPHYR:
self.build_system = NxpBuildSystem.CMAKE
else:
self.build_system = build_system
self.low_power = low_power
self.smu2 = smu2
self.enable_factory_data = enable_factory_data
self.convert_dac_pk = convert_dac_pk
self.enable_lit = enable_lit
self.enable_rotating_id = enable_rotating_id
self.has_sw_version_2 = has_sw_version_2
self.disable_ble = disable_ble
self.enable_thread = enable_thread
self.enable_wifi = enable_wifi
self.enable_ethernet = enable_ethernet
self.enable_ota = enable_ota
self.enable_shell = enable_shell
self.enable_factory_data_build = enable_factory_data_build
self.enable_mtd = enable_mtd
self.disable_pairing_autostart = disable_pairing_autostart
self.board_variant = board_variant
self.iw416_transceiver = iw416_transceiver
self.w8801_transceiver = w8801_transceiver
self.iwx12_transceiver = iwx12_transceiver
self.iw610_transceiver = iw610_transceiver
self.se05x_enable = se05x_enable
if self.low_power and log_level != NxpLogLevel.NONE:
logging.warning("Switching log level to 'NONE' for low power build")
log_level = NxpLogLevel.NONE
self.log_level = log_level
def BoardVariantName(self, board, os_env, board_variant):
match board:
case NxpBoard.RW61X:
if self.os_env is NxpOsUsed.FREERTOS:
return "frdmrw612"
else:
return "frdm_rw612"
case NxpBoard.RT1060:
if board_variant is NxpBoardVariant.EVKC:
return "evkcmimxrt1060"
else:
return "evkbmimxrt1060"
case NxpBoard.RT1170:
return "evkbmimxrt1170"
case NxpBoard.MCXW71:
if board_variant is NxpBoardVariant.FRDM:
return "frdmmcxw71"
else:
return "mcxw71evk"
case NxpBoard.MCXW72:
if board_variant is NxpBoardVariant.FRDM:
return "frdmmcxw72"
else:
return "mcxw72evk"
case _:
raise Exception("Unknown NXP board")
def GnBuildArgs(self):
args = []
if self.low_power:
args.append('nxp_use_low_power=true')
if self.smu2:
args.append('nxp_use_smu2_static=true nxp_use_smu2_dynamic=true')
if self.enable_factory_data:
args.append('nxp_use_factory_data=true')
if self.convert_dac_pk:
args.append('nxp_convert_dac_private_key=true')
if self.enable_lit:
args.append('chip_enable_icd_lit=true')
if self.enable_rotating_id:
args.append('chip_enable_rotating_device_id=1 chip_enable_additional_data_advertising=1')
if self.log_level == NxpLogLevel.DEFAULT:
pass
elif self.log_level == NxpLogLevel.ALL:
args.append("chip_logging=true")
args.append("chip_error_logging=true")
args.append("chip_progress_logging=true")
args.append("chip_detail_logging=true")
args.append("chip_automation_logging=true")
elif self.log_level == NxpLogLevel.PROGRESS:
args.append("chip_logging=true")
args.append("chip_error_logging=true")
args.append("chip_progress_logging=true")
args.append("chip_detail_logging=false")
args.append("chip_automation_logging=false")
elif self.log_level == NxpLogLevel.ERROR:
args.append("chip_logging=true")
args.append("chip_error_logging=true")
args.append("chip_progress_logging=false")
args.append("chip_detail_logging=false")
args.append("chip_automation_logging=false")
elif self.log_level == NxpLogLevel.NONE:
args.append("chip_logging=false")
else:
raise Exception("Unknown log level: %r", self.log_level)
if self.has_sw_version_2:
args.append('nxp_software_version=2')
if self.enable_ota:
# OTA is enabled by default on kw32
if self.board == NxpBoard.RW61X:
args.append('chip_enable_ota_requestor=true no_mcuboot=false')
if self.enable_wifi:
args.append('chip_enable_wifi=true')
if self.disable_ble:
args.append('chip_enable_ble=false')
if self.enable_shell:
args.append('nxp_enable_matter_cli=true')
if self.enable_thread:
# thread is enabled by default on kw32
if self.board == NxpBoard.RW61X:
args.append('chip_enable_openthread=true chip_inet_config_enable_ipv4=false')
if self.board == NxpBoard.RT1060:
args.append('chip_enable_openthread=true chip_inet_config_enable_ipv4=false')
if self.board == NxpBoard.RT1170:
args.append('chip_enable_openthread=true chip_inet_config_enable_ipv4=false')
if self.board_variant:
board_variant_value = self.BoardVariantName(self.board, self.os_env, self.board_variant)
if self.board == NxpBoard.RT1060:
flag_board_variant = "evkname=\\\"%s\\\"" % board_variant_value
args.append(flag_board_variant)
if self.board == NxpBoard.RW61X:
flag_board_variant = "board_version=\"frdm\""
args.append(flag_board_variant)
if self.iw416_transceiver:
args.append('iw416_transceiver=true')
if self.w8801_transceiver:
# BLE not supported on this transceiver
args.append('w8801_transceiver=true chip_enable_ble=false')
if self.iwx12_transceiver:
args.append('iwx12_transceiver=true')
return args
def CmakeBuildFlags(self):
flags = []
if self.enable_factory_data and self.os_env == NxpOsUsed.ZEPHYR:
flags.append('-DFILE_SUFFIX=fdata')
if self.enable_ethernet and self.os_env == NxpOsUsed.ZEPHYR:
flags.append('-DEXTRA_CONF_FILE="prj_ethernet.conf"')
if self.has_sw_version_2:
flags.append("-DCONFIG_CHIP_DEVICE_SOFTWARE_VERSION=2")
flags.append("-DCONFIG_CHIP_DEVICE_SOFTWARE_VERSION_STRING=\"2.0\"")
if self.enable_factory_data_build:
# Generate the factory data binary
flags.append("-DCONFIG_CHIP_FACTORY_DATA_BUILD=y")
if self.disable_pairing_autostart:
flags.append('-DCONFIG_CHIP_ENABLE_PAIRING_AUTOSTART=n')
if self.iw416_transceiver:
flags.append('-DCONFIG_MCUX_COMPONENT_component.wifi_bt_module.IW416=y')
if self.w8801_transceiver:
flags.append('-DCONFIG_MCUX_COMPONENT_component.wifi_bt_module.88W8801=y')
if self.iwx12_transceiver or self.iw610_transceiver:
flags.append('-DCONFIG_MCUX_COMPONENT_component.wifi_bt_module.IW61X=y')
if self.iw610_transceiver:
flags.append('-DCONFIG_MCUX_COMPONENT_component.wifi_bt_module.board_murata_2ll_m2=y')
if self.board == NxpBoard.RT1170:
flags.append('-Dcore_id=cm7')
if self.se05x_enable:
flags.append('-DCONFIG_CHIP_SE05X=y')
if self.board in (NxpBoard.MCXW71, NxpBoard.MCXW72):
flags.append('-DCONFIG_MCUX_COMPONENT_middleware.freertos-kernel.config=n')
if self.board == NxpBoard.MCXW72:
flags.append('-Dcore_id=cm33_core0')
build_flags = " ".join(flags)
return build_flags
def get_conf_file(self):
thread_type = "mtd" if self.enable_mtd else "ftd"
components = [
"prj",
f"thread_{thread_type}" if self.enable_thread else None,
"wifi" if self.enable_wifi else None,
"eth" if self.enable_ethernet else None,
"br" if self.enable_wifi and self.enable_thread else None,
"ota" if self.enable_ota else None,
"fdata" if self.enable_factory_data else None,
"onnetwork" if self.disable_ble else None,
"low_power" if self.low_power else None
]
prj_file = "_".join(filter(None, components)) + ".conf"
prj_file_abs_path = os.path.dirname(os.path.realpath(__file__)) + "/../../../examples/platform/nxp/config/" + prj_file
if os.path.isfile(prj_file_abs_path):
return prj_file
else:
raise Exception("Configuration not supported, no conf file available: %s" % prj_file_abs_path)
def generate(self):
if self.build_system is NxpBuildSystem.CMAKE:
build_flags = self.CmakeBuildFlags()
if self.os_env == NxpOsUsed.ZEPHYR:
if 'ZEPHYR_NXP_SDK_INSTALL_DIR' not in os.environ:
raise Exception("ZEPHYR_NXP_SDK_INSTALL_DIR need to be set")
if 'ZEPHYR_NXP_BASE' not in os.environ:
raise Exception("ZEPHYR_NXP_BASE need to be set")
cmd = 'export ZEPHYR_SDK_INSTALL_DIR="$ZEPHYR_NXP_SDK_INSTALL_DIR"'
cmd += '\nexport ZEPHYR_BASE="$ZEPHYR_NXP_BASE"'
cmd += '\nunset ZEPHYR_TOOLCHAIN_VARIANT'
else:
if self.build_system is NxpBuildSystem.CMAKE:
build_flags += " " + "-DCONF_FILE_NAME=%s" % self.get_conf_file()
cmd = ''
# will be used with next sdk version to get sdk path
if 'NXP_UPDATE_SDK_SCRIPT_DOCKER' in os.environ:
# Dynamic import of a python file to get platforms sdk path
spec = importlib.util.spec_from_file_location("None", os.environ['NXP_UPDATE_SDK_SCRIPT_DOCKER'])
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module)
for p in module.ALL_PLATFORM_SDK:
if p.sdk_name == 'common':
cmd += 'export NXP_SDK_ROOT="' + str(p.sdk_storage_location_abspath) + '" \n '
cmd += 'export McuxSDK_DIR=$NXP_SDK_ROOT' + ' \n '
cmd += 'source $NXP_SDK_ROOT/mcux-env.sh' + ' \n '
if self.build_system == NxpBuildSystem.CMAKE:
if 'PW_ENVIRONMENT_ROOT' in os.environ:
cmd += 'export ARMGCC_DIR=$PW_ENVIRONMENT_ROOT/cipd/packages/arm' + ' \n '
else:
cmd += 'export ARMGCC_DIR=%s/.environment/cipd/packages/arm' % os.path.abspath(self.code_root) + ' \n '
if ((self.os_env == NxpOsUsed.FREERTOS) and (self.build_system == NxpBuildSystem.GN)):
# add empty space at the end to avoid concatenation issue when there is no --args
cmd += 'gn gen --check --fail-on-unused-args --add-export-compile-commands=* --root=%s ' % self.root
extra_args = []
if self.options.pw_command_launcher:
extra_args.append('pw_command_launcher="%s"' % self.options.pw_command_launcher)
if self.options.enable_link_map_file:
extra_args.append('chip_generate_link_map_file=true')
if self.options.pregen_dir:
extra_args.append('chip_code_pre_generated_directory="%s"' % self.options.pregen_dir)
extra_args.extend(self.GnBuildArgs() or [])
if extra_args:
cmd += ' --args="%s' % ' '.join(extra_args) + '" '
cmd += self.output_dir
title = 'Generating ' + self.identifier
self._Execute(['bash', '-c', cmd], title=title)
else:
cmd += '\nwest build -p --cmake-only -b {board_name} -d {out_folder} {example_folder} {build_flags}'.format(
board_name=self.BoardVariantName(self.board, self.os_env, self.board_variant),
out_folder=self.output_dir,
example_folder=self.app.BuildRoot(self.code_root, self.board, self.os_env, self.build_system),
build_flags=build_flags)
self._Execute(['bash', '-c', cmd], title='Generating ' + self.identifier)
def build_outputs(self):
name = 'chip-%s-%s' % (self.board.Name(self.os_env), self.app.NameSuffix())
if self.os_env == NxpOsUsed.ZEPHYR:
yield BuilderOutput(
os.path.join(self.output_dir, 'zephyr', 'zephyr.elf'),
f'{name}.elf')
if self.options.enable_link_map_file:
yield BuilderOutput(
os.path.join(self.output_dir, 'zephyr', 'zephyr.map'),
f'{name}.map')
else:
if self.build_system == NxpBuildSystem.GN:
yield BuilderOutput(
os.path.join(self.output_dir, name),
f'{name}.elf')
if self.options.enable_link_map_file:
yield BuilderOutput(
os.path.join(self.output_dir, f'{name}.map'),
f'{name}.map')
elif self.build_system == NxpBuildSystem.CMAKE:
yield BuilderOutput(
os.path.join(self.output_dir, 'out/debug', name),
f'{name}.elf')
if self.options.enable_link_map_file:
yield BuilderOutput(
os.path.join(self.output_dir, 'out/debug', f'{name}.map'),
f'{name}.map')