/// <summary> /// Parse the replies checking for a valid response, if we have a valid response extract the payload data /// </summary> /// <param name="rxMsgs"></param> /// <param name="txMode"></param> /// <param name="payload"></param> /// <returns></returns> UDSPacket ParseUDSResponse(PassThruMsg rxMsg, UDScmd.Mode txMode) { var rxMsgBytes = rxMsg.GetBytes(); UDSPacket rxPacket = new UDSPacket(); //Iterate the reply bytes to find the echod ECU index, response code, function response and payload data if there is any //If we could use some kind of HEX regex this would be a bit neater int stateMachine = 0; for (int i = 0; i < rxMsgBytes.Length; i++) { switch (stateMachine) { case 0: if (rxMsgBytes[i] == 0x07) { stateMachine = 1; } else if (rxMsgBytes[i] != 0) { return(rxPacket); } break; case 1: if (rxMsgBytes[i] == 0xE8) { stateMachine = 2; } else { return(rxPacket); } break; case 2: var payload = new byte[rxMsgBytes.Length - i]; int payloadLength = rxMsgBytes.Length - i; if (payloadLength > 0) { payload = new byte[payloadLength]; Array.Copy(rxMsgBytes, i, payload, 0, payloadLength); rxPacket = new UDSPacket(payload, txMode); ; } return(rxPacket); case 3: default: return(rxPacket); } } return(rxPacket); }
public void ReadMemoryByAddress(uint address, uint blockSize, out byte[] memory) { //Send the read memory request byte blockSizeUpper = (byte)((blockSize >> 8) & 0xFF); byte blockSizeLower = (byte)(blockSize & 0xFF); //ISO14229 ReadMemoryByAddress //byte1 ServiceID 0x23 //byte2 AddressAndLengthFormatIdentifier (0 for Ford Spanish Oak) //byte3 address byte 1 //byte4 address byte 2 //byte5 address byte 3 //byte6 address byte 4 //byte7 block size byte1 //byte8 block size byte2 byte[] txMsgBytes = { (byte)UDScmd.Mode.READ_MEMORY_BY_ADDRESS, 0, (byte)((address >> 16) & 0xFF), (byte)((address >> 8) & 0xFF), (byte)((address) & 0xFF), blockSizeUpper, blockSizeLower }; SendMessage(txMsgBytes); //We expect 3 messages, rx, start of message, then the payload data List <PassThruMsg> rxMsgs; //This will throw an exception if we don't get a valid reply while (ReadMessage(out rxMsgs, 250) == J2534Err.STATUS_NOERROR) { if (rxMsgs[0].RxStatus == RxStatus.NONE) { break; } } //If we couldn't find the start of the mesage give up if (J2534Status != J2534Err.STATUS_NOERROR) { throw new J2534Exception(J2534Status); } if (rxMsgs.Count < 1) { throw new J2534Exception(J2534Err.ERR_INVALID_MSG); } UDSPacket rxPacket = ParseUDSResponse(rxMsgs[0], UDScmd.Mode.READ_MEMORY_BY_ADDRESS); if (rxPacket.Response != UDScmd.Response.POSTIVE_RESPONSE) { throw new UDSException(rxPacket.NegativeResponse); } memory = rxPacket.Payload; }
public void RequestTransferExit() { //ISO14229 RequestTransferExit //byte1 ServiceID 0x37 byte[] txMsgBytes = { (byte)UDScmd.Mode.TRANSFER_EXIT }; SendMessage(txMsgBytes); //We expect no reply List <PassThruMsg> rxMsgs; //This will throw an exception if we don't get a valid reply while (ReadMessage(out rxMsgs, 250) == J2534Err.STATUS_NOERROR) { if (rxMsgs[0].RxStatus == RxStatus.NONE) { break; } } //If we couldn't find the start of the mesage give up if (J2534Status != J2534Err.STATUS_NOERROR) { throw new J2534Exception(J2534Status); } if (rxMsgs.Count < 1) { throw new J2534Exception(J2534Err.ERR_INVALID_MSG); } UDSPacket rxPacket = ParseUDSResponse(rxMsgs[0], UDScmd.Mode.TRANSFER_EXIT); var b = rxMsgs[0].GetBytes(); if (rxPacket.Response != UDScmd.Response.POSTIVE_RESPONSE) { //We expect a negative response but with response pending if (rxPacket.NegativeResponse != UDScmd.NegativeResponse.REPONSE_PENDING) { throw new UDSException(rxPacket.NegativeResponse); } } }
public void SecurityAccess(byte subFunction) { //Send the security request byte[] txMsgBytes = { (byte)UDScmd.Mode.SECURITY_ACCESS, subFunction }; SendMessage(txMsgBytes); //Attempt to read at least 1 message as a reply List <PassThruMsg> rxMsgs; ReadAllMessages(out rxMsgs, 1, 200); //Find the start of the response and parse it. PassThruMsg seedKeyResponse; int startOfMessageIndex = GetStartOfMessageIndex(rxMsgs); if (startOfMessageIndex == -1) { throw new J2534Exception(J2534Err.ERR_BUFFER_EMPTY); } seedKeyResponse = rxMsgs[startOfMessageIndex]; //needs to respond with 00 00 07 e8 67 03 xx xx xx //response is 00 00 7F 27 12 if you have just powered on and had VPP during power on but the command is incorrect length (unsupported) //response is 00 00 7F 27 11 if you have no VPP //response is 00 07 E8 67 mode XX XX XX if success UDSPacket rxPacket = ParseUDSResponse(seedKeyResponse, UDScmd.Mode.SECURITY_ACCESS); if (rxPacket.Response == UDScmd.Response.NO_RESPONSE) { throw new UDSException(UDScmd.NegativeResponse.INCORRECT_MSG_LENGTH_OR_FORMAT); } else if (rxPacket.Response == UDScmd.Response.NEGATIVE_RESPONSE) { //Inform the user of the error if (rxPacket.NegativeResponse == UDScmd.NegativeResponse.UNKNOWN) { //no error code supplied, something else went wrong throw new UDSException(UDScmd.NegativeResponse.INCORRECT_MSG_LENGTH_OR_FORMAT); } else { //We got a sub function error code throw new UDSException(rxPacket.NegativeResponse); } } else { if (rxPacket.Payload.Length < 3) { //Incorrect seed response length throw new UDSException(UDScmd.NegativeResponse.INCORRECT_MSG_LENGTH_OR_FORMAT); } else { //Calculate the seed response var seedresponse = CalculateResponseFromSeed(0x7E0, subFunction, rxPacket.Payload); //Send the packet txMsgBytes = new byte[] { (byte)UDScmd.Mode.SECURITY_ACCESS, (byte)(subFunction + 1), (byte)((seedresponse >> 16) & 0xFF), (byte)((seedresponse >> 8) & 0xFF), (byte)((seedresponse) & 0xFF) }; SendMessage(txMsgBytes); //Attempt to read at least 1 message as a reply ReadAllMessages(out rxMsgs, 1, 200); //Get the response startOfMessageIndex = GetStartOfMessageIndex(rxMsgs); if (startOfMessageIndex == -1) { throw new J2534Exception(J2534Err.ERR_BUFFER_EMPTY); } var unlockResponse = rxMsgs[startOfMessageIndex]; //needs to be 00 00 07 E8 67 04 (mode+1) (or 67 02) rxPacket = ParseUDSResponse(unlockResponse, UDScmd.Mode.SECURITY_ACCESS); if (rxPacket.Response == UDScmd.Response.NO_RESPONSE) { throw new UDSException(UDScmd.NegativeResponse.INCORRECT_MSG_LENGTH_OR_FORMAT); } else if (rxPacket.Response == UDScmd.Response.NEGATIVE_RESPONSE) { //Inform the user of the error if (rxPacket.NegativeResponse == UDScmd.NegativeResponse.UNKNOWN) { //no error code supplied, something else went wrong throw new UDSException(UDScmd.NegativeResponse.INCORRECT_MSG_LENGTH_OR_FORMAT); } else { //We got a sub function error code throw new UDSException(rxPacket.NegativeResponse); } } if (rxPacket.SubFunction != subFunction + 1) { throw new Exception($"Returned an incorrect subfunction code, expected {subFunction+1} got {rxPacket.SubFunction}"); } //We successfully entered the serurity level! } } }
public void RequestDownload() { //ISO14229 RequestDownload //byte1 ServiceID 0x34 //byte2 DataFormatIdentifier // High nibble = memorySize) // Low nibble = memoryAddress //byte3 AddressAndLengthFormatIdentifier (0x01 for Ford Spanish Oak) //byte4 memoryAddressByte1 //byte5 memoryAddressByte2 //byte6 memoryAddressByte3 //byte7 uncompressedMemorySizeByte1 //byte8 uncompressedMemorySizeByte1 //byte9 uncompressedMemorySizeByte1 //We need to do something more clever here based upon the flash size byte[] txMsgBytes = { (byte)UDScmd.Mode.REQUEST_DOWNLOAD, 0x00, 0x01, 0x00, 00, 00, 0x0F, 0x00, 00 }; SendMessage(txMsgBytes); //We expect 3 messages, rx, start of message, 0x78 (response pending) then the successful response List <PassThruMsg> rxMsgs; //This will throw an exception if we don't get a valid reply while (ReadMessage(out rxMsgs, 250) == J2534Err.STATUS_NOERROR) { if (rxMsgs[0].RxStatus == RxStatus.NONE) { break; } } //If we couldn't find the start of the mesage give up if (J2534Status != J2534Err.STATUS_NOERROR) { throw new J2534Exception(J2534Status); } if (rxMsgs.Count < 1) { throw new J2534Exception(J2534Err.ERR_INVALID_MSG); } UDSPacket rxPacket = ParseUDSResponse(rxMsgs[0], UDScmd.Mode.REQUEST_DOWNLOAD); if (rxPacket.Response != UDScmd.Response.POSTIVE_RESPONSE) { //We expect a negative response but with response pending if (rxPacket.NegativeResponse != UDScmd.NegativeResponse.REPONSE_PENDING) { throw new UDSException(rxPacket.NegativeResponse); } //ReadMessage(out rxMsgs, 250); List <byte[]> temp = new List <byte[]>(); while (ReadMessage(out rxMsgs, 250) == J2534Err.STATUS_NOERROR) { var b = rxMsgs[0].GetBytes(); temp.Add(b); if (rxMsgs[0].RxStatus == RxStatus.NONE) { break; } } //If we couldn't find the start of the mesage give up if (J2534Status != J2534Err.STATUS_NOERROR) { throw new J2534Exception(J2534Status); } if (rxMsgs.Count < 1) { throw new J2534Exception(J2534Err.ERR_INVALID_MSG); } rxPacket = ParseUDSResponse(rxMsgs[0], UDScmd.Mode.REQUEST_DOWNLOAD); if (rxPacket.Response != UDScmd.Response.POSTIVE_RESPONSE) { throw new UDSException(rxPacket.NegativeResponse); } } //We have a positive response lets check the payload //This reply from the spanish oak doesn't really seem to match the ISO14229 spec however it must be in this format so we fail if it is not if (rxPacket.LengthFormatIdentifier != 0x04 || rxPacket.MaxNumberOfBlockLength != 0x01) { throw new UDSException(UDScmd.NegativeResponse.UPLOAD_DOWNLOAD_NOT_ACCEPTED); } }
public void TransferData(byte [] data, int offset, int length, int blockSize = -1) { //ISO14229 TransferData //byte1 ServiceID 0x36 if (blockSize == -1) { blockSize = length; } byte[] txMsgBytes = new byte[(length + 1)]; txMsgBytes[0] = (byte)UDScmd.Mode.TRANSFER_DATA; Buffer.BlockCopy(data, offset, txMsgBytes, 1, blockSize); SendMessage(txMsgBytes); //We expect no reply List <PassThruMsg> rxMsgs; List <byte[]> msgs = new List <byte[]>(); //This will throw an exception if we don't get a valid reply while (ReadMessage(out rxMsgs, 250) == J2534Err.STATUS_NOERROR) { if (rxMsgs[0].RxStatus == RxStatus.NONE) { break; } msgs.Add(rxMsgs[0].GetBytes()); } //If we couldn't find the start of the mesage give up if (J2534Status != J2534Err.STATUS_NOERROR) { throw new J2534Exception(J2534Status); } if (rxMsgs.Count < 1) { throw new J2534Exception(J2534Err.ERR_INVALID_MSG); } UDSPacket rxPacket = ParseUDSResponse(rxMsgs[0], UDScmd.Mode.TRANSFER_DATA); var b = rxMsgs[0].GetBytes(); msgs.Add(b); if (rxPacket.Response != UDScmd.Response.POSTIVE_RESPONSE) { while (rxPacket.NegativeResponse == UDScmd.NegativeResponse.REPONSE_PENDING) { ReadMessage(out rxMsgs, 250); if (J2534Status != J2534Err.STATUS_NOERROR) { throw new J2534Exception(J2534Status); } if (rxMsgs.Count < 1) { throw new J2534Exception(J2534Err.ERR_INVALID_MSG); } rxPacket = ParseUDSResponse(rxMsgs[0], UDScmd.Mode.TRANSFER_DATA); msgs.Add(rxMsgs[0].GetBytes()); } //If we get a different negative response code then this is an actual error if (rxPacket.Response != UDScmd.Response.POSTIVE_RESPONSE) { throw new UDSException(rxPacket.NegativeResponse); } } }
//This is used to erase the flash public void EraseFlash(BackgroundWorker progressReporter = null) { //Non Standard Manafacturer Specific Mode EraseFlash (Ford Spanish Oak) //byte1 ServiceID 0xB1 //byte2 AddressAndLengthFormatIdentifier (0x00 for Ford Spanish Oak) //byte3 0xB2 magic byte 1 //byte4 0xAA byte[] txMsgBytes = { (byte)UDScmd.Mode.DIAGNOSTIC_COMMAND, 0x00, 0xB2, 0xAA }; SendMessage(txMsgBytes); List <PassThruMsg> rxMsgs; while (ReadMessage(out rxMsgs, 250) == J2534Err.STATUS_NOERROR) { if (rxMsgs[0].RxStatus == RxStatus.NONE) { break; } } //Expect back 0x7F B1 78 (78=Response Pending) //0xF1 00 B2 which is success //If we couldn't find the start of the mesage give up if (J2534Status != J2534Err.STATUS_NOERROR) { throw new J2534Exception(J2534Status); } if (rxMsgs.Count < 1) { throw new J2534Exception(J2534Err.ERR_INVALID_MSG); } UDSPacket rxPacket = ParseUDSResponse(rxMsgs[0], UDScmd.Mode.DIAGNOSTIC_COMMAND); if (rxPacket.Response != UDScmd.Response.POSTIVE_RESPONSE) { //We expect a negative response but with response pending if (rxPacket.NegativeResponse != UDScmd.NegativeResponse.REPONSE_PENDING) { throw new UDSException(rxPacket.NegativeResponse); } //Wait for the PCM to erase the flash ReadMessage(out rxMsgs, 15000); //If we couldn't find the start of the mesage give up if (J2534Status != J2534Err.STATUS_NOERROR) { throw new J2534Exception(J2534Status); } if (rxMsgs.Count < 1) { throw new J2534Exception(J2534Err.ERR_INVALID_MSG); } rxPacket = ParseUDSResponse(rxMsgs[0], UDScmd.Mode.DIAGNOSTIC_COMMAND); if (rxPacket.Response != UDScmd.Response.POSTIVE_RESPONSE) { throw new UDSException(rxPacket.NegativeResponse); } } if (rxPacket.Payload.Length < 2) { throw new J2534Exception(J2534Err.ERR_INVALID_MSG); } //There is no IS14229 spec for this command so we manually check it if (rxPacket.Payload[0] != 0x00 || rxPacket.Payload[1] != 0xB2) { throw new J2534Exception(J2534Err.ERR_INVALID_MSG); } }