""" Copyright (c) 2021-, Haibin Wen, sunnypilot, and a number of other contributors. This file is part of sunnypilot and is licensed under the MIT License. See the LICENSE.md file in the root directory for more details. """ import time import cereal.messaging as messaging from cereal import log, custom from opendbc.car import structs from openpilot.common.params import Params from openpilot.common.swaglog import cloudlog from openpilot.sunnypilot import PARAMS_UPDATE_PERIOD from openpilot.sunnypilot.livedelay.helpers import get_lat_delay from openpilot.sunnypilot.modeld.modeld_base import ModelStateBase from openpilot.sunnypilot.selfdrive.controls.lib.blinker_pause_lateral import BlinkerPauseLateral class ControlsExt(ModelStateBase): def __init__(self, CP: structs.CarParams, params: Params): ModelStateBase.__init__(self) self.CP = CP self.params = params self._param_update_time: float = 0.0 self.blinker_pause_lateral = BlinkerPauseLateral() cloudlog.info("controlsd_ext is waiting for CarParamsSP") self.CP_SP = messaging.log_from_bytes(params.get("CarParamsSP", block=True), custom.CarParamsSP) cloudlog.info("controlsd_ext got CarParamsSP") self.sm_services_ext = ['radarState', 'selfdriveStateSP'] self.pm_services_ext = ['carControlSP'] def get_params_sp(self, sm: messaging.SubMaster) -> None: if time.monotonic() - self._param_update_time > PARAMS_UPDATE_PERIOD: self.blinker_pause_lateral.get_params() if self.CP.lateralTuning.which() == 'torque': self.lat_delay = get_lat_delay(self.params, sm["liveDelay"].lateralDelay) self._param_update_time = time.monotonic() def get_lat_active(self, sm: messaging.SubMaster) -> bool: if self.blinker_pause_lateral.update(sm['carState']): return False ss_sp = sm['selfdriveStateSP'] if ss_sp.mads.available: return bool(ss_sp.mads.active) # MADS not available, use stock state to engage return bool(sm['selfdriveState'].active) @staticmethod def get_lead_data(ld: log.RadarState.LeadData) -> dict: return { "dRel": ld.dRel, "yRel": ld.yRel, "vRel": ld.vRel, "aRel": ld.aRel, "vLead": ld.vLead, "dPath": ld.dPath, "vLat": ld.vLat, "vLeadK": ld.vLeadK, "aLeadK": ld.aLeadK, "fcw": ld.fcw, "status": ld.status, "aLeadTau": ld.aLeadTau, "modelProb": ld.modelProb, "radar": ld.radar, "radarTrackId": ld.radarTrackId, } def state_control_ext(self, sm: messaging.SubMaster) -> custom.CarControlSP: CC_SP = custom.CarControlSP.new_message() CC_SP.leadOne = self.get_lead_data(sm['radarState'].leadOne) CC_SP.leadTwo = self.get_lead_data(sm['radarState'].leadTwo) # MADS state CC_SP.mads = sm['selfdriveStateSP'].mads CC_SP.intelligentCruiseButtonManagement = sm['selfdriveStateSP'].intelligentCruiseButtonManagement return CC_SP @staticmethod def publish_ext(CC_SP: custom.CarControlSP, sm: messaging.SubMaster, pm: messaging.PubMaster) -> None: cc_sp_send = messaging.new_message('carControlSP') cc_sp_send.valid = sm['carState'].canValid cc_sp_send.carControlSP = CC_SP pm.send('carControlSP', cc_sp_send) def run_ext(self, sm: messaging.SubMaster, pm: messaging.PubMaster) -> None: CC_SP = self.state_control_ext(sm) self.publish_ext(CC_SP, sm, pm)