优化了副驾座椅控制
This commit is contained in:
@@ -43,18 +43,24 @@ MQTT_VALID_FD_PAYLOAD_LENGTHS = frozenset(
|
||||
)
|
||||
MQTT_SAFETY_FEEDBACK_IDS = frozenset({0x342, 0x4EB})
|
||||
MQTT_VEHICLE_FEEDBACK_IDS = OBSERVABLE_IDS | frozenset({0x2F5, 0x37B})
|
||||
# Frames accepted from the Android head unit are the seat-ota wire protocol.
|
||||
# ``0x302`` is an internal compatibility frame synthesized below so the
|
||||
# existing seat-domain state reader can consume the four firmware axes; it is
|
||||
# deliberately not accepted as authoritative MQTT input.
|
||||
MQTT_SEAT_WIRE_FEEDBACK_IDS = frozenset({0x6A0, 0x6A2})
|
||||
MQTT_SEAT_FEEDBACK_IDS = frozenset({0x302, 0x6A2})
|
||||
# CAN0 accepts both state formats currently emitted by the passenger-seat
|
||||
# stack. The production firmware publishes its authoritative classic-CAN
|
||||
# status directly on 0x301..0x306/0x4FA. Older head-unit builds expose the
|
||||
# read-only seat-ota request/response exchange on 0x6A0/0x6A2; that exchange is
|
||||
# retained and translated to an internal 0x302 position frame below.
|
||||
MQTT_SEAT_NATIVE_FEEDBACK_IDS = frozenset(
|
||||
{0x301, 0x302, 0x303, 0x304, 0x305, 0x306, 0x4FA}
|
||||
)
|
||||
MQTT_SEAT_WIRE_FEEDBACK_IDS = MQTT_SEAT_NATIVE_FEEDBACK_IDS | frozenset(
|
||||
{0x6A0, 0x6A2}
|
||||
)
|
||||
MQTT_SEAT_FEEDBACK_IDS = MQTT_SEAT_NATIVE_FEEDBACK_IDS | frozenset({0x6A2})
|
||||
MQTT_ACCEPTED_FEEDBACK_IDS = {
|
||||
0: MQTT_SEAT_FEEDBACK_IDS,
|
||||
1: MQTT_VEHICLE_FEEDBACK_IDS,
|
||||
}
|
||||
MQTT_APPROVED_CONTROL_IDS = {
|
||||
0: frozenset({0x6A0}),
|
||||
0: frozenset({0x29E, 0x3CE, 0x6A0}),
|
||||
1: frozenset({0x1DE, 0x32B, 0x3FC, 0x431, 0x4C1, 0x4EF, 0x4F5}),
|
||||
}
|
||||
MQTT_OTA_SEAT_RUNTIME_OPCODES = frozenset({0x63, 0x64, 0x65, 0x66})
|
||||
@@ -449,6 +455,39 @@ def _validate_ota_seat_runtime_control(data: bytes) -> None:
|
||||
)
|
||||
|
||||
|
||||
def _validate_native_seat_thermal_control(frame: CanFrame) -> None:
|
||||
"""Validate the two runtime thermal frames implemented by the CAN0 firmware."""
|
||||
|
||||
if len(frame.data) != 8:
|
||||
raise CanGatewayError("CAN0 passenger-seat thermal control requires DLC 8")
|
||||
if frame.arbitration_id == 0x3CE:
|
||||
mode = (frame.data[0] >> 4) & 0x03
|
||||
if mode not in {1, 2} or frame.data[0] & 0xCF or any(frame.data[1:]):
|
||||
raise CanGatewayError("CAN0 0x3CE thermal mode payload is invalid")
|
||||
return
|
||||
if frame.arbitration_id != 0x29E:
|
||||
raise CanGatewayError("CAN0 native thermal frame ID is invalid")
|
||||
fan_on = frame.data[0] & 0x03
|
||||
fan_mode = (frame.data[0] >> 2) & 0x03
|
||||
heating_on = (frame.data[0] >> 4) & 0x03
|
||||
fan_level = frame.data[2] & 0x0F
|
||||
heating_level = (frame.data[2] >> 4) & 0x0F
|
||||
if (
|
||||
fan_on not in {1, 2}
|
||||
or fan_mode != 1
|
||||
or heating_on not in {1, 2}
|
||||
or fan_level not in range(4)
|
||||
or heating_level not in range(4)
|
||||
or (fan_on == 1 and fan_level == 0)
|
||||
or (fan_on == 2 and fan_level != 0)
|
||||
or (heating_on == 1 and heating_level == 0)
|
||||
or (heating_on == 2 and heating_level != 0)
|
||||
or frame.data[1] != 0
|
||||
or any(frame.data[3:])
|
||||
):
|
||||
raise CanGatewayError("CAN0 0x29E thermal control payload is invalid")
|
||||
|
||||
|
||||
class MqttCanTransport:
|
||||
"""One process-wide MQTT connection serving snapshots and executor buses."""
|
||||
|
||||
@@ -633,7 +672,7 @@ class MqttCanTransport:
|
||||
discriminator = (
|
||||
frame.data[0]
|
||||
if frame.channel == 0
|
||||
and frame.arbitration_id == 0x302
|
||||
and frame.arbitration_id in {0x302, 0x303, 0x304}
|
||||
and frame.data
|
||||
else 0
|
||||
)
|
||||
@@ -751,7 +790,15 @@ class MqttCanTransport:
|
||||
initial_frames = tuple(
|
||||
frame
|
||||
for (seen_channel, _frame_id, _discriminator),
|
||||
(captured_monotonic, frame) in sorted(self._latest_bus_frames.items())
|
||||
(captured_monotonic, frame) in sorted(
|
||||
self._latest_bus_frames.items(),
|
||||
key=lambda item: (
|
||||
0 if item[0][1] == 0x306 else
|
||||
1 if item[0][1] == 0x4FA else
|
||||
2,
|
||||
item[0],
|
||||
),
|
||||
)
|
||||
if replay_latest
|
||||
and seen_channel == channel
|
||||
and now - captured_monotonic <= self.freshness_s
|
||||
@@ -772,8 +819,10 @@ class MqttCanTransport:
|
||||
if frame.channel == 0 and (frame.is_fd or frame.bitrate_switch):
|
||||
raise CanGatewayError("CAN0 passenger-seat control requires classic CAN")
|
||||
_validate_headunit_command_frame(frame)
|
||||
if frame.channel == 0:
|
||||
if frame.channel == 0 and frame.arbitration_id == 0x6A0:
|
||||
_validate_ota_seat_runtime_control(frame.data)
|
||||
elif frame.channel == 0:
|
||||
_validate_native_seat_thermal_control(frame)
|
||||
with self._condition:
|
||||
client = self._client
|
||||
state = self._state
|
||||
|
||||
Reference in New Issue
Block a user