Expose the existing registers through Modbus and service CAN using one GAS provider only in M95M02 builds. Include the EEPROM layout/driver, LOAD protection and calibration, firmware identity and shared CCS build workflow. Add transport/profile and SCI8 validation tests, documentation and the checked M95M02 firmware image.
49 lines
2.1 KiB
Python
49 lines
2.1 KiB
Python
"""Generate build identity using the release version from firmware_version.h."""
|
|
import argparse
|
|
import importlib.util
|
|
import json
|
|
from pathlib import Path
|
|
import re
|
|
import tempfile
|
|
|
|
|
|
def read_version(header):
|
|
text = header.read_text(encoding="utf-8-sig")
|
|
text = re.sub(r"/\*.*?\*/|//[^\n]*", "", text, flags=re.S)
|
|
version = []
|
|
for part, limit in (("MAJOR", 255), ("MINOR", 255), ("PATCH", 999)):
|
|
name = "FIRMWARE_VERSION_" + part
|
|
definitions = re.findall(r"^\s*#\s*define\s+" + name + r"\b([^\n]*)", text, re.M)
|
|
if len(definitions) != 1:
|
|
raise ValueError(f"{header}: define {name} exactly once")
|
|
value = definitions[0].strip()
|
|
if not re.fullmatch(r"(?:0|[1-9][0-9]*)[uU]?", value):
|
|
raise ValueError(f"{header}: {name} must be a decimal integer")
|
|
number = int(value.rstrip("uU"))
|
|
if not 0 <= number <= limit:
|
|
raise ValueError(f"{header}: {name} must be in 0..{limit}")
|
|
version.append(number)
|
|
return version
|
|
|
|
|
|
def prepare(project, templates, output):
|
|
settings = json.loads((project / "firmware_identity.json").read_text(encoding="utf-8-sig"))
|
|
settings["version"] = read_version(project / "firmware_version.h")
|
|
spec = importlib.util.spec_from_file_location("shared_firmware_identity", templates / "c/firmware-info/tools/identity.py")
|
|
identity = importlib.util.module_from_spec(spec)
|
|
spec.loader.exec_module(identity)
|
|
# The source header owns SemVer; retain the shared generator and manifest format.
|
|
with tempfile.TemporaryDirectory(prefix="balsam-identity-") as directory:
|
|
config = Path(directory) / "config.json"
|
|
config.write_text(json.dumps(settings), encoding="utf-8")
|
|
return identity.prepare(project, templates, config, output)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
parser = argparse.ArgumentParser(description=__doc__)
|
|
parser.add_argument("--project", type=Path, required=True)
|
|
parser.add_argument("--templates", type=Path, required=True)
|
|
parser.add_argument("--output", type=Path, required=True)
|
|
args = parser.parse_args()
|
|
print(json.dumps(prepare(args.project, args.templates, args.output)))
|