def test_honda_checksum(self): """Test checksums for Honda standard and extended CAN ids""" dbc_file = "honda_accord_2018_can_generated" signals = [ ("CHECKSUM", "LKAS_HUD"), ("CHECKSUM", "LKAS_HUD_A"), ] checks = [("LKAS_HUD", 0), ("LKAS_HUD_A", 0)] parser = CANParser(dbc_file, signals, checks, 0) packer = CANPacker(dbc_file) values = { 'SET_ME_X41': 0x41, 'STEERING_REQUIRED': 1, 'SOLID_LANES': 1, 'BEEP': 0, } # known correct checksums according to the above values checksum_std = [11, 10, 9, 8] checksum_ext = [4, 3, 2, 1] for std, ext in zip(checksum_std, checksum_ext): msgs = [ packer.make_can_msg("LKAS_HUD", 0, values), packer.make_can_msg("LKAS_HUD_A", 0, values), ] can_strings = [can_list_to_can_capnp(msgs), ] parser.update_strings(can_strings) self.assertEqual(parser.vl['LKAS_HUD']['CHECKSUM'], std) self.assertEqual(parser.vl['LKAS_HUD_A']['CHECKSUM'], ext)
def test_packer_parser(self): signals = [ ("COUNTER", "STEERING_CONTROL"), ("CHECKSUM", "STEERING_CONTROL"), ("STEER_TORQUE", "STEERING_CONTROL"), ("STEER_TORQUE_REQUEST", "STEERING_CONTROL"), ("COUNTER", "CAN_FD_MESSAGE"), ("64_BIT_LE", "CAN_FD_MESSAGE"), ("64_BIT_BE", "CAN_FD_MESSAGE"), ("SIGNED", "CAN_FD_MESSAGE"), ] checks = [("STEERING_CONTROL", 0), ("CAN_FD_MESSAGE", 0)] packer = CANPacker(TEST_DBC) parser = CANParser(TEST_DBC, signals, checks, 0) for steer in range(-256, 255): for active in (1, 0): v1 = { "STEER_TORQUE": steer, "STEER_TORQUE_REQUEST": active, } m1 = packer.make_can_msg("STEERING_CONTROL", 0, v1) v2 = { "SIGNED": steer, "64_BIT_LE": random.randint(0, 100), "64_BIT_BE": random.randint(0, 100), } m2 = packer.make_can_msg("CAN_FD_MESSAGE", 0, v2) bts = can_list_to_can_capnp([m1, m2]) parser.update_string(bts) for key, val in v1.items(): self.assertAlmostEqual(parser.vl["STEERING_CONTROL"][key], val) for key, val in v2.items(): self.assertAlmostEqual(parser.vl["CAN_FD_MESSAGE"][key], val) # also check address for sig in ("STEER_TORQUE", "STEER_TORQUE_REQUEST", "COUNTER", "CHECKSUM"): self.assertEqual(parser.vl["STEERING_CONTROL"][sig], parser.vl[228][sig])
def test_civic(self): dbc_file = "honda_civic_touring_2016_can_generated" signals = [ ("STEER_TORQUE", "STEERING_CONTROL", 0), ("STEER_TORQUE_REQUEST", "STEERING_CONTROL", 0), ] checks = [("STEERING_CONTROL", 50)] parser = CANParser(dbc_file, signals, checks, 0) packer = CANPacker(dbc_file) idx = 0 for steer in range(-256, 255): for active in [1, 0]: values = { "STEER_TORQUE": steer, "STEER_TORQUE_REQUEST": active, } msgs = packer.make_can_msg("STEERING_CONTROL", 0, values, idx) bts = can_list_to_can_capnp([msgs]) parser.update_string(bts) self.assertAlmostEqual(parser.vl["STEERING_CONTROL"]["STEER_TORQUE"], steer) self.assertAlmostEqual(parser.vl["STEERING_CONTROL"]["STEER_TORQUE_REQUEST"], active) self.assertAlmostEqual(parser.vl["STEERING_CONTROL"]["COUNTER"], idx % 4) idx += 1
def test_parser_can_valid(self): signals = [ ("COUNTER", "CAN_FD_MESSAGE"), ] checks = [ ("CAN_FD_MESSAGE", 10), ] packer = CANPacker(TEST_DBC) parser = CANParser(TEST_DBC, signals, checks, 0) # shouldn't be valid initially self.assertFalse(parser.can_valid) # not valid until the message is seen for _ in range(100): dat = can_list_to_can_capnp([]) parser.update_string(dat) self.assertFalse(parser.can_valid) # valid once seen for i in range(1, 100): t = int(0.01 * i * 1e9) msg = packer.make_can_msg("CAN_FD_MESSAGE", 0, {}) dat = can_list_to_can_capnp([ msg, ], logMonoTime=t) parser.update_string(dat) self.assertTrue(parser.can_valid)
def test_packer(self): packer = CANPacker(TEST_DBC) for b in range(6): for i in range(256): values = {"COUNTER": i} addr, _, dat, bus = packer.make_can_msg( "CAN_FD_MESSAGE", b, values) self.assertEqual(addr, 245) self.assertEqual(bus, b) self.assertEqual(dat[0], i)
def test_packer_counter(self): signals = [ ("COUNTER", "CAN_FD_MESSAGE"), ] checks = [ ("CAN_FD_MESSAGE", 0), ] packer = CANPacker(TEST_DBC) parser = CANParser(TEST_DBC, signals, checks, 0) # packer should increment the counter for i in range(1000): msg = packer.make_can_msg("CAN_FD_MESSAGE", 0, {}) dat = can_list_to_can_capnp([ msg, ]) parser.update_string(dat) self.assertEqual(parser.vl["CAN_FD_MESSAGE"]["COUNTER"], i % 256) # setting COUNTER should override for _ in range(100): cnt = random.randint(0, 255) msg = packer.make_can_msg("CAN_FD_MESSAGE", 0, { "COUNTER": cnt, }) dat = can_list_to_can_capnp([ msg, ]) parser.update_string(dat) self.assertEqual(parser.vl["CAN_FD_MESSAGE"]["COUNTER"], cnt) # then, should resume counting from the override value cnt = parser.vl["CAN_FD_MESSAGE"]["COUNTER"] for i in range(100): msg = packer.make_can_msg("CAN_FD_MESSAGE", 0, {}) dat = can_list_to_can_capnp([ msg, ]) parser.update_string(dat) self.assertEqual(parser.vl["CAN_FD_MESSAGE"]["COUNTER"], (cnt + i) % 256)
def test_subaru(self): # Subuaru is little endian dbc_file = "subaru_global_2017_generated" signals = [ ("Counter", "ES_LKAS", 0), ("LKAS_Output", "ES_LKAS", 0), ("LKAS_Request", "ES_LKAS", 0), ("SET_1", "ES_LKAS", 0), ] checks = [] parser = CANParser(dbc_file, signals, checks, 0) packer = CANPacker(dbc_file) idx = 0 for steer in range(-256, 255): for active in [1, 0]: values = { "Counter": idx, "LKAS_Output": steer, "LKAS_Request": active, "SET_1": 1 } msgs = packer.make_can_msg("ES_LKAS", 0, values) bts = can_list_to_can_capnp([msgs]) parser.update_string(bts) self.assertAlmostEqual(parser.vl["ES_LKAS"]["LKAS_Output"], steer) self.assertAlmostEqual(parser.vl["ES_LKAS"]["LKAS_Request"], active) self.assertAlmostEqual(parser.vl["ES_LKAS"]["SET_1"], 1) self.assertAlmostEqual(parser.vl["ES_LKAS"]["Counter"], idx % 16) idx += 1
def test_scale_offset(self): """Test that both scale and offset are correctly preserved""" dbc_file = "honda_civic_touring_2016_can_generated" signals = [ ("USER_BRAKE", "VSA_STATUS"), ] checks = [("VSA_STATUS", 50)] parser = CANParser(dbc_file, signals, checks, 0) packer = CANPacker(dbc_file) for brake in range(0, 100): values = {"USER_BRAKE": brake} msgs = packer.make_can_msg("VSA_STATUS", 0, values) bts = can_list_to_can_capnp([msgs]) parser.update_string(bts) self.assertAlmostEqual(parser.vl["VSA_STATUS"]["USER_BRAKE"], brake)
def test_updated(self): """Test updated value dict""" dbc_file = "honda_civic_touring_2016_can_generated" signals = [("USER_BRAKE", "VSA_STATUS")] checks = [("VSA_STATUS", 50)] parser = CANParser(dbc_file, signals, checks, 0) packer = CANPacker(dbc_file) # Make sure nothing is updated self.assertEqual(len(parser.vl_all["VSA_STATUS"]["USER_BRAKE"]), 0) idx = 0 for _ in range(10): # Ensure CANParser holds the values of any duplicate messages over multiple frames user_brake_vals = [ random.randrange(100) for _ in range(random.randrange(5, 10)) ] half_idx = len(user_brake_vals) // 2 can_msgs = [[], []] for frame, brake_vals in enumerate( (user_brake_vals[:half_idx], user_brake_vals[half_idx:])): for user_brake in brake_vals: values = {"USER_BRAKE": user_brake} can_msgs[frame].append( packer.make_can_msg("VSA_STATUS", 0, values)) idx += 1 can_strings = [can_list_to_can_capnp(msgs) for msgs in can_msgs] parser.update_strings(can_strings) vl_all = parser.vl_all["VSA_STATUS"]["USER_BRAKE"] self.assertEqual(vl_all, user_brake_vals) if len(user_brake_vals): self.assertEqual(vl_all[-1], parser.vl["VSA_STATUS"]["USER_BRAKE"])
hyundai_checksum = crcmod.mkCrcFun(0x11D, initCrc=0xFD, rev=False, xorOut=0xdf) dbc_name = 'kia_forte_koup_2013' packer = CANPacker(dbc_name) values = { "CF_Spas_Stat": 5, "CF_Spas_TestMode": 0, "CR_Spas_StrAngCmd": 18.5, "CF_Spas_BeepAlarm": 0, "CF_Spas_Mode_Seq": 2, "CF_Spas_AliveCnt": 205, "CF_Spas_Chksum": 0, "CF_Spas_PasVol": 0 } dat = packer.make_can_msg("SPAS11", 0, values)[2] print(dat) crc = hyundai_checksum(dat) values["CF_Spas_Chksum"] = sum(dat[:6]) % 256 #dat = dat[:6] cs6b = (sum(dat[:6]) % 256) #cs7b = ((sum(dat[:6]) + dat[7]) % 256) print(dat) print(crc) print(cs6b) print(values["CF_Spas_Chksum"]) """
class CarController(): def __init__(self, dbc_name, CP, VW): # state self.acc_enabled_prev = 0 # steering related self.angle_request_prev = 0 # Direction change statemachine self.UNBLOCKED = 0 self.BLOCKED = 1 self.BLOCK_LEN = CCP.BLOCK_LEN # Block steer direction change for x samples self.dir_state = 0 self.block_steering = 0 self.steer_direction_bf_block = 0 self.des_steer_direction_prev = 0 # SteerCommand self.SteerCommand = SteerCommand self.trq_fifo = deque([]) self.fault_frame = -200 # Diag self.doDTCRequests = True # Turn on and off DTC requests self.checkPN = False # Check partnumbers self.clearDtcs = False # Set false to stop sending diagnostic requests self.timeout = 0 # Set to 0 as init self.diagRequest = { "byte0": 0x03, "byte1": 0x19, "byte2": 0x02, "byte3": 0x02, } self.flowControl = { "byte0": 0x30, "byte1": 0x00, "byte2": 0x00, "byte3": 0x00, } self.clearDTC = { "byte0": 0x04, "byte1": 0x14, "byte2": 0xFF, "byte3": 0xFF, "byte4": 0xFF, } # Part number self.cnt = 0 # Init at 0 always self.sndNxtFrame = 0 # Init at low value self.dictKeys = ["byte"+str(x) for x in range(8)] startdid = 0xf1a1 # Start with this DID (Data IDentifier, read UDS Spec for more info) self.dids = [x for x in range(startdid, startdid+9)] # Setup detection helper. Routes commands to # an appropriate CAN bus number. self.CP = CP self.packer = CANPacker(DBC[CP.carFingerprint]['pt']) def max_angle_req(self, current_steer_angle, angle_request_prev, CCP): """ Calculate maximum angle request delta/offset from current steering angle. This is just a helper function that calculates the boundary for min and max steering angle request. It uses the parameters CCP.MAX_ACT_ANGLE_REQUEST_DIFF and CCP.STEER_ANGLE_DELTA_REQ_DIFF. To calculate the max and min allowed delta/offset request. The delta request is just a rate limiter. The request angle cant change more than CCP.STEER_ANGLE_DELTA_REQ_DIFF per loop. """ # determine max and min allowed lka angle request # based on delta per sample max_delta_right = angle_request_prev-CCP.STEER_ANGLE_DELTA_REQ_DIFF max_delta_left = angle_request_prev+CCP.STEER_ANGLE_DELTA_REQ_DIFF # based on distance from actual steering angle max_right = current_steer_angle-CCP.MAX_ACT_ANGLE_REQUEST_DIFF max_left = current_steer_angle+CCP.MAX_ACT_ANGLE_REQUEST_DIFF return max_right, max_left, max_delta_right, max_delta_left def dir_change(self, steer_direction, error): """ Filters out direction changes Uses a simple state machine to determine if we should block or allow the steer_direction bits to pass thru. """ dessd = steer_direction dzError = 0 if abs(error) < CCP.DEADZONE else error tState = -1 # Update prev with desired if just enabled. self.des_steer_direction_prev = steer_direction if not self.acc_enabled_prev else self.des_steer_direction_prev # Check conditions for state change if self.dir_state == self.UNBLOCKED: tState = self.BLOCKED if (steer_direction != self.des_steer_direction_prev and dzError != 0) else tState elif self.dir_state == self.BLOCKED: if (steer_direction == self.steer_direction_bf_block) or (self.block_steering <= 0) or (dzError == 0): tState = self.UNBLOCKED # State transition if tState == self.UNBLOCKED: self.dir_state = self.UNBLOCKED elif tState == self.BLOCKED: self.steer_direction_bf_block = self.des_steer_direction_prev self.block_steering = self.BLOCK_LEN self.dir_state = self.BLOCKED # Run actions in state if self.dir_state == self.UNBLOCKED: if dzError == 0: steer_direction = self.des_steer_direction_prev # Set old request when inside deadzone if self.dir_state == self.BLOCKED: self.block_steering -= 1 steer_direction = CCP.STEER_NO #print("State:{} Sd:{} Sdp:{} Bs:{} Dz:{:.2f} Err:{:.2f}".format(self.dir_state, steer_direction, self.des_steer_direction_prev, self.block_steering, dzError, error)) return steer_direction def update(self, enabled, CS, frame, actuators, visualAlert, leftLaneVisible, rightLaneVisible, leadVisible, leftLaneDepart, rightLaneDepart): """ Controls thread """ # Send CAN commands. can_sends = [] # run at 50hz if (frame % 2 == 0): fingerprint = self.CP.carFingerprint if enabled and CS.out.vEgo > self.CP.minSteerSpeed: current_steer_angle = CS.out.steeringAngleDeg self.SteerCommand.angle_request = actuators.steeringAngleDeg # Desired value from pathplanner # # windup slower if self.angle_request_prev * self.SteerCommand.angle_request > 0. and abs(self.SteerCommand.angle_request) > abs(self.angle_request_prev): angle_rate_lim = interp(CS.out.vEgo, CCP.ANGLE_DELTA_BP, CCP.ANGLE_DELTA_V) else: angle_rate_lim = interp(CS.out.vEgo, CCP.ANGLE_DELTA_BP, CCP.ANGLE_DELTA_VU) self.SteerCommand.angle_request = clip(self.SteerCommand.angle_request, self.angle_request_prev - angle_rate_lim, self.angle_request_prev + angle_rate_lim) # Create trqlim from angle request (before constraints) self.SteerCommand.trqlim = 0 if fingerprint in PLATFORM.C1: #self.SteerCommand.trqlim = -127 if current_steer_angle > self.SteerCommand.angle_request else 127 self.SteerCommand.steer_direction = CCP.STEER elif fingerprint in PLATFORM.EUCD: # MIGHT be needed for EUCD self.SteerCommand.steer_direction = CCP.STEER_RIGHT if current_steer_angle > self.SteerCommand.angle_request else CCP.STEER_LEFT self.SteerCommand.steer_direction = self.dir_change(self.SteerCommand.steer_direction, current_steer_angle-self.SteerCommand.angle_request) # Filter the direction change else: self.SteerCommand.steer_direction = CCP.STEER_NO self.SteerCommand.trqlim = 0 if fingerprint in PLATFORM.C1: self.SteerCommand.angle_request = clip(CS.out.steeringAngleDeg, -359.95, 359.90) # Cap values at max min values (Cap 2 steps from max min). Max=359.99445, Min=-360.0384 else: self.SteerCommand.angle_request = 0 # Count no of consequtive samples of zero torque by lka. # Try to recover, blocking steering request for 2 seconds. if fingerprint in PLATFORM.C1: if enabled and CS.out.vEgo > self.CP.minSteerSpeed: self.trq_fifo.append(CS.PSCMInfo.LKATorque) if len(self.trq_fifo) > CCP.N_ZERO_TRQ: self.trq_fifo.popleft() else: self.trq_fifo.clear() self.fault_frame = -200 if (self.trq_fifo.count(0) >= CCP.N_ZERO_TRQ) and (self.fault_frame == -200): self.fault_frame = frame+100 if enabled and (frame < self.fault_frame): self.SteerCommand.steer_direction = CCP.STEER_NO if frame > self.fault_frame+8: # Ignore steerWarning for another 8 samples. self.fault_frame = -200 # update stored values self.acc_enabled_prev = enabled self.angle_request_prev = self.SteerCommand.angle_request if self.SteerCommand.steer_direction == CCP.STEER_RIGHT or self.SteerCommand.steer_direction == CCP.STEER_LEFT: # TODO: Move this inside dir_change, think it should work? self.des_steer_direction_prev = self.SteerCommand.steer_direction # Used for dir_change function # Manipulate data from servo to FSM # Avoid fault codes, that will stop LKA can_sends.append(volvocan.manipulateServo(self.packer, self.CP.carFingerprint, CS)) # send can, add to list. can_sends.append(volvocan.create_steering_control(self.packer, frame, self.CP.carFingerprint, self.SteerCommand, CS.FSMInfo)) # Cancel ACC if engaged when OP is not. if not enabled and CS.out.cruiseState.enabled: can_sends.append(volvocan.cancelACC(self.packer, self.CP.carFingerprint, CS)) # Send diagnostic requests if(self.doDTCRequests): if(frame % 100 == 0) and (not self.clearDtcs): # Request diagnostic codes, 2 Hz can_sends.append(self.packer.make_can_msg("diagFSMReq", 2, self.diagRequest)) #can_sends.append(self.packer.make_can_msg("diagGlobalReq", 2, self.diagRequest)) can_sends.append(self.packer.make_can_msg("diagGlobalReq", 0, self.diagRequest)) #can_sends.append(self.packer.make_can_msg("diagPSCMReq", 0, self.diagRequest)) #can_sends.append(self.packer.make_can_msg("diagCEMReq", 0, self.diagRequest)) #can_sends.append(self.packer.make_can_msg("diagCVMReq", 0, self.diagRequest)) self.timeout = frame + 5 # Set wait time # Handle flow control in case of many DTC if frame > self.timeout and self.timeout > 0: # Wait fix time before sending flow control, otherwise just spamming... self.timeout = 0 if (CS.diag.diagFSMResp & 0x10000000): can_sends.append(self.packer.make_can_msg("diagFSMReq", 2, self.flowControl)) if (CS.diag.diagCEMResp & 0x10000000): can_sends.append(self.packer.make_can_msg("diagCEMReq", 0, self.flowControl)) if (CS.diag.diagPSCMResp & 0x10000000): can_sends.append(self.packer.make_can_msg("diagPSCMReq", 0, self.flowControl)) if (CS.diag.diagCVMResp & 0x10000000): can_sends.append(self.packer.make_can_msg("diagCVMReq", 0, self.flowControl)) # Check part numbers if self.checkPN and frame > 100 and frame > self.sndNxtFrame: if self.cnt < len(self.dids): did = [0x03, 0x22, (self.dids[self.cnt] & 0xff00)>>8, self.dids[self.cnt] & 0x00ff] # Create diagnostic command did.extend([0]*(8-len(did))) diagReq = dict(zip(self.dictKeys,did)) #can_sends.append(self.packer.make_can_msg("diagGlobalReq", 2, diagReq)) #can_sends.append(self.packer.make_can_msg("diagGlobalReq", 0, diagReq)) can_sends.append(self.packer.make_can_msg("diagFSMReq", 2, diagReq)) can_sends.append(self.packer.make_can_msg("diagCEMReq", 0, diagReq)) can_sends.append(self.packer.make_can_msg("diagPSCMReq", 0, diagReq)) can_sends.append(self.packer.make_can_msg("diagCVMReq", 0, diagReq)) self.cnt += 1 self.timeout = frame+5 # When to send flowControl self.sndNxtFrame = self.timeout+5 # When to send next part number request elif True: # Stop when list has been looped thru. self.checkPN = False # Clear DTCs in FSM on start # TODO check for engine running before clearing dtc. if(self.clearDtcs and (frame > 0) and (frame % 500 == 0)): can_sends.append(self.packer.make_can_msg("diagGlobalReq", 0, self.clearDTC)) can_sends.append(self.packer.make_can_msg("diagFSMReq", 2, self.clearDTC)) #can_sends.append(self.packer.make_can_msg("diagPSCMReq", 0, self.clearDTC)) #can_sends.append(self.packer.make_can_msg("diagCEMReq", 0, self.clearDTC)) self.clearDtcs = False return can_sends
p = Panda() p.set_safety_mode(Panda.SAFETY_ALLOUTPUT) dumpsafety = p.health() if dumpsafety['safety_mode'] == 0: print( 'Sorry, u need change for some dev branch, if u deserv this copy and past this command:\n\n\necho -en "1" > /data/params/d/DisableUpdates; cd ..; rm -rf openpilot; git clone -b master --recurse-submodules https://github.com/commaai/openpilot; reboot' ) exit(1) packer = CANPacker(dbc_name) values = { "ACC_TYPE": 1, } data = packer.make_can_msg( "ACC_CONTROL", 0, values) # maybe u need change this ACC_CONTROL confirm in your odbc def main(): for i in range(0, max): print(f"PCM exploit :{data}") print( ' __ __ .___\n/ \ / \ ____ ____ ____ ____ __| _/\n\ \/\/ // __ \ / \_/ __ \_/ __ \ / __ | \n \ /\ ___/ | | \ ___/\ ___// /_/ | \n \__/\ / \___ > |___| /\___ >\___ >____ | \n \/ \/ \/ \/ \/ \/ \n _________ ________ \n / _____/ ____ / _____/ \n \_____ \ / \/ \ ___ \n / \ | \ \_\ \\\n/_______ /___| /\______ /\n \/ \/ \/ \n' ) p.can_send(data[0], data[2], data[3]) progress(i, max, 'start your engine before reach the end') if i < (max - 1): os.system('clear')