| #!/usr/bin/env python3 |
| # 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 os |
| import pathlib |
| import re |
| import sys |
| |
| import bflb_iot_tool |
| import bflb_iot_tool.__main__ |
| import firmware_utils |
| |
| # Additional options that can be use to configure an `Flasher` |
| # object (as dictionary keys) and/or passed as command line options. |
| BOUFFALO_OPTIONS = { |
| # Configuration options define properties used in flashing operations. |
| 'configuration': { |
| 'chipname': { |
| 'help': "Bouffalolab chip name", |
| 'default': None, |
| 'argparse': { |
| 'metavar': 'CHIP_NAME', |
| } |
| }, |
| 'pt': { |
| 'help': 'Partition table for board', |
| 'default': None, |
| 'argparse': { |
| 'metavar': 'PARTITION_TABLE_FILE', |
| 'type': pathlib.Path |
| } |
| }, |
| 'dts': { |
| 'help': 'Device tree file', |
| 'default': None, |
| 'argparse': { |
| 'metavar': 'DEVICE_TREE_FILE', |
| 'type': pathlib.Path |
| } |
| }, |
| 'xtal': { |
| 'help': 'XTAL for board', |
| 'default': None, |
| 'argparse': { |
| 'metavar': 'XTAL', |
| } |
| }, |
| 'port': { |
| 'help': 'UART port to flash device', |
| 'default': None, |
| 'argparse': { |
| 'metavar': 'PORT', |
| } |
| }, |
| 'baudrate': { |
| 'help': 'UART baudrate to flash device', |
| 'default': None, |
| 'argparse': { |
| 'metavar': 'BAUDRATE', |
| }, |
| }, |
| 'build': { |
| 'help': 'Build image', |
| 'default': None, |
| 'argparse': { |
| 'action': 'store_true' |
| } |
| }, |
| 'ota': { |
| 'help': 'output directory of ota image build', |
| 'default': None, |
| 'argparse': { |
| 'metavar': 'DIR', |
| 'type': pathlib.Path |
| } |
| }, |
| 'pk': { |
| 'help': 'public key to sign and encrypt firmware. Available for OTA image building.', |
| 'default': None, |
| 'argparse': { |
| 'metavar': 'path', |
| 'type': pathlib.Path |
| } |
| }, |
| 'sk': { |
| 'help': 'private key to sign and encrypt firmware. Available for OTA image building.', |
| 'default': None, |
| 'argparse': { |
| 'metavar': 'path', |
| 'type': pathlib.Path |
| } |
| }, |
| 'boot2': { |
| 'help': 'boot2 image.', |
| 'default': None, |
| 'argparse': { |
| 'metavar': 'path', |
| } |
| } |
| }, |
| } |
| |
| |
| class Flasher(firmware_utils.Flasher): |
| |
| isErase = False |
| |
| def __init__(self, **options): |
| super().__init__(platform=None, module=__name__, **options) |
| self.define_options(BOUFFALO_OPTIONS) |
| |
| def get_boot_image(self, config_path, boot2_image): |
| |
| boot_image_guess = None |
| |
| for root, dirs, files in os.walk(config_path, topdown=False): |
| for name in files: |
| print("get_boot_image", root, boot2_image) |
| if boot2_image: |
| return os.path.join(root, boot2_image) |
| else: |
| if name == "boot2_isp_release.bin": |
| return os.path.join(root, name) |
| elif not boot_image_guess and name.find("release") >= 0: |
| boot_image_guess = os.path.join(root, name) |
| |
| return boot_image_guess |
| |
| def get_dts_file(self, config_path, xtal_value): |
| |
| for root, dirs, files in os.walk(config_path, topdown=False): |
| for name in files: |
| if name.find(xtal_value) >= 0: |
| return os.path.join(config_path, name) |
| |
| return None |
| |
| def verify(self): |
| """Not supported""" |
| self.log(0, "Verification is done after image flashed.") |
| |
| def reset(self): |
| """Not supported""" |
| self.log(0, "Reset is triggered automatically after image flashed.") |
| |
| def actions(self): |
| """Perform actions on the device according to self.option.""" |
| self.log(3, 'Options:', self.option) |
| |
| tool_path = os.path.dirname(bflb_iot_tool.__file__) |
| |
| options_keys = BOUFFALO_OPTIONS["configuration"].keys() |
| arguments = [__file__] |
| work_dir = None |
| |
| print("self.option", self.option) |
| |
| if self.option.reset: |
| self.reset() |
| if self.option.verify_application: |
| self.verify() |
| |
| chip_name = None |
| chip_config_path = None |
| boot2_image = None |
| dts_path = None |
| xtal_value = None |
| |
| is_for_ota_image_building = False |
| is_for_programming = False |
| has_private_key = False |
| has_public_key = False |
| |
| boot2_image = None |
| |
| command_args = {} |
| for (key, value) in dict(vars(self.option)).items(): |
| |
| if self.option.build and value: |
| if "port" in command_args.keys(): |
| continue |
| else: |
| if "ota" in command_args.keys(): |
| continue |
| |
| if key == "application": |
| key = "firmware" |
| work_dir = os.path.dirname(os.path.join(os.getcwd(), str(value))) |
| elif key == "boot2": |
| boot2_image = value |
| continue |
| elif key in options_keys: |
| pass |
| else: |
| continue |
| |
| if value: |
| if value is True: |
| arg = ("--{}".format(key)).strip() |
| elif isinstance(value, pathlib.Path): |
| arg = ("--{}={}".format(key, os.path.join(os.getcwd(), str(value)))).strip() |
| else: |
| arg = ("--{}={}".format(key, value)).strip() |
| |
| if key == "chipname": |
| chip_name = value |
| elif key == "xtal": |
| xtal_value = value |
| elif key == "dts": |
| dts_path = value |
| elif "port" == key: |
| if value: |
| is_for_programming = True |
| elif "build" == key: |
| if value: |
| is_for_ota_image_building = True |
| elif "pk" == key: |
| if value: |
| has_public_key = True |
| elif "sk" == key: |
| if value: |
| has_private_key = True |
| |
| arguments.append(arg) |
| |
| print(key, value) |
| |
| if is_for_ota_image_building and is_for_programming: |
| print("ota imge build can't work with image programming") |
| return self |
| |
| if is_for_ota_image_building: |
| if (has_private_key is not has_public_key) and (has_private_key or has_public_key): |
| print("For ota image signature, key pair must be used together") |
| return self |
| |
| print(dts_path, xtal_value) |
| if not dts_path and xtal_value: |
| chip_config_path = os.path.join(tool_path, "chips", chip_name, "device_tree") |
| dts_path = self.get_dts_file(chip_config_path, xtal_value) |
| arguments.append("--dts") |
| arguments.append(dts_path) |
| |
| if boot2_image: |
| chip_config_path = os.path.join(tool_path, "chips", chip_name, "builtin_imgs") |
| boot2_image = self.get_boot_image(chip_config_path, boot2_image) |
| arguments.append("--boot2") |
| arguments.append(boot2_image) |
| else: |
| if self.option.erase: |
| arguments.append("--erase") |
| |
| if chip_name == "bl602": |
| chip_config_path = os.path.join(tool_path, "chips", chip_name, "builtin_imgs") |
| boot2_image = self.get_boot_image(chip_config_path, boot2_image) |
| arguments.append("--boot2") |
| arguments.append(boot2_image) |
| |
| os.chdir(work_dir) |
| arguments[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', arguments[0]) |
| sys.argv = arguments |
| |
| print("arguments", arguments) |
| bflb_iot_tool.__main__.run_main() |
| |
| return self |
| |
| |
| if __name__ == '__main__': |
| |
| sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) |
| |
| sys.exit(Flasher().flash_command(sys.argv)) |