Skip to content

Commit 4f3c2d0

Browse files
authored
Fix System Failure Tracer Logic (#214)
* Implemented a stringifier. (#210) * Separated callback methods into system callback and device callback. (#210) * Separated callback methods into system callback and device callback. (#210) * Included error in `on_device_fail()`. (#210)
1 parent aa1a4a0 commit 4f3c2d0

3 files changed

Lines changed: 26 additions & 8 deletions

File tree

leads/dt/device.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ def __init__(self, *pins: int | str) -> None:
1515
self._parent_tags: tuple[str, ...] = ()
1616
self._pins: tuple[int | str, ...] = pins
1717

18+
@_override
19+
def __str__(self) -> str:
20+
return f"{len(self._parent_tags)}.{self._tag}"
21+
1822
def level(self) -> int:
1923
"""
2024
Get the level of the device in the device tree.

leads/sft.py

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,25 +19,39 @@ def read_marked_system(device: Device) -> list[str] | None:
1919
class SystemFailureTracer(object):
2020
def __init__(self) -> None:
2121
super().__init__()
22-
self.on_fail: _Callable[[Device, SuspensionEvent], None] = lambda _, __: None
23-
self.on_recover: _Callable[[Device, SuspensionEvent], None] = lambda _, __: None
22+
self.on_fail: _Callable[[SuspensionEvent], None] = lambda _: None
23+
self.on_recover: _Callable[[SuspensionEvent], None] = lambda _: None
24+
self.on_device_fail: _Callable[[Device, str | Exception], None] = lambda _, __: None
25+
self.on_device_recover: _Callable[[Device], None] = lambda _: None
26+
self._system_failure: dict[str, int] = {}
2427

2528
def fail(self, device: Device, error: str | Exception) -> None:
2629
if isinstance(error, Exception):
2730
error = repr(error)
2831
if not (systems := read_marked_system(device)):
2932
raise RuntimeWarning(f"No system marked for device {device}")
33+
self.on_device_fail(device, error)
34+
L.error(f"{device} error: {error}")
3035
for system in systems:
31-
self.on_fail(device, e := SuspensionEvent(context := require_context(), system, error))
36+
if system not in self._system_failure:
37+
self._system_failure[system] = 0
38+
self._system_failure[system] += 1
39+
self.on_fail(e := SuspensionEvent(context := require_context(), system, error))
3240
context.suspend(e)
33-
L.error(f"{system} error: {error}")
3441

3542
def recover(self, device: Device) -> None:
3643
if not (systems := read_marked_system(device)):
3744
raise RuntimeWarning(f"System not marked for device {device}")
45+
self.on_device_recover(device)
46+
L.debug(f"{device} recovered")
3847
for system in systems:
39-
self.on_recover(device, SuspensionEvent(require_context(), system, "Recovered"))
40-
L.info(f"{system} recovered")
48+
if system not in self._system_failure:
49+
continue
50+
self._system_failure[system] -= 1
51+
if self._system_failure[system] > 0:
52+
continue
53+
self._system_failure.pop(system)
54+
self.on_recover(SuspensionEvent(require_context(), system, "Recovered"))
4155

4256

4357
SFT: SystemFailureTracer = SystemFailureTracer()

leads_vec/cli.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,7 @@ def hazard(self, e: Event, state: bool) -> None:
250250
uim["motor_fault"] = _Label(root, text="")
251251
uim["wsc_fault"] = _Label(root, text="")
252252

253-
def on_fail(_, e: SuspensionEvent) -> None:
253+
def on_fail(e: SuspensionEvent) -> None:
254254
match e.system:
255255
case "BATT":
256256
uim["battery_fault"].configure(image=Battery(color=Color.RED))
@@ -267,7 +267,7 @@ def on_fail(_, e: SuspensionEvent) -> None:
267267

268268
SFT.on_fail = on_fail
269269

270-
def on_recover(_, e: SuspensionEvent) -> None:
270+
def on_recover(e: SuspensionEvent) -> None:
271271
match e.system:
272272
case "BATT":
273273
uim["battery_fault"].configure(image=None)

0 commit comments

Comments
 (0)