9fb6c9ddd7
During testing it was found that if the partition type was displayed as msdos it could not be detected correctly, so this partition type determination was added. Signed-off-by: Yuchao Guo <yuchao.guo@hoorii.io>
106 lines
3.2 KiB
Python
106 lines
3.2 KiB
Python
# Copyright (c) 2023 Peter Johanson <peter@peterjohanson.com>
|
|
#
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
|
|
'''UF2 runner (flash only) for UF2 compatible bootloaders.'''
|
|
|
|
from pathlib import Path
|
|
from shutil import copy
|
|
|
|
from runners.core import ZephyrBinaryRunner, RunnerCaps
|
|
|
|
try:
|
|
import psutil # pylint: disable=unused-import
|
|
MISSING_PSUTIL = False
|
|
except ImportError:
|
|
# This can happen when building the documentation for the
|
|
# runners package if psutil is not on sys.path. This is fine
|
|
# to ignore in that case.
|
|
MISSING_PSUTIL = True
|
|
|
|
class UF2BinaryRunner(ZephyrBinaryRunner):
|
|
'''Runner front-end for copying to UF2 USB-MSC mounts.'''
|
|
|
|
def __init__(self, cfg, board_id=None):
|
|
super().__init__(cfg)
|
|
self.board_id = board_id
|
|
|
|
@classmethod
|
|
def name(cls):
|
|
return 'uf2'
|
|
|
|
@classmethod
|
|
def capabilities(cls):
|
|
return RunnerCaps(commands={'flash'})
|
|
|
|
@classmethod
|
|
def do_add_parser(cls, parser):
|
|
parser.add_argument('--board-id', dest='board_id',
|
|
help='Board-ID value to match from INFO_UF2.TXT')
|
|
|
|
@classmethod
|
|
def do_create(cls, cfg, args):
|
|
return UF2BinaryRunner(cfg, board_id=args.board_id)
|
|
|
|
@staticmethod
|
|
def get_uf2_info_path(part) -> Path:
|
|
return Path(part.mountpoint) / "INFO_UF2.TXT"
|
|
|
|
@staticmethod
|
|
def is_uf2_partition(part):
|
|
try:
|
|
return ((part.fstype in ['vfat', 'FAT', 'msdos']) and
|
|
UF2BinaryRunner.get_uf2_info_path(part).is_file())
|
|
except PermissionError:
|
|
return False
|
|
|
|
@staticmethod
|
|
def get_uf2_info(part):
|
|
lines = UF2BinaryRunner.get_uf2_info_path(part).read_text().splitlines()
|
|
|
|
lines = lines[1:] # Skip the first summary line
|
|
|
|
def split_uf2_info(line: str):
|
|
k, _, val = line.partition(':')
|
|
return k.strip(), val.strip()
|
|
|
|
return {k: v for k, v in (split_uf2_info(line) for line in lines) if k and v}
|
|
|
|
def match_board_id(self, part):
|
|
info = self.get_uf2_info(part)
|
|
|
|
return info.get('Board-ID') == self.board_id
|
|
|
|
def get_uf2_partitions(self):
|
|
parts = [part for part in psutil.disk_partitions() if self.is_uf2_partition(part)]
|
|
|
|
if (self.board_id is not None) and parts:
|
|
parts = [part for part in parts if self.match_board_id(part)]
|
|
if not parts:
|
|
self.logger.warning("Discovered UF2 partitions don't match Board-ID '%s'",
|
|
self.board_id)
|
|
|
|
return parts
|
|
|
|
def copy_uf2_to_partition(self, part):
|
|
self.ensure_output('uf2')
|
|
|
|
copy(self.cfg.uf2_file, part.mountpoint)
|
|
|
|
def do_run(self, command, **kwargs):
|
|
if MISSING_PSUTIL:
|
|
raise RuntimeError(
|
|
'could not import psutil; something may be wrong with the '
|
|
'python environment')
|
|
|
|
partitions = self.get_uf2_partitions()
|
|
if not partitions:
|
|
raise RuntimeError('No matching UF2 partitions found')
|
|
|
|
if len(partitions) > 1:
|
|
raise RuntimeError('More than one matching UF2 partitions found')
|
|
|
|
part = partitions[0]
|
|
self.logger.info("Copying UF2 file to '%s'", part.mountpoint)
|
|
self.copy_uf2_to_partition(part)
|