diff options
Diffstat (limited to 'tools')
| -rw-r--r-- | tools/gen_products.py | 23 | ||||
| -rw-r--r-- | tools/tests/test_gen_products.py | 23 |
2 files changed, 43 insertions, 3 deletions
diff --git a/tools/gen_products.py b/tools/gen_products.py index 7504287..ff9cf67 100644 --- a/tools/gen_products.py +++ b/tools/gen_products.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # Author: cirakg & claude ai -# Summary: Check that every product in manifest.xml is a watch with API 5.0+ and at least 512 KB for watch apps. +# Summary: Check each manifest product: a watch with API 5.0+, 512 KB or more, and the watchdog the job runner assumes. """Check the manifest's product list against the downloaded device files. The target rule (README section 14, decision D4): a product belongs in @@ -9,6 +9,12 @@ variant supports Connect IQ API 5.0.0 or newer, and watch apps get at least 512 KB of memory. The data comes from each device's compiler.json, which `make sdk` downloads for exactly the products in the manifest. +The app's job runner (source/util/Jobs.mc) also assumes a watchdog limit +from the memory size: watches with more than 600,000 bytes for watch apps +run two job steps per event, which needs 240,000 bytecodes per event +(simulator.json's watchdogCount); the others run one step and need at +least 120,000. + Usage: gen_products.py --check [--manifest manifest.xml] [--devices DIR] Exit: 0 every product qualifies, 1 some don't, 2 device files missing. @@ -29,6 +35,9 @@ EXIT_OK, EXIT_UNQUALIFIED, EXIT_MISSING = 0, 1, 2 IQ_NS = "{http://www.garmin.com/xml/connectiq}" MIN_API = (5, 0, 0) MIN_WATCH_APP_MEMORY = 512 * 1024 +# Jobs.LARGE_WATCH_MEMORY and the watchdog each memory class needs. +LARGE_WATCH_MEMORY = 600_000 +WATCHDOG_SMALL, WATCHDOG_LARGE = 120_000, 240_000 WATCH_GROUP = "Watches/Wearables" DEFAULT_DEVICES = Path.home() / ".Garmin" / "ConnectIQ" / "Devices" @@ -42,6 +51,7 @@ class Device: group: str min_api: tuple[int, ...] watch_app_memory: int + watchdog: int def problems(self) -> list[str]: reasons = [] @@ -51,6 +61,12 @@ class Device: reasons.append(f"API {'.'.join(map(str, self.min_api))} is below 5.0.0") if self.watch_app_memory < MIN_WATCH_APP_MEMORY: reasons.append(f"watch apps get {self.watch_app_memory // 1024} KB, below 512 KB") + needed = WATCHDOG_LARGE if self.watch_app_memory > LARGE_WATCH_MEMORY else WATCHDOG_SMALL + if self.watchdog < needed: + reasons.append( + f"watchdog allows {self.watchdog} bytecodes per event; the job runner needs {needed} at" + f" {self.watch_app_memory // 1024} KB (change Jobs.stepsPerTick)" + ) return reasons @@ -61,12 +77,17 @@ def parse_version(text: str) -> tuple[int, ...]: def load_device(devices: Path, product: str) -> Device: compiler = json.loads((devices / product / "compiler.json").read_text(encoding="utf-8")) memory = {app["type"]: int(app["memoryLimit"]) for app in compiler["appTypes"]} + simulator = devices / product / "simulator.json" + watchdog = 0 + if simulator.exists(): + watchdog = int(json.loads(simulator.read_text(encoding="utf-8")).get("watchdogCount", 0)) return Device( product=product, name=str(compiler.get("displayName", product)), group=str(compiler.get("webDocDeviceGroup", "")), min_api=min(parse_version(p["connectIQVersion"]) for p in compiler["partNumbers"]), watch_app_memory=memory.get("watchApp", 0), + watchdog=watchdog, ) diff --git a/tools/tests/test_gen_products.py b/tools/tests/test_gen_products.py index 47424d2..e57973f 100644 --- a/tools/tests/test_gen_products.py +++ b/tools/tests/test_gen_products.py @@ -1,5 +1,5 @@ # Author: cirakg & claude ai -# Summary: Tests for tools/gen_products.py (the manifest product rule). +# Summary: Tests for tools/gen_products.py (the manifest product rule and the watchdog the job runner assumes). """Tests for tools/gen_products.py, with synthetic device definitions.""" from __future__ import annotations @@ -17,6 +17,7 @@ MANIFEST = """<iq:manifest version="3" xmlns:iq="http://www.garmin.com/xml/conne def add_device(devices: Path, product: str, api: list[str], memory: int, group: str = gp.WATCH_GROUP) -> None: folder = devices / product folder.mkdir(parents=True) + set_watchdog(devices, product, gp.WATCHDOG_LARGE if memory > gp.LARGE_WATCH_MEMORY else gp.WATCHDOG_SMALL) compiler = { "displayName": product.upper(), "webDocDeviceGroup": group, @@ -26,6 +27,10 @@ def add_device(devices: Path, product: str, api: list[str], memory: int, group: (folder / "compiler.json").write_text(json.dumps(compiler)) +def set_watchdog(devices: Path, product: str, count: int) -> None: + (devices / product / "simulator.json").write_text(json.dumps({"watchdogCount": count})) + + def write_manifest(tmp_path: Path, products: list[str]) -> Path: path = tmp_path / "manifest.xml" path.write_text(MANIFEST.format(products="".join(f'<iq:product id="{p}"/>' for p in products))) @@ -55,9 +60,23 @@ def test_missing_device_files(tmp_path: Path) -> None: def test_problem_messages() -> None: - device = gp.Device("x", "X", "Edge", (4, 2, 0), 131072) + device = gp.Device("x", "X", "Edge", (4, 2, 0), 131072, 120000) assert device.problems() == [ "group is 'Edge', not 'Watches/Wearables'", "API 4.2.0 is below 5.0.0", "watch apps get 128 KB, below 512 KB", ] + + +def test_watchdog_must_match_the_job_runner(tmp_path: Path) -> None: + devices = tmp_path / "Devices" + add_device(devices, "big_slow", ["6.0.0"], 786432) + set_watchdog(devices, "big_slow", 120000) # would run 2 steps on 120,000 + add_device(devices, "small_fast", ["6.0.0"], 524288) + set_watchdog(devices, "small_fast", 240000) # fine: 1 step, more room + assert gp.check(write_manifest(tmp_path, ["small_fast"]), devices) == gp.EXIT_OK + assert gp.check(write_manifest(tmp_path, ["big_slow"]), devices) == gp.EXIT_UNQUALIFIED + problems = gp.load_device(devices, "big_slow").problems() + assert problems == [ + "watchdog allows 120000 bytecodes per event; the job runner needs 240000 at 768 KB (change Jobs.stepsPerTick)" + ] |
