wolfBoot/tools/scripts/boot_status.py

141 lines
4.7 KiB
Python
Executable File

#!/usr/bin/env python3
import argparse
import sys
# Declare config_vars as a global variable
config_vars: dict[str, int] = {}
def set_status(status_file: str, partition: str, value: str) -> None:
with open(status_file, "r+b") as f:
if partition == "BOOT":
addr = config_vars["WOLFBOOT_PARTITION_BOOT_ADDRESS"]
elif partition == "UPDATE":
addr = config_vars["WOLFBOOT_PARTITION_UPDATE_ADDRESS"]
else:
print(f"Error: Invalid partition: {partition}")
sys.exit(1)
f.seek(addr + config_vars["WOLFBOOT_PARTITION_SIZE"] - 4)
magic: bytes = f.read(4)
if magic != b"BOOT":
f.seek(addr + config_vars["WOLFBOOT_PARTITION_SIZE"] - 4)
f.write(b"BOOT")
if value == "NEW":
status_byte = b"\xFF"
elif value == "UPDATING":
status_byte = b"\x70"
elif value == "SUCCESS":
status_byte = b"\x00"
else:
print(f"Error: Invalid value: {value}")
sys.exit(1)
# Write status byte at correct address
f.seek(addr + config_vars["WOLFBOOT_PARTITION_SIZE"] - 5)
f.write(status_byte)
def get_status(status_file: str, partition: str) -> None:
with open(status_file, "rb") as f:
if partition == "BOOT":
addr = config_vars["WOLFBOOT_PARTITION_BOOT_ADDRESS"]
elif partition == "UPDATE":
addr = config_vars["WOLFBOOT_PARTITION_UPDATE_ADDRESS"]
else:
print(f"Error: Invalid partition: {partition}")
sys.exit(1)
f.seek(addr + config_vars["WOLFBOOT_PARTITION_SIZE"] - 4)
magic: bytes = f.read(4)
if magic != b"BOOT":
print(f"Error: Missing magic at expected address {hex(addr)}")
sys.exit(1)
f.seek(addr + config_vars["WOLFBOOT_PARTITION_SIZE"] - 5)
status_byte: bytes = f.read(1)
if status_byte == b"\xFF":
print("NEW")
elif status_byte == b"\x70":
print("UPDATING")
elif status_byte == b"\x00":
print("SUCCESS")
else:
print("INVALID")
def read_config(config_path: str) -> dict[str, str]:
"""
Reads a config file and returns a dictionary of variables.
Supports lines of the form KEY=VALUE, KEY:=VALUE, KEY::=VALUE, KEY:::=VALUE, and KEY?=VALUE.
Ignores comments and blank lines.
"""
config: dict[str, str] = {}
assignment_ops = [":::= ", "::=", ":=", "="]
with open(config_path, "r") as f:
for line in f:
line = line.strip()
if not line or line.startswith("#"):
continue
for op in assignment_ops:
if op in line:
parts = line.split(op, 1)
if len(parts) == 2:
key = parts[0].rstrip("?").strip()
value = parts[1].strip()
config[key] = value
break # Stop after first matching operator
return config
def main() -> None:
parser = argparse.ArgumentParser(description="Manage boot status")
parser.add_argument(
"file",
type=str,
help="Path to the boot status file"
)
parser.add_argument(
"config",
type=str,
help="Path to the .config file"
)
subparsers = parser.add_subparsers(dest="command", required=True)
partitions = ["BOOT", "UPDATE"]
states = ["SUCCESS", "UPDATING", "NEW"]
set_parser = subparsers.add_parser("set")
set_parser.add_argument("slot", choices=partitions, type=str)
set_parser.add_argument("value", choices=states, type=str)
get_parser = subparsers.add_parser("get")
get_parser.add_argument("slot", choices=partitions, type=str)
args = parser.parse_args()
read_vars = read_config(args.config)
# Check required config variables using a for loop
required_vars = [
"WOLFBOOT_PARTITION_SIZE",
"WOLFBOOT_PARTITION_BOOT_ADDRESS",
"WOLFBOOT_PARTITION_UPDATE_ADDRESS",
]
for var in required_vars:
if var not in read_vars:
print(f"Error: Missing required config variable: {var}")
sys.exit(1)
try:
config_vars[var] = int(read_vars[var], 16)
except ValueError:
print(f"Error: Config variable {var} value '{read_vars[var]}' is not a valid hex number")
sys.exit(1)
command: str = str(args.command)
if command == "set":
set_status(str(args.file), str(args.slot), str(args.value))
elif command == "get":
get_status(str(args.file), str(args.slot))
else:
parser.print_help()
if __name__ == "__main__":
main()