Code: Select all
* $2D --> OneShot --> $22
* |
* -> $2C --> Endless --> $AA
And extra lastly, I'm trying to obey the spec with regards to the pci frames and negative response handling. Just wondering if those skilled in the art wouldn't mind taking a look? I'm a hack when it comes to code.
Code: Select all
public static void SendCommand(PID.Pid_Obj pid_Obj, List<byte[]> sendCommand, List<byte[]> simReturnMessage = null)
{
int retryCnt_FlowCtrl = 0;
int negativeResponse = 0;
int dbg_RxMsgIndx = 0;
// Perform initialisation ops
pid_Obj.Payload.Clear();
pid_Obj.Status = PID.J2534_Message.status.OK;
pid_Obj.ErrorMsg = PID.J2534_Message.errorReason.None;
GetMessageResults messages = null;
int timeOut = pid_Obj.Timeout;
try
{
// Number of messages to send
for (int TxMsgIndx = 0; TxMsgIndx < sendCommand.Count; TxMsgIndx++)
{
// Send out the message to the node
if (!Form1.SIM_MODE)
{
Channel.SendMessage(sendCommand[TxMsgIndx]);
}
// Save the full length send command to the pid object for our reference
pid_Obj.TxBytes = sendCommand[TxMsgIndx];
// Logs the tx bytes to the status console
if (Logger.LogTxRxMsgsToStatusConsole) Logger.WriteLineAsync($"{Form1.indent} Tx {BitConverter.ToString(pid_Obj.TxBytes).Replace("-", " ").Remove(0, 12)}");
// Around we go
for (; ; )
{
AttemptWaitForResponse:
// Clear out the pci status and flow control registers before use
PciFrame.ResetPciBytes();
if (!Form1.SIM_MODE)
{
// Read response, block here till messages arrive or timeout expired
try
{
messages = Channel.GetMessages(1, timeOut);
}
catch (Exception e)
{
Logger.WriteLineAsync($"J2534.GetMessages() error. {e.Message}");
}
// Save full length message response for our reference
pid_Obj.RxBytes = messages.Messages[0].Data;
}
else
{
// Debug: Simulate message behaviour. Basically keep pumping them out until the buffer is empty
if (dbg_RxMsgIndx < simReturnMessage.Count)
{
pid_Obj.RxBytes = simReturnMessage[dbg_RxMsgIndx];
}
else
{
pid_Obj.Status = PID.J2534_Message.status.Error;
pid_Obj.ErrorMsg = PID.J2534_Message.errorReason.BufferEmptyTimeout;
goto Exit;
}
dbg_RxMsgIndx++;
}
// Log to status console
if (Logger.LogTxRxMsgsToStatusConsole) Logger.WriteLineAsync($"{Form1.indent} Rx {BitConverter.ToString(pid_Obj.RxBytes).Replace("-", " ").Remove(0, 12)}");
// Split into can id and can data frame
(pid_Obj.CanID, pid_Obj.CanFrame) = ParseOutCanIdAndFrame(pid_Obj.RxBytes);
// Parses pci frame(s) information
PciFrame.ePciType pciType = PciFrame.GetPciFrames(pid_Obj.CanFrame);
switch (pciType)
{
case PciFrame.ePciType.Single:
pid_Obj.DataLen = PciFrame.DataLength;
// Payload. For pci type 'single' payload width is 7 bytes
pid_Obj.CanPayload = GetPayload(pid_Obj.CanFrame, 1, pid_Obj.DataLen);
// Add the payload to the response list
pid_Obj.Payload.Add(pid_Obj.CanPayload);
// Positive response
if (pid_Obj.CanFrame[1] == 0x6D) // Success, all done
{
pid_Obj.Status = PID.J2534_Message.status.OK;
goto Exit;
}
// Negative response
if (pid_Obj.CanFrame[1] == 0x7F) // Negative response
{
bool error = ProcessNegativeResponse(pid_Obj, ref negativeResponse, pid_Obj.MaxRetries);
if (error)
goto Exit; // No good, exit with error
else
goto AttemptWaitForResponse; // Response pending, attempt again to wait for a message to arrive
}
goto Exit;
case PciFrame.ePciType.First:
pid_Obj.DataLen = PciFrame.DataLength;
// Calc number of messages we are to receive
pid_Obj.TrgtMsgCnt = NumberOfRxMsgs(pid_Obj.DataLen);
// This is the first message
pid_Obj.ActMsgCnt++;
// Payload. For pci type 'first' payload width is 6 bytes
pid_Obj.CanPayload = GetPayload(pid_Obj.CanFrame, 2, 6);
// Add the payload to the response list
pid_Obj.Payload.Add(pid_Obj.CanPayload);
break;
case PciFrame.ePciType.Consecutive:
pid_Obj.SeqNum = PciFrame.SequenceNum;
// The sequence numbers start at 0x21 through to 0x2F then it repeats. Anyway, I'm not
// looking at them, just keeping count instead
pid_Obj.ActMsgCnt++;
// Payload. For pci type 'consecutive' payload width is 7 bytes
pid_Obj.CanPayload = GetPayload(pid_Obj.CanFrame, 1, 7);
// Add the payload to the response list
pid_Obj.Payload.Add(pid_Obj.CanPayload);
// Last message?
if (pid_Obj.TrgtMsgCnt == pid_Obj.ActMsgCnt)
{
pid_Obj.Status = PID.J2534_Message.status.OK;
goto Exit;
}
break;
case PciFrame.ePciType.FlowControl:
PciFrame.eFlowCtrl flowCtrl = PciFrame.GetFlowCtrlCode(pid_Obj.CanFrame);
switch (flowCtrl)
{
case PciFrame.eFlowCtrl.ClearToSend:
goto SendNextMsg;
case PciFrame.eFlowCtrl.Wait:
if (retryCnt_FlowCtrl > pid_Obj.MaxRetries)
{
pid_Obj.Status = PID.J2534_Message.status.Error;
pid_Obj.ErrorMsg = PID.J2534_Message.errorReason.FlowControlWaitTimeout;
goto Exit;
}
retryCnt_FlowCtrl++;
Thread.Sleep(5);
goto AttemptWaitForResponse;
case PciFrame.eFlowCtrl.Overflow:
pid_Obj.Status = PID.J2534_Message.status.Error;
pid_Obj.ErrorMsg = PID.J2534_Message.errorReason.FlowControlOverflow;
goto Exit;
}
break;
}
}
SendNextMsg:;
}
}
catch (Exception ex)
{
Logger.WriteLineAsync($"SendCommand Error source: {0} {ex.Source}");
APIFactory.StaticDispose();
pid_Obj.Status = PID.J2534_Message.status.Error;
pid_Obj.ErrorMsg = PID.J2534_Message.errorReason.Exception;
pid_Obj.ExceptionMsg = ex.Message;
}
Exit:
// If error, print result
if (pid_Obj.Status == PID.J2534_Message.status.Error)
{
Logger.WriteLineAsync
(
$"{Form1.indent} Send command error: " +
$"{pid_Obj.ErrorMsg.ToString()} " +
$"{(pid_Obj.NegResp == PID.J2534_Message.negResponce.None ? String.Empty : pid_Obj.NegResp.ToString())}"
);
if (pid_Obj.ErrorMsg == PID.J2534_Message.errorReason.Exception)
{
Logger.WriteLineAsync($"{Form1.indent} Exception message: {pid_Obj.ExceptionMsg.ToString()}");
}
}
}
private static bool ProcessNegativeResponse(PID.Pid_Obj pid, ref int retryCount, int maxRetries)
{
// 7. Negative Response ($7F) Service Definition pg 69
bool error = false;
byte errorCode = pid.CanFrame[3];
switch (errorCode)
{
case 0x11:
pid.Status = PID.J2534_Message.status.Error;
pid.ErrorMsg = PID.J2534_Message.errorReason.NegativeResponse;
pid.NegResp = PID.J2534_Message.negResponce.ServiceNotSupported;
error = true;
break;
case 0x12:
pid.Status = PID.J2534_Message.status.Error;
pid.ErrorMsg = PID.J2534_Message.errorReason.NegativeResponse;
pid.NegResp = PID.J2534_Message.negResponce.SubFunctionNotSupported_InvalidFormat;
error = true;
break;
case 0x22:
pid.Status = PID.J2534_Message.status.Error;
pid.ErrorMsg = PID.J2534_Message.errorReason.NegativeResponse;
pid.NegResp = PID.J2534_Message.negResponce.ConditionsNotCorrectOrRequestSequenceError;
error = true;
break;
case 0x31:
pid.Status = PID.J2534_Message.status.Error;
pid.ErrorMsg = PID.J2534_Message.errorReason.NegativeResponse;
pid.NegResp = PID.J2534_Message.negResponce.RequestOutOfRange;
error = true;
break;
case 0x35:
pid.Status = PID.J2534_Message.status.Error;
pid.ErrorMsg = PID.J2534_Message.errorReason.NegativeResponse;
pid.NegResp = PID.J2534_Message.negResponce.InvalidKey;
error = true;
break;
case 0x36:
pid.Status = PID.J2534_Message.status.Error;
pid.ErrorMsg = PID.J2534_Message.errorReason.NegativeResponse;
pid.NegResp = PID.J2534_Message.negResponce.ExceedNumberOfAttempts;
error = true;
break;
case 0x37:
pid.Status = PID.J2534_Message.status.Error;
pid.ErrorMsg = PID.J2534_Message.errorReason.NegativeResponse;
pid.NegResp = PID.J2534_Message.negResponce.RequiredTimeDelayNotExpired;
error = true;
break;
case 0x78:
error = false;
retryCount++;
if (retryCount > maxRetries)
{
pid.Status = PID.J2534_Message.status.Error;
pid.ErrorMsg = PID.J2534_Message.errorReason.NegativeResponse;
pid.NegResp = PID.J2534_Message.negResponce.RequestCorrectlyReceived_ResponsePending;
error = true;
}
break;
case 0x81:
pid.Status = PID.J2534_Message.status.Error;
pid.ErrorMsg = PID.J2534_Message.errorReason.NegativeResponse;
pid.NegResp = PID.J2534_Message.negResponce.SchedulerFull;
error = true;
break;
case 0x83:
pid.Status = PID.J2534_Message.status.Error;
pid.ErrorMsg = PID.J2534_Message.errorReason.NegativeResponse;
pid.NegResp = PID.J2534_Message.negResponce.VoltageOutOfRangeFault;
error = true;
break;
case 0x85:
pid.Status = PID.J2534_Message.status.Error;
pid.ErrorMsg = PID.J2534_Message.errorReason.NegativeResponse;
pid.NegResp = PID.J2534_Message.negResponce.GeneralProgrammingFailure;
error = true;
break;
case 0x89:
pid.Status = PID.J2534_Message.status.Error;
pid.ErrorMsg = PID.J2534_Message.errorReason.NegativeResponse;
pid.NegResp = PID.J2534_Message.negResponce.DeviceTypeError;
error = true;
break;
case 0x99:
pid.Status = PID.J2534_Message.status.Error;
pid.ErrorMsg = PID.J2534_Message.errorReason.NegativeResponse;
pid.NegResp = PID.J2534_Message.negResponce.ReadyForDownload_DTCStored;
error = true;
break;
case 0xE3:
pid.Status = PID.J2534_Message.status.Error;
pid.ErrorMsg = PID.J2534_Message.errorReason.NegativeResponse;
pid.NegResp = PID.J2534_Message.negResponce.DeviceControlLimitsExceeded;
error = true;
break;
default:
pid.Status = PID.J2534_Message.status.Error;
pid.ErrorMsg = PID.J2534_Message.errorReason.NegativeResponse;
pid.NegResp = PID.J2534_Message.negResponce.UndocumentedResponseCode;
error = true;
break;
}
return error;
}