blob: bd7b64cf021bcdf2581f24196757eece97f8184a [file] [log] [blame]
#!/usr/bin/env python3
# Copyright (c) 2020 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.
"""Flash an SILABS device.
This is layered so that a caller can perform individual operations
through an `Flasher` instance, or operations according to a command line.
For `Flasher`, see the class documentation. For the parse_command()
interface or standalone execution:
usage: silabs_firmware_utils.py [-h] [--verbose] [--erase] [--application FILE]
[--verify_application] [--reset] [--skip_reset]
[--commander FILE] [--device DEVICE]
[--serialno SERIAL] [--ip ADDRESS]
Flash SILABS device
optional arguments:
-h, --help show this help message and exit
configuration:
--verbose, -v Report more verbosely
--commander FILE File name of the commander executable
--device DEVICE, -d DEVICE
Device family or platform to target
--serialno SERIAL, -s SERIAL
Serial number of device to flash
--ip ADDRESS, -a ADDRESS
Ip Address of the targeted flasher
operations:
--erase Erase device
--application FILE Flash an image
--verify_application, --verify-application
Verify the image after flashing
--reset Reset device after flashing
--skip_reset, --skip-reset
Do not reset device after flashing
"""
import os
import shutil
import sys
import firmware_utils
# Additional options that can be use to configure an `Flasher`
# object (as dictionary keys) and/or passed as command line options.
SILABS_OPTIONS = {
# Configuration options define properties used in flashing operations.
'configuration': {
# Tool configuration options.
'commander': {
'help': 'File name of the commander executable',
'default': 'commander',
'argparse': {
'metavar': 'FILE'
},
'verify': ['{commander}', '--version'],
'error':
"""\
Unable to execute {commander}.
Please ensure that this tool is installed and
available. See the SILABS example README for
installation instructions.
""",
},
'device': {
'help': 'Device family or platform to target (EFR32 or MGM240)',
'default': None,
'alias': ['-d'],
'argparse': {
'metavar': 'DEVICE'
},
},
'serialno': {
'help': 'Serial number of device to flash',
'default': None,
'alias': ['-s'],
'argparse': {
'metavar': 'SERIAL'
},
},
'ip': {
'help': 'Ip Address of the probe connected to the target',
'default': None,
'alias': ['-a'],
'argparse': {
'metavar': 'ADDRESS'
},
},
},
}
class Flasher(firmware_utils.Flasher):
"""Manage silabs flashing."""
def __init__(self, **options):
super().__init__(platform='SILABS', module=__name__, **options)
self.define_options(SILABS_OPTIONS)
# Common command line arguments for commander device subcommands.
DEVICE_ARGUMENTS = [{'optional': 'serialno'}, {
'optional': 'ip'}, {'optional': 'device'}]
def erase(self):
"""Perform `commander device masserase`."""
return self.run_tool(
'commander', ['device', 'masserase', self.DEVICE_ARGUMENTS],
name='Erase device')
def verify(self, image):
"""Verify image."""
return self.run_tool(
'commander',
['verify', self.DEVICE_ARGUMENTS, image],
name='Verify',
pass_message='Verified',
fail_message='Not verified',
fail_level=2)
def flash(self, image):
"""Flash image."""
return self.run_tool(
'commander',
['flash', self.DEVICE_ARGUMENTS, image],
name='Flash')
def reset(self):
"""Reset the device."""
return self.run_tool(
'commander',
['device', 'reset', self.DEVICE_ARGUMENTS],
name='Reset')
def actions(self):
"""Perform actions on the device according to self.option."""
self.log(3, 'Options:', self.option)
if self.option.erase:
if self.erase().err:
return self
if self.option.application:
application = self.option.application
if self.flash(application).err:
return self
if self.option.verify_application:
if self.verify(application).err:
return self
if self.option.reset is None:
self.option.reset = True
if self.option.reset:
if self.reset().err:
return self
return self
def _platform_wrapper_args(self, args):
"""Called from make_wrapper() to optionally manipulate arguments."""
# Generate the flashbundle.txt file and copy the firmware utils.
if args.flashbundle_file is not None:
# Generate the flashbundle contents.
# Copy the platform-specific and general firmware utils to the same directory as the wrapper.
flashbundle_contents = os.path.basename(args.output)
if args.application is not None:
flashbundle_contents += "\n" + os.path.basename(args.application)
output_dir = os.path.dirname(args.output) or "."
if args.platform_firmware_utils is not None:
flashbundle_contents += "\n" + os.path.basename(args.platform_firmware_utils)
shutil.copy(args.platform_firmware_utils, output_dir)
if args.firmware_utils is not None:
flashbundle_contents += "\n" + os.path.basename(args.firmware_utils)
shutil.copy(args.firmware_utils, output_dir)
# Create the flashbundle file.
with open(args.flashbundle_file, 'w') as flashbundle_file:
flashbundle_file.write(flashbundle_contents.strip())
def make_wrapper(self, argv):
self.parser.add_argument(
'--flashbundle-file',
metavar='FILENAME',
help='path and name of the flashbundle text file to create')
self.parser.add_argument(
'--platform-firmware-utils',
metavar='FILENAME',
help='path and file of the platform-specific firmware utils script')
self.parser.add_argument(
'--firmware-utils',
metavar='FILENAME',
help='path and file of the general firmware utils script')
super().make_wrapper(argv)
if __name__ == '__main__':
sys.exit(Flasher().flash_command(sys.argv))