Instrument Cluster EEPROM read via CAN

Ford information and tools can be found here
Post Reply
jakka
Posts: 53
Joined: Mon Dec 11, 2023 11:51 am
cars: 6FPAAAJGSW9E86101
Location: Aus
Contact:

Instrument Cluster EEPROM read via CAN

Post by jakka »

FG Falcon Instrument Cluster EEPROM, read via CAN, using socketCAN.

https://github.com/jakka351/Instrument_ ... /tree/main

Code: Select all

#!/usr/bin/python3
#coding:utf-8
#//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#region Copyright (c) 2024, Jack Leighton
#     __________________________________________________________________________________________________________________
#
#                  __                   __              __________                                      __   
#                _/  |_  ____   _______/  |_  __________\______   \_______   ____   ______ ____   _____/  |_ 
#                \   __\/ __ \ /  ___/\   __\/ __ \_  __ \     ___/\_  __ \_/ __ \ /  ___// __ \ /    \   __\
#                 |  | \  ___/ \___ \  |  | \  ___/|  | \/    |     |  | \/\  ___/ \___ \\  ___/|   |  \  |  
#                 |__|  \___  >____  > |__|  \___  >__|  |____|     |__|    \___  >____  >\___  >___|  /__|  
#                           \/     \/            \/                             \/     \/     \/     \/      
#                                                          .__       .__  .__          __                    
#                               ____________   ____   ____ |__|____  |  | |__| _______/  |_                  
#                              /  ___/\____ \_/ __ \_/ ___\|  \__  \ |  | |  |/  ___/\   __\                 
#                              \___ \ |  |_> >  ___/\  \___|  |/ __ \|  |_|  |\___ \  |  |                   
#                             /____  >|   __/ \___  >\___  >__(____  /____/__/____  > |__|                   
#                                  \/ |__|        \/     \/        \/             \/                         
#                                  __                         __  .__                                        
#                   _____   __ ___/  |_  ____   _____   _____/  |_|__|__  __ ____                            
#                   \__  \ |  |  \   __\/  _ \ /     \ /  _ \   __\  \  \/ // __ \                           
#                    / __ \|  |  /|  | (  <_> )  Y Y  (  <_> )  | |  |\   /\  ___/                           
#                   (____  /____/ |__|  \____/|__|_|  /\____/|__| |__| \_/  \___  >                          
#                        \/                         \/                          \/                           
#                                                  .__          __  .__                                      
#                                       __________ |  |  __ ___/  |_|__| ____   ____   ______                
#                                      /  ___/  _ \|  | |  |  \   __\  |/  _ \ /    \ /  ___/                
#                                      \___ (  <_> )  |_|  |  /|  | |  (  <_> )   |  \\___ \                 
#                                     /____  >____/|____/____/ |__| |__|\____/|___|  /____  >                
#                                          \/                                      \/     \/                 
#                                   Tester Present Specialist Automotive Solutions
#     __________________________________________________________________________________________________________________
#      |--------------------------------------------------------------------------------------------------------------|
#      |       https://github.com/jakka351/| https://testerPresent.com.au | https://facebook.com/testerPresent        |
#      |--------------------------------------------------------------------------------------------------------------|
#      | Copyright (c) 2022/2023/2024 Benjamin Jack Leighton                                                          |          
#      | All rights reserved.                                                                                         |
#      |--------------------------------------------------------------------------------------------------------------|
#        Redistribution and use in source and binary forms, with or without modification, are permitted provided that
#        the following conditions are met:
#        1.    With the express written consent of the copyright holder.
#        2.    Redistributions of source code must retain the above copyright notice, this
#              list of conditions and the following disclaimer.
#        3.    Redistributions in binary form must reproduce the above copyright notice, this
#              list of conditions and the following disclaimer in the documentation and/or other
#              materials provided with the distribution.
#        4.    Neither the name of the organization nor the names of its contributors may be used to
#              endorse or promote products derived from this software without specific prior written permission.
#      _________________________________________________________________________________________________________________
#      THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
#      INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
#      DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
#      SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
#      SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
#      WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
#      USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#      _________________________________________________________________________________________________________________
#
#       This software can only be distributed with my written permission. It is for my own educational purposes and  
#       is potentially dangerous to ECU health and safety. Gracias a Gato Blancoford desde las alturas del mar de chelle.                                                        
#      _________________________________________________________________________________________________________________
#
#
#//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#endregion License
#############################################################################################################
# library imports
#############################################################################################################
import os, sys, time, queue, traceback
from threading import *
from threading import Thread
from array import array
import can 
#################################################################################################################
# GNU/Linux socketcan canbus interfaces //
# // vcan0 is virtual socket for testing on linux socketcan
# // virtualcan is https://github.com/windelbouwman/virtualcan cross platform
#################################################################################################################
businput     = 'socketcan'
channelinput = 'vcan0'
bitrateinput = '125000'
MidSpeedCan  = can.interface.Bus(channel=channelinput, bustype=businput, bitrate=bitrateinput) # MS CAN
# // insert secret key here
fixed                                                 = 0xbfa49056cd 
# // ecu rx can id insert here
DiagSix_Rx                                            = 0x728
DiagSig_Tx                                            = DiagSig_Rx + 0x08
ServiceRequest                                        = dict()
#################################################################################################################
# EEPROM PROCESS
#################################################################################################################
def msgbuffer():
    global message, q,DiagSig_Rx                                      
    while True:
        message = MidSpeedCan.recv()          # if recieving can frames then put these can arb id's into a queue
        if message.arbitration_id == DiagSig_Rx:                        
            q.put(message)
        elif message.arbitration_id == DiagSig_Tx
            q.put(message)
'''
#################################################################################################################
# EEPROM PROCESS
#################################################################################################################
Jack Whiteford
“FG(I) Read and Write the entire EEPROM:
########################################
### < send to Cluster
### > Cluster responds
    03 22 E2 00 <                Request data by ID
    06 62 E2 00 17 0B 6C >       Data is 170B6C - might be checking model?
    02 BA 0B <         Quickly jam in these two..
    02 BA 07 <      ..requests that "fail" (you will get en error)
    FA 11 88 57 >   3 byte challenge key appears out of nowhere
                    (If it doesn't appear, try again from BA0B)
    04 BA 8E 5C 8D < Respond with 3 byte key generated with { 0xbf, 0xa4, 0x90, 0x56, 0xcd }
    02 10 FA <       Don't wait, just do
    02 50 FA >       Success!
    BA 01 02 00 00 < Read 2 bytes at EEPROM address 0x0000
    FA 01 02 15 A1 > !!! 0xA1 is byte 0, 0x15 is byte 1 in the EEPROM.
    BA 02 02 00 00 16 A1 < !!! Write 2 bytes at address 0x0000
                        !!! 16 was 15 increased by 1 as a test
    FA 02 02 > Happy days
                    (FYI)
    BA 01 02 00 02 < Read 2 bytes at address 0x0002, next two bytes
                        ...and on it goes...
    BA 01 02 01 FE < Read 2 bytes at address 0x01FE the last EEPROM address
                     (I say last, but I also assume the 02 means two byte read/write)
                     (You probably/might be able to read and write 1 byte at a time)
    02 10 81 < Request to leave secure mode
    02 50 81 > Left secure mode
    02 11 01 < reset
    02 51 01 > yeah yeah”
############################################
Please forward onto Jakka - I expect him to come up with a neat script to do all the things I did for the FGII”
“Thoughts: It's probably worth doing a reset also at the end of any EEPROM write, to make sure any cached data in RAM isn't kept.//
##################################################################################################################

'''
#############################################################################################################
# function that generates the key
#############################################################################################################
def KeyGen(seed, fixed):
    seed   = requestSecurityAccess(DiagSix_Rx, 0x01)
    try: 
        challengeCode = array('Q')
        challengeCode.append(fixed & 0xff)
        challengeCode.append((fixed >> 8) & 0xff)
        challengeCode.append((fixed >> 16) & 0xff)
        challengeCode.append((fixed >> 24) & 0xff)
        challengeCode.append((fixed >> 32) & 0xff)
        challengeCode.append(seed[2])
        challengeCode.append(seed[1])
        challengeCode.append(seed[0])
        temp1 = 0xC541A9
        for i in range(64):
            abit = temp1 & 0x01
            chbit = challengeCode[7] & 0x01
            bbit = abit ^ chbit
            temp2 = (temp1 >> 1) + bbit * 0x800000 & -1
            temp1 = (temp2 ^ 0x109028 * bbit) & -1
            challengeCode[7] = challengeCode[7] >> 1 & 0xff
            for a in range(7, 0, -1):
                challengeCode[a] = challengeCode[a] + (challengeCode[a - 1] & 1) * 128 & 0xff
                challengeCode[a - 1] = challengeCode[a - 1] >> 1
        key = [ temp1 >> 4 & 0xff, ((temp1 >> 12 & 0x0f) << 4) + (temp1 >> 20 & 0x0f), (temp1 >> 16 & 0x0f) + ((temp1 & 0x0f) << 4) ]
        print("Succesfully got key: {key}")
        return key
    except can.CanError():
        print("CAN Error")            
#############################################################################################################
# function to send key 
# Usage: SendKey(key) should be all that needs to be called.
#############################################################################################################
def SendKey(key):
    keyResponse   = can.Message(arbitration_id = DiagSig_Rx,
                                 data          = [0x04, 0xBA, key[0], key[1], key[2], 0, 0, 0], is_extended_id = False)
    MidSpeedCan.Send(keyResponse)
#############################################################################################################
# MAIN
#
############################################################################################################
def main:
    glboal message, MidSpeedCan, q, fixed, DiagSig_Rx, DiagSig_Tx
     try:
        while True:
            for i in range(8):
                while(q.empty() == True):                               # wait for messages to queue
                    pass
                message = q.get()   
                c = '{0:f},{1:d},'.format(message.timestamp,count)
                requestDataById = can.Message(arbitration_id=DiagSig_Rx, data=[0x03, 0x22, 0x62, 0x00, 0x00, 0x00, 0x00, 0x00 ],extended_id=False)
                MidSpeedCan.Send(requestDataById)
                ba0b = can.Message(arbitration_id=DiagSig_Rx, data=[0x02, 0xBA, 0x0B, 0x00, 0x00, 0x00, 0x00, 0x00 ],extended_id=False)
                MidSpeedCan.Send(ba0b)
                ba07 = can.Message(arbitration_id=DiagSig_Rx, data=[0x02, 0xBA, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00 ],extended_id=False)
                MidSpeedCan.Send(ba07)
                if message.arbitration_id == DiagSig_Rx:
                    print(message)
                elif message.arbitration_id == DiagSig_Tx:
                    print(message)
                elif message.arbitration_id == DiagSig_Tx and  and message.data[0] == 0xFA:
                    print("Got Seed: ", message.data[1], message.data[2], message.data[3])
                    seed    = message.data[1], message.data[2], message.data[3]
                    seed[0] = message.data[1]
                    seed[1] = message.data[2]
                    seed[2] = message.data[3]
                    print("Generating Key...")
                    Keygen(seed, fixed)
                    SendKey(key)
                    systemSupplierSpecific = can.Message(arbitration_id=DiagSig_Rx, data=[0x02, 0x10, 0xFA, 0x00, 0x00, 0x00, 0x00, 0x00 ],extended_id=False)
                    MidSpeedCan.Send(systemSupplierSpecific)
                    data = 0x00
                    print("EEPROM: ")
                    for address in range(0x0000, 0x01FF, 2):
                        address_high = (address >> 8) & 0xFF
                        address_low = address & 0xFF
                        read_eeprom = can.Message(arbitration_id=DiagSig_Rx, data=[0x05, 0xBA, 0x01, 0x02, address_high, address_low, 0x00, 0x00 ],extended_id=False)
                        eeprom = MidSpeedCan.recv()
                        if eeprom.arbitration_id == DiagSig_Tx: & eeprom.data[2] == 0xFA:
                            data += eeprom.data[4], eeprom.data[5]
                            print(data)
                        if address == 0x1FF:
                            break                                                     
    except KeyboardInterrupt:
        sys.exit(0)                                              # quit if ctl + c is hit
    except Exception:
        traceback.print_exc(file=sys.stdout)                     # quit if there is a python problem
        sys.exit()
    except OSError:
        sys.exit()                                               # quit if there is a system issue  

#################################################################################################################
if __name__ == "__main__":
    q                      = queue.Queue()                       #
    rx                     = Thread(target = msgbuffer)          #
    rx.start()                                                   # start the rx thread and queue msgs
    main()                                                       # match ca
Post Reply