From 47ec58dc9bf0d5c9625fcdec0ca9039f6c816e4d Mon Sep 17 00:00:00 2001 From: Marian Buschsieweke Date: Fri, 19 May 2023 13:12:12 +0200 Subject: [PATCH] dist/tools/openocd: fix parsing of flash bank base Since 80fc9fabc66a0bc767467fa14c703e5a9f340cd3 the format of the `flash list` command changed to a more human readable multi-line variant. Technically, the change is white-space only. Still, the current approach of parsing them with awk, sed and cut doesn't like the new multi-line format. The parsing is now delegated into a python script that is compatible across OpenOCD versions. --- dist/tools/openocd/openocd.sh | 69 +++---------------------- dist/tools/openocd/openocd_flashinfo.py | 69 +++++++++++++++++++++++++ 2 files changed, 75 insertions(+), 63 deletions(-) create mode 100755 dist/tools/openocd/openocd_flashinfo.py diff --git a/dist/tools/openocd/openocd.sh b/dist/tools/openocd/openocd.sh index 408ce77c13..1bd5d09a3e 100755 --- a/dist/tools/openocd/openocd.sh +++ b/dist/tools/openocd/openocd.sh @@ -195,42 +195,7 @@ _is_binfile() { [[ -z "${firmware_type}" ]] && _has_bin_extension "${firmware}"; } } -# Split bank info on different lines without the '{}' -_split_banks() { - # Input: - # ... - # {name nrf51 base 0 size 0 bus_width 1 chip_width 1} {name nrf51 base 268439552 size 0 bus_width 1 chip_width 1} - # ... - # or for newer openocd versions (v0.12.0 or higher) - # ... - # {name nrf51.flash driver nrf51 base 0 size 0 bus_width 1 chip_width 1 target nrf51.cpu} {name nrf51.uicr ...} - # ... - # - # Output: - # ... - # name nrf51 base 0 size 0 bus_width 1 chip_width 1 - # name nrf51 base 268439552 size 0 bus_width 1 chip_width 1 - # ... - # or for newer openocd versions (v0.12.0 or higher) - # ... - # name nrf51.flash driver nrf51 base 0 size 0 bus_width 1 chip_width 1 target nrf51.cpu - # name nrf51.uicr driver nrf51 base 268439552 size 0 bus_width 1 chip_width 1 target nrf51.cpu - # ... - # - # The following command needs specific osx handling (non gnu): - # * Same commands for a pattern should be on different lines - # * Cannot use '\n' in the replacement string - local sed_escaped_newline=\\$'\n' - - sed -n ' - /^{.*}$/ { - s/\} /\}'"${sed_escaped_newline}"'/g - s/[{}]//g - p - }' -} - -_flash_list_raw() { +_flash_list() { # Openocd output for 'flash list' is either # .... # {name nrf51 base 0 size 0 bus_width 1 chip_width 1} {name nrf51 base 268439552 size 0 bus_width 1 chip_width 1} @@ -272,32 +237,10 @@ _flash_list_raw() { -c 'shutdown'" 2>&1 } -# Outputs bank info on different lines without the '{}' -_flash_list() { - # .... - # name nrf51 base 0 size 0 bus_width 1 chip_width 1 - # name nrf51 base 268439552 size 0 bus_width 1 chip_width 1 - # .... - # or for newer openocd versions (v0.12.0 or higher) - # .... - # name nrf51.flash driver nrf51 base 0 size 0 bus_width 1 chip_width 1 target nrf51.cpu - # name nrf51.uicr driver nrf51 base 268439552 size 0 bus_width 1 chip_width 1 target nrf51.cpu - # .... - _flash_list_raw | _split_banks -} - -# Print flash address for 'bank_num' num defaults to 1 -# _flash_address [bank_num:1] +# Print flash address for 'bank_num' num defaults to 0 +# _flash_address [bank_num:0] _flash_address() { - # extract the line from '_flash_list' output for bank with number 'bank_num' - bank=$(_flash_list | awk "NR==${1:-1}") - # determine the column of base address, a line can have following formats - # name nrf51 base 268439552 size 0 bus_width 1 chip_width 1 - # or for newer openocd versions (v0.12.0 or higher) - # name nrf51.flash driver nrf51 base 0 size 0 bus_width 1 chip_width 1 target nrf51.cpu - base_addr_idx=$(echo ${bank} | awk '{ for (i=1; i <= NF; i++) if ($i == "base") print i + 1 }') - # extract the base address in hexadecimal format - printf 0x"%08x" $(echo ${bank} | cut -d " " -f${base_addr_idx}) + _flash_list | "${RIOTTOOLS}/openocd/openocd_flashinfo.py" --idx "${1:-0}" } do_flashr() { @@ -317,7 +260,7 @@ do_flashr() { # This allows flashing normal binary files without env configuration if _is_binfile "${IMAGE_FILE}" "${IMAGE_TYPE}"; then # hardwritten to use the first bank - FLASH_ADDR=$(_flash_address 1) + FLASH_ADDR=$(_flash_address 0) echo "Binfile detected, adding ROM base address: ${FLASH_ADDR}" IMAGE_TYPE=bin IMAGE_OFFSET=$(printf "0x%08x\n" "$((${IMAGE_OFFSET} + ${FLASH_ADDR}))") @@ -366,7 +309,7 @@ do_flash() { # This allows flashing normal binary files without env configuration if _is_binfile "${IMAGE_FILE}" "${IMAGE_TYPE}"; then # hardwritten to use the first bank - FLASH_ADDR=$(_flash_address 1) + FLASH_ADDR=$(_flash_address 0) echo "Binfile detected, adding ROM base address: ${FLASH_ADDR}" IMAGE_TYPE=bin IMAGE_OFFSET=$(printf "0x%08x\n" "$((${IMAGE_OFFSET} + ${FLASH_ADDR}))") diff --git a/dist/tools/openocd/openocd_flashinfo.py b/dist/tools/openocd/openocd_flashinfo.py new file mode 100755 index 0000000000..f69ee376ac --- /dev/null +++ b/dist/tools/openocd/openocd_flashinfo.py @@ -0,0 +1,69 @@ +#!/usr/bin/env python3 +""" +Utility to parse the output of OpenOCD's "flash list" command +""" +import argparse +import sys + +NUMERIC_FIELDS = {"base", "size", "bus_width", "chip_width"} + + +def parse_flash_info(lines): + """ + Read output of OpenOCD's "flash list" command given in lines into a list + of dictionaries + + :param lines: Output of "flash list" lines + + :return: [{"name": "nrf52.flash", "base": 0, ...}, + {"name": "nrf52.uicr", ...}, ...] + """ + tokens = [] + for line in lines: + for word in line.split(): + if word.startswith('{') and len(word) > 1: + tokens += ["{", word[1:]] + elif word.endswith('}') and len(word) > 1: + tokens += [word[:-1], "}"] + else: + tokens.append(word) + + idx = 0 + result = [] + while idx < len(tokens): + entry = {} + while idx < len(tokens) and tokens[idx] != "{": + idx += 1 + idx += 1 + while idx < len(tokens) and tokens[idx] != "}": + if idx + 1 >= len(tokens) or tokens[idx + 1] == "}": + break + key = tokens[idx] + value = tokens[idx + 1] + if key in NUMERIC_FIELDS: + value = int(value, 0) + entry[key] = value + idx += 2 + if idx < len(tokens) and tokens[idx] == "}": + result.append(entry) + + return result + + +if __name__ == "__main__": + parser = argparse.ArgumentParser( + description="Parse OpenOCD's \"flash list\" output") + parser.add_argument("--field", default="base", type=str, + help="Field to extract (default \"base\")") + parser.add_argument("--idx", default=0, type=int, + help="Index of the bank to extract info from " + + "(default 0)") + args = parser.parse_args() + info = parse_flash_info(sys.stdin) + if args.idx < 0 or args.idx >= len(info): + sys.exit("flash bank index out of range") + value = info[args.idx][args.field] + if args.field in NUMERIC_FIELDS: + print(f"0x{value:08x}") + else: + print(value)