feat: update CAN integration and T2G seat firmware
This commit is contained in:
@@ -10,7 +10,7 @@ from pathlib import Path
|
||||
from typing import Any, Callable
|
||||
|
||||
from cognitive_agent.infrastructure.firmware import (
|
||||
EXPECTED_IDENTITY_PAYLOAD,
|
||||
FIRMWARE_PROTOCOL_SIGNATURE,
|
||||
FirmwareProgrammingError,
|
||||
T2GFirmwareGuard,
|
||||
T2GSeatProgrammer,
|
||||
@@ -21,17 +21,14 @@ from .gateway import CanBus, CanGatewayError, PythonCanBus, ZlgCanBridgeBus
|
||||
|
||||
TRUE_VALUES = {"1", "true", "yes", "on"}
|
||||
VALID_PROFILES = {"combined"}
|
||||
SHARED_PHYSICAL_TARGETS = {
|
||||
("front_left", "driver"),
|
||||
("front_right", "passenger"),
|
||||
}
|
||||
SUPPORTED_PHYSICAL_TARGET = ("front_right", "passenger")
|
||||
CAPABILITY_PROFILE = {
|
||||
"seat.set_heating": "combined",
|
||||
"seat.set_ventilation": "combined",
|
||||
"seat.set_longitudinal_position": "combined",
|
||||
"seat.set_cushion_tilt": "combined",
|
||||
"seat.set_backrest_recline": "combined",
|
||||
"seat.set_legrest_height": "combined",
|
||||
"seat.set_legrest_extension": "combined",
|
||||
}
|
||||
|
||||
|
||||
@@ -76,6 +73,7 @@ class SeatHardwareSettings:
|
||||
|
||||
repository_root: Path
|
||||
enabled: bool
|
||||
approval_required: bool
|
||||
approval_token: str
|
||||
profiles: frozenset[str]
|
||||
backend: str
|
||||
@@ -87,13 +85,13 @@ class SeatHardwareSettings:
|
||||
zlg_python: Path
|
||||
zlg_dll: Path
|
||||
bridge_script: Path
|
||||
sdk_root: Path
|
||||
cspybat: Path
|
||||
auto_flash_enabled: bool
|
||||
auto_home_enabled: bool
|
||||
home_timeout_s: int
|
||||
firmware_probe_timeout_ms: int
|
||||
firmware_boot_wait_ms: int
|
||||
firmware_program_timeout_ms: int
|
||||
allow_unverified_longitudinal: bool
|
||||
thermal_timeout_ms: int
|
||||
ack_timeout_ms: int
|
||||
firmware_images: dict[str, Path]
|
||||
@@ -102,12 +100,11 @@ class SeatHardwareSettings:
|
||||
|
||||
@classmethod
|
||||
def from_env(cls, repository_root: Path) -> "SeatHardwareSettings":
|
||||
sdk_root = Path(
|
||||
os.getenv(
|
||||
"COGNITIVE_AGENT_T2G_SDK_ROOT",
|
||||
r"C:\Users\D30042075206\Desktop\T2G_Sample_Driver_Library_7.9.0",
|
||||
)
|
||||
).expanduser()
|
||||
hardware_enabled = _env_bool("COGNITIVE_AGENT_HARDWARE_EXECUTION_ENABLED")
|
||||
auto_flash_enabled = _env_bool(
|
||||
"COGNITIVE_AGENT_SEAT_AUTO_FLASH_ENABLED",
|
||||
default=hardware_enabled,
|
||||
)
|
||||
backend = os.getenv("COGNITIVE_AGENT_SEAT_CAN_BACKEND", "zlgcan").strip().lower()
|
||||
if backend not in {"zlgcan", "python-can"}:
|
||||
raise HardwareSafetyError(
|
||||
@@ -135,7 +132,11 @@ class SeatHardwareSettings:
|
||||
}
|
||||
return cls(
|
||||
repository_root=repository_root,
|
||||
enabled=_env_bool("COGNITIVE_AGENT_HARDWARE_EXECUTION_ENABLED"),
|
||||
enabled=hardware_enabled,
|
||||
approval_required=_env_bool(
|
||||
"COGNITIVE_AGENT_HARDWARE_APPROVAL_TOKEN_REQUIRED",
|
||||
default=True,
|
||||
),
|
||||
approval_token=os.getenv("COGNITIVE_AGENT_HARDWARE_APPROVAL_TOKEN", ""),
|
||||
profiles=_profiles_from_env(),
|
||||
backend=backend,
|
||||
@@ -162,16 +163,19 @@ class SeatHardwareSettings:
|
||||
/ "infrastructure"
|
||||
/ "can"
|
||||
/ "zlgcan_bridge.py",
|
||||
sdk_root=sdk_root,
|
||||
cspybat=Path(
|
||||
os.getenv(
|
||||
"COGNITIVE_AGENT_IAR_CSPYBAT",
|
||||
r"D:\Program Files\IAR Systems\Embedded Workbench 9.2\common\bin\cspybat.exe",
|
||||
)
|
||||
),
|
||||
auto_flash_enabled=_env_bool("COGNITIVE_AGENT_SEAT_AUTO_FLASH_ENABLED"),
|
||||
auto_flash_enabled=auto_flash_enabled,
|
||||
auto_home_enabled=_env_bool("COGNITIVE_AGENT_SEAT_AUTO_HOME_ENABLED"),
|
||||
home_timeout_s=_env_int(
|
||||
"COGNITIVE_AGENT_SEAT_HOME_TIMEOUT_S", 120
|
||||
),
|
||||
firmware_probe_timeout_ms=_env_int(
|
||||
"COGNITIVE_AGENT_SEAT_FIRMWARE_PROBE_TIMEOUT_MS", 750
|
||||
"COGNITIVE_AGENT_SEAT_FIRMWARE_PROBE_TIMEOUT_MS", 1_200
|
||||
),
|
||||
firmware_boot_wait_ms=_env_int(
|
||||
"COGNITIVE_AGENT_SEAT_FIRMWARE_BOOT_WAIT_MS", 1_500
|
||||
@@ -179,9 +183,6 @@ class SeatHardwareSettings:
|
||||
firmware_program_timeout_ms=_env_int(
|
||||
"COGNITIVE_AGENT_SEAT_FIRMWARE_PROGRAM_TIMEOUT_MS", 120_000
|
||||
),
|
||||
allow_unverified_longitudinal=_env_bool(
|
||||
"COGNITIVE_AGENT_ENABLE_UNVERIFIED_LONGITUDINAL"
|
||||
),
|
||||
thermal_timeout_ms=_env_int(
|
||||
"COGNITIVE_AGENT_SEAT_THERMAL_TIMEOUT_MS", 2_000
|
||||
),
|
||||
@@ -207,7 +208,7 @@ class SeatHardwareSettings:
|
||||
def configured(self) -> bool:
|
||||
return bool(
|
||||
self.enabled
|
||||
and self.approval_token
|
||||
and (not self.approval_required or self.approval_token)
|
||||
and self.profiles
|
||||
and self.adapter_configured
|
||||
and all(self.firmware_images[item].is_file() for item in self.profiles)
|
||||
@@ -228,20 +229,25 @@ class SeatHardwareSettings:
|
||||
raise HardwareSafetyError(
|
||||
"hardware execution is disabled; set COGNITIVE_AGENT_HARDWARE_EXECUTION_ENABLED=true"
|
||||
)
|
||||
if not self.approval_token:
|
||||
raise HardwareSafetyError(
|
||||
"COGNITIVE_AGENT_HARDWARE_APPROVAL_TOKEN is not configured"
|
||||
)
|
||||
if not supplied_token or not hmac.compare_digest(
|
||||
supplied_token, self.approval_token
|
||||
):
|
||||
raise HardwareSafetyError("hardware approval token is invalid")
|
||||
if self.approval_required:
|
||||
if not self.approval_token:
|
||||
raise HardwareSafetyError(
|
||||
"COGNITIVE_AGENT_HARDWARE_APPROVAL_TOKEN is not configured"
|
||||
)
|
||||
if not supplied_token or not hmac.compare_digest(
|
||||
supplied_token, self.approval_token
|
||||
):
|
||||
raise HardwareSafetyError("hardware approval token is invalid")
|
||||
if not self.profiles:
|
||||
raise HardwareSafetyError(
|
||||
"the combined IAR seat-controller firmware profile is not selected"
|
||||
)
|
||||
if self.bitrate != 500_000:
|
||||
raise HardwareSafetyError("the verified T2G seat protocol requires 500000 bit/s")
|
||||
if not 10 <= self.home_timeout_s <= 600:
|
||||
raise HardwareSafetyError(
|
||||
"COGNITIVE_AGENT_SEAT_HOME_TIMEOUT_S must be between 10 and 600"
|
||||
)
|
||||
if not self.adapter_configured:
|
||||
raise HardwareSafetyError("the configured CAN adapter runtime is not ready")
|
||||
missing = [
|
||||
@@ -268,10 +274,9 @@ class SeatHardwareSettings:
|
||||
capability = str(operation.get("capability", ""))
|
||||
target = operation.get("target", {})
|
||||
target_key = (str(target.get("zone", "")), str(target.get("instance", "")))
|
||||
if target_key not in SHARED_PHYSICAL_TARGETS:
|
||||
if target_key != SUPPORTED_PHYSICAL_TARGET:
|
||||
raise HardwareSafetyError(
|
||||
"the T2G bench accepts driver/front_left and passenger/front_right; "
|
||||
"both aliases operate the same physical seat actuators"
|
||||
"the T2G bench accepts only passenger/front_right seat operations"
|
||||
)
|
||||
try:
|
||||
profile = CAPABILITY_PROFILE[capability]
|
||||
@@ -284,20 +289,7 @@ class SeatHardwareSettings:
|
||||
f"{capability} requires the '{profile}' firmware profile"
|
||||
)
|
||||
parameters = dict(operation.get("parameters", {}))
|
||||
previous = physical_requests.get(capability)
|
||||
if previous is not None and previous != parameters:
|
||||
raise HardwareSafetyError(
|
||||
f"driver and passenger requests conflict for shared physical capability {capability}"
|
||||
)
|
||||
physical_requests[capability] = parameters
|
||||
if (
|
||||
capability == "seat.set_longitudinal_position"
|
||||
and not self.allow_unverified_longitudinal
|
||||
):
|
||||
raise HardwareSafetyError(
|
||||
"longitudinal Motor3 is unwired/unverified; explicitly set "
|
||||
"COGNITIVE_AGENT_ENABLE_UNVERIFIED_LONGITUDINAL=true only after calibration"
|
||||
)
|
||||
|
||||
def bus_factory(self) -> Callable[[], CanBus]:
|
||||
if self.backend == "zlgcan":
|
||||
@@ -362,7 +354,7 @@ class SeatHardwareSettings:
|
||||
return {
|
||||
"enabled": self.enabled,
|
||||
"configured": self.configured,
|
||||
"approval_required": True,
|
||||
"approval_required": self.approval_required,
|
||||
"approval_configured": bool(self.approval_token),
|
||||
"platform": "t2g_seat_bench",
|
||||
"backend": self.backend,
|
||||
@@ -372,20 +364,23 @@ class SeatHardwareSettings:
|
||||
"frame_format": "classic_can_11_bit",
|
||||
"firmware_profiles": sorted(self.profiles),
|
||||
"firmware_images": images,
|
||||
"firmware_status": "identity_verified_before_each_hardware_request",
|
||||
"firmware_identity": EXPECTED_IDENTITY_PAYLOAD.hex(" ").upper(),
|
||||
"firmware_status": "passive_protocol_verified_before_each_hardware_request",
|
||||
"firmware_protocol_signature": FIRMWARE_PROTOCOL_SIGNATURE,
|
||||
"firmware_source": "repository",
|
||||
"auto_flash_enabled": self.auto_flash_enabled,
|
||||
"programmer_configured": self.programmer_configured,
|
||||
"programmer_backend": "iar_cspy_cmsisdap",
|
||||
"supported_targets": ["front_left", "front_right"],
|
||||
"supported_targets": ["front_right"],
|
||||
"supported_seat_instances": ["passenger"],
|
||||
"physical_target": "t2g_primary_seat",
|
||||
"target_aliasing": "driver_and_passenger_share_one_physical_actuator_group",
|
||||
"unverified_longitudinal_enabled": self.allow_unverified_longitudinal,
|
||||
"target_aliasing": "disabled_front_passenger_only",
|
||||
"auto_home_enabled": self.auto_home_enabled,
|
||||
"home_timeout_s": self.home_timeout_s,
|
||||
"limitations": [
|
||||
"hardware execution requires the unified Seat_Controller_demo image on one development board",
|
||||
"driver and passenger commands are aliases for the same physical motor/heater/fan group",
|
||||
"Motor3 longitudinal motion stays blocked until explicitly enabled after wiring and calibration",
|
||||
"cushion tilt has no physical actuator in Seat_Move_demo",
|
||||
"all seat capabilities are restricted to passenger/front_right",
|
||||
"M0/M1/M2/M3 map to horizontal, seat-pan, backrest and legrest on one physical seat",
|
||||
"known-range homing can move an invalid axis to its near endpoint and remains separately disabled by default",
|
||||
"current diagnostics use conservative bench thresholds and do not replace external power limiting",
|
||||
],
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user