diff --git a/cereal b/cereal index d6c3cf6b33..932c44c6bd 160000 --- a/cereal +++ b/cereal @@ -1 +1 @@ -Subproject commit d6c3cf6b33e699f82e5d78ae22c74cad978830b6 +Subproject commit 932c44c6bda17d7e19e1f58cd26442560a562696 diff --git a/opendbc b/opendbc index eb56fff37a..004db342a8 160000 --- a/opendbc +++ b/opendbc @@ -1 +1 @@ -Subproject commit eb56fff37a4a2738df7add08779db51a0a6f38e2 +Subproject commit 004db342a825155f7bd03e7d08f3861e18b23795 diff --git a/selfdrive/car/body/interface.py b/selfdrive/car/body/interface.py index 379e89f624..2b44200397 100644 --- a/selfdrive/car/body/interface.py +++ b/selfdrive/car/body/interface.py @@ -37,13 +37,9 @@ class CarInterface(CarInterfaceBase): return ret - def update(self, c, can_strings): - self.cp.update_strings(can_strings) - + def _update(self, c): ret = self.CS.update(self.cp) - ret.canValid = self.cp.can_valid - # wait for everything to init first if self.frame > int(5. / DT_CTRL): # body always wants to enable @@ -52,8 +48,7 @@ class CarInterface(CarInterfaceBase): ret.events[0].enable = True self.frame += 1 - self.CS.out = ret.as_reader() - return self.CS.out + return ret def apply(self, c): return self.CC.update(c, self.CS) diff --git a/selfdrive/car/chrysler/interface.py b/selfdrive/car/chrysler/interface.py index 1bc34dff4d..7751bd151b 100755 --- a/selfdrive/car/chrysler/interface.py +++ b/selfdrive/car/chrysler/interface.py @@ -47,16 +47,9 @@ class CarInterface(CarInterfaceBase): return ret # returns a car.CarState - def update(self, c, can_strings): - # ******************* do can recv ******************* - self.cp.update_strings(can_strings) - self.cp_cam.update_strings(can_strings) - + def _update(self, c): ret = self.CS.update(self.cp, self.cp_cam) - ret.canValid = self.cp.can_valid and self.cp_cam.can_valid - - # speeds ret.steeringRateLimited = self.CC.steer_rate_limited if self.CC is not None else False # events @@ -67,10 +60,7 @@ class CarInterface(CarInterfaceBase): ret.events = events.to_msg() - # copy back carState packet to CS - self.CS.out = ret.as_reader() - - return self.CS.out + return ret # pass in a car.CarControl # to be called @ 100hz diff --git a/selfdrive/car/ford/interface.py b/selfdrive/car/ford/interface.py index 3b15f03c91..438c304882 100755 --- a/selfdrive/car/ford/interface.py +++ b/selfdrive/car/ford/interface.py @@ -41,15 +41,9 @@ class CarInterface(CarInterfaceBase): return ret - # returns a car.CarState - def update(self, c, can_strings): - # ******************* do can recv ******************* - self.cp.update_strings(can_strings) - + def _update(self, c): ret = self.CS.update(self.cp) - ret.canValid = self.cp.can_valid - # events events = self.create_common_events(ret) @@ -58,8 +52,7 @@ class CarInterface(CarInterfaceBase): ret.events = events.to_msg() - self.CS.out = ret.as_reader() - return self.CS.out + return ret # pass in a car.CarControl # to be called @ 100hz diff --git a/selfdrive/car/gm/interface.py b/selfdrive/car/gm/interface.py index 5787dc5ae8..64ec9d4242 100755 --- a/selfdrive/car/gm/interface.py +++ b/selfdrive/car/gm/interface.py @@ -155,13 +155,9 @@ class CarInterface(CarInterfaceBase): return ret # returns a car.CarState - def update(self, c, can_strings): - self.cp.update_strings(can_strings) - self.cp_loopback.update_strings(can_strings) - + def _update(self, c): ret = self.CS.update(self.cp, self.cp_loopback) - ret.canValid = self.cp.can_valid and self.cp_loopback.can_valid ret.steeringRateLimited = self.CC.steer_rate_limited if self.CC is not None else False buttonEvents = [] @@ -210,10 +206,7 @@ class CarInterface(CarInterfaceBase): ret.events = events.to_msg() - # copy back carState packet to CS - self.CS.out = ret.as_reader() - - return self.CS.out + return ret def apply(self, c): ret = self.CC.update(c, self.CS) diff --git a/selfdrive/car/honda/interface.py b/selfdrive/car/honda/interface.py index 8a23154bc9..265175d940 100755 --- a/selfdrive/car/honda/interface.py +++ b/selfdrive/car/honda/interface.py @@ -328,17 +328,9 @@ class CarInterface(CarInterfaceBase): disable_ecu(logcan, sendcan, bus=1, addr=0x18DAB0F1, com_cont_req=b'\x28\x83\x03') # returns a car.CarState - def update(self, c, can_strings): - # ******************* do can recv ******************* - self.cp.update_strings(can_strings) - self.cp_cam.update_strings(can_strings) - if self.cp_body: - self.cp_body.update_strings(can_strings) - + def _update(self, c): ret = self.CS.update(self.cp, self.cp_cam, self.cp_body) - ret.canValid = self.cp.can_valid and self.cp_cam.can_valid and (self.cp_body is None or self.cp_body.can_valid) - buttonEvents = [] if self.CS.cruise_buttons != self.CS.prev_cruise_buttons: @@ -412,11 +404,9 @@ class CarInterface(CarInterfaceBase): ret.events = events.to_msg() - self.CS.out = ret.as_reader() - return self.CS.out + return ret # pass in a car.CarControl # to be called @ 100hz def apply(self, c): - ret = self.CC.update(c, self.CS) - return ret + return self.CC.update(c, self.CS) diff --git a/selfdrive/car/hyundai/interface.py b/selfdrive/car/hyundai/interface.py index 4bb24ba4ea..ba74c23e47 100644 --- a/selfdrive/car/hyundai/interface.py +++ b/selfdrive/car/hyundai/interface.py @@ -297,12 +297,8 @@ class CarInterface(CarInterfaceBase): if CP.openpilotLongitudinalControl: disable_ecu(logcan, sendcan, addr=0x7d0, com_cont_req=b'\x28\x83\x01') - def update(self, c, can_strings): - self.cp.update_strings(can_strings) - self.cp_cam.update_strings(can_strings) - + def _update(self, c): ret = self.CS.update(self.cp, self.cp_cam) - ret.canValid = self.cp.can_valid and self.cp_cam.can_valid ret.steeringRateLimited = self.CC.steer_rate_limited if self.CC is not None else False events = self.create_common_events(ret, pcm_enable=self.CS.CP.pcmCruise) @@ -352,8 +348,7 @@ class CarInterface(CarInterfaceBase): ret.events = events.to_msg() - self.CS.out = ret.as_reader() - return self.CS.out + return ret def apply(self, c): ret = self.CC.update(c, self.CS) diff --git a/selfdrive/car/interfaces.py b/selfdrive/car/interfaces.py index ddf67e4d62..2d4b3416a4 100644 --- a/selfdrive/car/interfaces.py +++ b/selfdrive/car/interfaces.py @@ -33,12 +33,17 @@ class CarInterfaceBase(ABC): self.low_speed_alert = False self.silent_steer_warning = True + self.CS = None + self.can_parsers = [] if CarState is not None: self.CS = CarState(CP) + self.cp = self.CS.get_can_parser(CP) self.cp_cam = self.CS.get_cam_can_parser(CP) + self.cp_adas = self.CS.get_adas_can_parser(CP) self.cp_body = self.CS.get_body_can_parser(CP) self.cp_loopback = self.CS.get_loopback_can_parser(CP) + self.can_parsers = [self.cp, self.cp_cam, self.cp_adas, self.cp_body, self.cp_loopback] self.CC = None if CarController is not None: @@ -100,9 +105,28 @@ class CarInterfaceBase(ABC): return ret @abstractmethod - def update(self, c: car.CarControl, can_strings: List[bytes]) -> car.CarState: + def _update(self, c: car.CarControl) -> car.CarState: pass + def update(self, c: car.CarControl, can_strings: List[bytes]) -> car.CarState: + # parse can + for cp in self.can_parsers: + if cp is not None: + cp.update_strings(can_strings) + + # get CarState + ret = self._update(c) + + ret.canValid = all(cp.can_valid for cp in self.can_parsers if cp is not None) + ret.canTimeout = any(cp.bus_timeout for cp in self.can_parsers if cp is not None) + + # copy back for next iteration + reader = ret.as_reader() + if self.CS is not None: + self.CS.out = reader + + return reader + @abstractmethod def apply(self, c: car.CarControl) -> Tuple[car.CarControl.Actuators, List[bytes]]: pass @@ -254,6 +278,10 @@ class CarStateBase(ABC): def get_cam_can_parser(CP): return None + @staticmethod + def get_adas_can_parser(CP): + return None + @staticmethod def get_body_can_parser(CP): return None diff --git a/selfdrive/car/mazda/interface.py b/selfdrive/car/mazda/interface.py index b9a3d66ff2..0ef573c6b6 100755 --- a/selfdrive/car/mazda/interface.py +++ b/selfdrive/car/mazda/interface.py @@ -75,13 +75,8 @@ class CarInterface(CarInterfaceBase): return ret # returns a car.CarState - def update(self, c, can_strings): - - self.cp.update_strings(can_strings) - self.cp_cam.update_strings(can_strings) - + def _update(self, c): ret = self.CS.update(self.cp, self.cp_cam) - ret.canValid = self.cp.can_valid and self.cp_cam.can_valid # events events = self.create_common_events(ret) @@ -93,8 +88,7 @@ class CarInterface(CarInterfaceBase): ret.events = events.to_msg() - self.CS.out = ret.as_reader() - return self.CS.out + return ret def apply(self, c): ret = self.CC.update(c, self.CS, self.frame) diff --git a/selfdrive/car/mock/interface.py b/selfdrive/car/mock/interface.py index 79f37097c8..65e886751d 100755 --- a/selfdrive/car/mock/interface.py +++ b/selfdrive/car/mock/interface.py @@ -48,7 +48,7 @@ class CarInterface(CarInterfaceBase): return ret # returns a car.CarState - def update(self, c, can_strings): + def _update(self, c): # get basic data from phone and gps since CAN isn't connected sensors = messaging.recv_sock(self.sensor) if sensors is not None: @@ -63,7 +63,6 @@ class CarInterface(CarInterfaceBase): # create message ret = car.CarState.new_message() - ret.canValid = True # speeds ret.vEgo = self.speed @@ -83,7 +82,7 @@ class CarInterface(CarInterfaceBase): curvature = self.yaw_rate / max(self.speed, 1.) ret.steeringAngleDeg = curvature * self.CP.steerRatio * self.CP.wheelbase * CV.RAD_TO_DEG - return ret.as_reader() + return ret def apply(self, c): # in mock no carcontrols diff --git a/selfdrive/car/nissan/interface.py b/selfdrive/car/nissan/interface.py index c078556434..3bf34e8266 100644 --- a/selfdrive/car/nissan/interface.py +++ b/selfdrive/car/nissan/interface.py @@ -5,9 +5,6 @@ from selfdrive.car import STD_CARGO_KG, scale_rot_inertia, scale_tire_stiffness, from selfdrive.car.interfaces import CarInterfaceBase class CarInterface(CarInterfaceBase): - def __init__(self, CP, CarController, CarState): - super().__init__(CP, CarController, CarState) - self.cp_adas = self.CS.get_adas_can_parser(CP) @staticmethod def get_params(candidate, fingerprint=gen_empty_fingerprint(), car_fw=None, disable_radar=False): @@ -53,15 +50,9 @@ class CarInterface(CarInterfaceBase): return ret # returns a car.CarState - def update(self, c, can_strings): - self.cp.update_strings(can_strings) - self.cp_cam.update_strings(can_strings) - self.cp_adas.update_strings(can_strings) - + def _update(self, c): ret = self.CS.update(self.cp, self.cp_adas, self.cp_cam) - ret.canValid = self.cp.can_valid and self.cp_adas.can_valid and self.cp_cam.can_valid - buttonEvents = [] be = car.CarState.ButtonEvent.new_message() be.type = car.CarState.ButtonEvent.Type.accelCruise @@ -74,8 +65,7 @@ class CarInterface(CarInterfaceBase): ret.events = events.to_msg() - self.CS.out = ret.as_reader() - return self.CS.out + return ret def apply(self, c): hud_control = c.hudControl diff --git a/selfdrive/car/subaru/interface.py b/selfdrive/car/subaru/interface.py index 37330f0e30..d0d8e91ce1 100644 --- a/selfdrive/car/subaru/interface.py +++ b/selfdrive/car/subaru/interface.py @@ -107,19 +107,15 @@ class CarInterface(CarInterfaceBase): return ret # returns a car.CarState - def update(self, c, can_strings): - self.cp.update_strings(can_strings) - self.cp_cam.update_strings(can_strings) + def _update(self, c): ret = self.CS.update(self.cp, self.cp_cam) - ret.canValid = self.cp.can_valid and self.cp_cam.can_valid ret.steeringRateLimited = self.CC.steer_rate_limited if self.CC is not None else False ret.events = self.create_common_events(ret).to_msg() - self.CS.out = ret.as_reader() - return self.CS.out + return ret def apply(self, c): hud_control = c.hudControl diff --git a/selfdrive/car/tesla/interface.py b/selfdrive/car/tesla/interface.py index 14d8e32de4..71594cecb6 100755 --- a/selfdrive/car/tesla/interface.py +++ b/selfdrive/car/tesla/interface.py @@ -57,18 +57,12 @@ class CarInterface(CarInterfaceBase): return ret - def update(self, c, can_strings): - self.cp.update_strings(can_strings) - self.cp_cam.update_strings(can_strings) - + def _update(self, c): ret = self.CS.update(self.cp, self.cp_cam) - ret.canValid = self.cp.can_valid and self.cp_cam.can_valid - events = self.create_common_events(ret) + ret.events = self.create_common_events(ret).to_msg() - ret.events = events.to_msg() - self.CS.out = ret.as_reader() - return self.CS.out + return ret def apply(self, c): ret = self.CC.update(c, self.CS) diff --git a/selfdrive/car/toyota/interface.py b/selfdrive/car/toyota/interface.py index dc0c64ad1b..f7d5aba7ab 100644 --- a/selfdrive/car/toyota/interface.py +++ b/selfdrive/car/toyota/interface.py @@ -240,14 +240,9 @@ class CarInterface(CarInterfaceBase): return ret # returns a car.CarState - def update(self, c, can_strings): - # ******************* do can recv ******************* - self.cp.update_strings(can_strings) - self.cp_cam.update_strings(can_strings) - + def _update(self, c): ret = self.CS.update(self.cp, self.cp_cam) - ret.canValid = self.cp.can_valid and self.cp_cam.can_valid ret.steeringRateLimited = self.CC.steer_rate_limited if self.CC is not None else False # events @@ -266,8 +261,7 @@ class CarInterface(CarInterfaceBase): ret.events = events.to_msg() - self.CS.out = ret.as_reader() - return self.CS.out + return ret # pass in a car.CarControl # to be called @ 100hz diff --git a/selfdrive/car/volkswagen/interface.py b/selfdrive/car/volkswagen/interface.py index ef42d63e96..b0fd08ccfc 100644 --- a/selfdrive/car/volkswagen/interface.py +++ b/selfdrive/car/volkswagen/interface.py @@ -161,17 +161,10 @@ class CarInterface(CarInterfaceBase): return ret # returns a car.CarState - def update(self, c, can_strings): + def _update(self, c): buttonEvents = [] - # Process the most recent CAN message traffic, and check for validity - # The camera CAN has no signals we use at this time, but we process it - # anyway so we can test connectivity with can_valid - self.cp.update_strings(can_strings) - self.cp_cam.update_strings(can_strings) - ret = self.CS.update(self.cp, self.cp_cam, self.cp_ext, self.CP.transmissionType) - ret.canValid = self.cp.can_valid and self.cp_cam.can_valid ret.steeringRateLimited = self.CC.steer_rate_limited if self.CC is not None else False # Check for and process state-change events (button press or release) from @@ -204,8 +197,7 @@ class CarInterface(CarInterfaceBase): self.displayMetricUnitsPrev = self.CS.displayMetricUnits self.buttonStatesPrev = self.CS.buttonStates.copy() - self.CS.out = ret.as_reader() - return self.CS.out + return ret def apply(self, c): hud_control = c.hudControl diff --git a/selfdrive/controls/controlsd.py b/selfdrive/controls/controlsd.py index 25b0c41419..e4db679b31 100755 --- a/selfdrive/controls/controlsd.py +++ b/selfdrive/controls/controlsd.py @@ -270,7 +270,9 @@ class Controls: LaneChangeState.laneChangeFinishing): self.events.add(EventName.laneChange) - if not CS.canValid: + if CS.canTimeout: + self.events.add(EventName.canBusMissing) + elif not CS.canValid: self.events.add(EventName.canError) for i, pandaState in enumerate(self.sm['pandaStates']): diff --git a/selfdrive/controls/lib/events.py b/selfdrive/controls/lib/events.py index a355f14623..ad91fbcab0 100644 --- a/selfdrive/controls/lib/events.py +++ b/selfdrive/controls/lib/events.py @@ -757,7 +757,7 @@ EVENTS: Dict[int, Dict[str, Union[Alert, AlertCallbackType]]] = { # - CAN data is received, but some message are not received at the right frequency # If you're not writing a new car port, this is usually cause by faulty wiring EventName.canError: { - ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("CAN Error: Check Connections"), + ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("CAN Error"), ET.PERMANENT: Alert( "CAN Error: Check Connections", "", @@ -766,7 +766,15 @@ EVENTS: Dict[int, Dict[str, Union[Alert, AlertCallbackType]]] = { ET.NO_ENTRY: NoEntryAlert("CAN Error: Check Connections"), }, - EventName.canBusMissing: {}, + EventName.canBusMissing: { + ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("CAN Bus Disconnected"), + ET.PERMANENT: Alert( + "CAN Bus Disconnected: Likely Faulty Cable", + "", + AlertStatus.normal, AlertSize.small, + Priority.LOW, VisualAlert.none, AudibleAlert.none, 1., creation_delay=1.), + ET.NO_ENTRY: NoEntryAlert("CAN Bus Disconnected: Check Connections"), + }, EventName.steerUnavailable: { ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("LKAS Fault: Restart the Car"), diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 79349868dd..b6b5465f31 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -de01f1544a1441f89c24c5ea587f3f99632f2b5a \ No newline at end of file +dea753b12032ad2c50b4a163a3077a8530267800 \ No newline at end of file