Skip to content

Commit c90d9d5

Browse files
committed
Consume OBC registry + shared firmware templates (Ecosystem Integration I1/I6)
hardware/registry.py: typed loader for the canonical registry.json exported by Oh-Ben-Claw's emit-registry (bundled copy + OBC_REGISTRY_PATH override), schema_version gate, name/USB/capability lookups, and platform_for_board routing registry boards onto Accelerapp codegen platforms (every emitted name pinned instantiable via get_platform). firmware/obc_templates.py: consumer for the shared starter-sketch set from emit-firmware-templates (template_for_board with node-id substitution; codegen_route pairs the OBC node-protocol scaffold with the platform generator). Both JSON documents packaged via package-data + MANIFEST. 25 pytest tests (registry 16, templates 9), incl. a templates-vs-registry flashable-set drift guard.
1 parent d8f7c78 commit c90d9d5

10 files changed

Lines changed: 3241 additions & 1 deletion

File tree

MANIFEST.in

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,7 @@ include README.md
22
include LICENSE
33
include requirements.txt
44
recursive-include src/accelerapp/templates *
5+
include src/accelerapp/hardware/registry.json
6+
include src/accelerapp/firmware/templates.json
57
recursive-include examples *.yaml
68
recursive-include docs *.md

pyproject.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,10 @@ Documentation = "https://github.com/thewriterben/Accelerapp/blob/main/README.md"
6464
[tool.setuptools.packages.find]
6565
where = ["src"]
6666

67+
[tool.setuptools.package-data]
68+
"accelerapp.hardware" = ["registry.json"]
69+
"accelerapp.firmware" = ["templates.json"]
70+
6771
[tool.pytest.ini_options]
6872
minversion = "7.0"
6973
testpaths = ["tests"]

src/accelerapp/firmware/__init__.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,19 @@
44
"""
55

66
from .generator import FirmwareGenerator
7+
from .obc_templates import (
8+
FirmwareTemplate,
9+
TemplatesSchemaError,
10+
codegen_route,
11+
load_templates,
12+
template_for_board,
13+
)
714

8-
__all__ = ["FirmwareGenerator"]
15+
__all__ = [
16+
"FirmwareGenerator",
17+
"FirmwareTemplate",
18+
"TemplatesSchemaError",
19+
"codegen_route",
20+
"load_templates",
21+
"template_for_board",
22+
]
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
"""
2+
OBC shared firmware templates — Ecosystem Integration I6.
3+
4+
The canonical starter-sketch template set is generated by Oh-Ben-Claw's
5+
``emit-firmware-templates`` binary (one capability-conditioned Arduino sketch
6+
per flashable registry board) and bundled here as ``templates.json`` —
7+
refreshed alongside ``registry.json``::
8+
9+
# in Oh-Ben-Claw
10+
cargo run --bin emit-firmware-templates -- firmware-templates/templates.json
11+
cp firmware-templates/templates.json ../Accelerapp/src/accelerapp/firmware/templates.json
12+
13+
Use :func:`template_for_board` for the OBC node-protocol scaffold, and
14+
:func:`codegen_route` to decide how Accelerapp should treat a registry board:
15+
start from the shared scaffold, route to one of Accelerapp's platform
16+
generators, or both.
17+
"""
18+
19+
from __future__ import annotations
20+
21+
import json
22+
import os
23+
from dataclasses import dataclass
24+
from functools import lru_cache
25+
from pathlib import Path
26+
from typing import List, Optional, Tuple
27+
28+
from accelerapp.hardware.registry import Board, platform_for_board
29+
30+
#: The templates.json schema this consumer understands (mirrors OBC's
31+
#: TEMPLATES_SCHEMA_VERSION).
32+
SUPPORTED_TEMPLATES_SCHEMA_VERSION = 1
33+
34+
#: Environment variable overriding the bundled template document.
35+
TEMPLATES_PATH_ENV = "OBC_FIRMWARE_TEMPLATES_PATH"
36+
37+
_BUNDLED = Path(__file__).parent / "templates.json"
38+
39+
#: The node id baked into canonical templates, to be substituted per node.
40+
NODE_ID_PLACEHOLDER = "obc-node"
41+
42+
43+
class TemplatesSchemaError(RuntimeError):
44+
"""The template document's schema_version is unsupported."""
45+
46+
47+
@dataclass(frozen=True)
48+
class FirmwareTemplate:
49+
"""One canonical starter sketch for a flashable registry board."""
50+
51+
board: str
52+
language: str
53+
filename: str
54+
source: str
55+
capabilities: List[str]
56+
vendor: str
57+
58+
def with_node_id(self, node_id: str) -> "FirmwareTemplate":
59+
"""The same template with the placeholder node id substituted."""
60+
return FirmwareTemplate(
61+
board=self.board,
62+
language=self.language,
63+
filename=self.filename,
64+
source=self.source.replace(NODE_ID_PLACEHOLDER, node_id),
65+
capabilities=self.capabilities,
66+
vendor=self.vendor,
67+
)
68+
69+
70+
def load_templates(path: Optional[os.PathLike] = None) -> List[FirmwareTemplate]:
71+
"""Load and validate the template document (path → env var → bundled)."""
72+
resolved = Path(path) if path else Path(os.environ.get(TEMPLATES_PATH_ENV, _BUNDLED))
73+
with open(resolved, encoding="utf-8") as f:
74+
doc = json.load(f)
75+
76+
version = doc.get("schema_version")
77+
if version != SUPPORTED_TEMPLATES_SCHEMA_VERSION:
78+
raise TemplatesSchemaError(
79+
f"templates.json schema_version {version!r} is not supported "
80+
f"(this consumer understands {SUPPORTED_TEMPLATES_SCHEMA_VERSION})"
81+
)
82+
83+
return [
84+
FirmwareTemplate(
85+
board=t["board"],
86+
language=t.get("language", "arduino"),
87+
filename=t["filename"],
88+
source=t["source"],
89+
capabilities=list(t.get("capabilities", [])),
90+
vendor=t.get("vendor", ""),
91+
)
92+
for t in doc.get("templates", [])
93+
]
94+
95+
96+
@lru_cache(maxsize=1)
97+
def _bundled() -> List[FirmwareTemplate]:
98+
return load_templates()
99+
100+
101+
def template_for_board(board_name: str, node_id: Optional[str] = None) -> Optional[FirmwareTemplate]:
102+
"""The shared OBC starter sketch for a board, optionally node-id'd."""
103+
t = next((t for t in _bundled() if t.board == board_name), None)
104+
if t is None:
105+
return None
106+
return t.with_node_id(node_id) if node_id else t
107+
108+
109+
def codegen_route(board: Board) -> Tuple[Optional[str], Optional[FirmwareTemplate]]:
110+
"""
111+
How should Accelerapp generate firmware for this registry board?
112+
113+
Returns ``(platform_name, template)``:
114+
- ``platform_name`` — an Accelerapp platform generator (``get_platform``)
115+
when the board maps to one, else ``None``;
116+
- ``template`` — the shared OBC node-protocol scaffold when the board is
117+
flashable, else ``None``.
118+
119+
Typical use: start from the scaffold (correct OBC announce/command
120+
skeleton), then generate platform-specific drivers with the platform
121+
generator.
122+
"""
123+
return platform_for_board(board), template_for_board(board.name)

0 commit comments

Comments
 (0)