//-----------------------------------------------------------------------
//
// Copyright © 2012 Nils Hammar. All rights reserved.
//
//-----------------------------------------------------------------------
/*
* Software to access vehicle information via the OBD-II connector.
*
* Copyright © 2012 Nils Hammar
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
* Alternative licensing is possible, see the licensing document.
*
* The above text may not be removed or modified.
*/
namespace Protocol.OBD
{
using System;
using System.Collections;
using System.Collections.Generic;
using System.Windows.Forms;
using global::SharedObjects;
using global::SharedObjects.DataMgmt;
using global::SharedObjects.Misc;
using global::SharedObjects.Protocol;
using global::SharedObjects.Protocol.OBD;
///
/// Class for parsing the "mode" byte received from the ECU.
///
/// This is the top level of the data structure, and this class
/// dispatches to various sub classes depending on data type.
///
///
public class ModeParser : IModeParser
{
///
/// Position of MODE byte in array.
///
public const int BYTE_MODE = 0;
///
/// Position of PID byte in array.
///
public const int BYTE_PID = 1;
///
/// Position of error code byte in the array for error responses.
///
public const int BYTE_ERRCODE = 2;
///
/// Position of Frame# byte.
///
public const int BYTE_FRAME = 2;
///
/// Current logger instance.
///
private ILogging iLogging;
///
/// Current protocol handler.
///
private IProtocolHandler protocolHandler;
///
/// List of panels able to receive and parse data.
///
private List dataPanels = new List();
///
/// Dictionary for fast lookup of PidGroup item.
///
private Hashtable modePidDictionary = new Hashtable();
///
/// Messaging interface.
///
private IMessaging iMessaging;
///
/// Gets Current PID parser instance.
///
public IPidParser pidParser { get; private set; }
///
/// Gets or sets a value indicating whether probing PIDs is active.
///
public bool probePids { get; set; }
///
/// Data source interface instance.
///
private IDataSource iDataSource;
///
/// Request data to help with parsing.
///
private IRequestData requestData = null;
///
/// Helper class that matches requests with responses.
///
private IRequestMatcher iRequestMatcher;
///
/// Initializes a new instance of the class.
///
/// Logger instance.
/// Data source interface instance.
/// Protocol handler instance.
/// PID parser instance.
/// Messaging interface instance.
/// Current request matcher instance.
public ModeParser(
ILogging iLogging,
IDataSource iDataSource,
IProtocolHandler protocolHandler,
PidParser pidParser,
IMessaging iMessaging,
IRequestMatcher iRequestMatcher)
{
this.iLogging = iLogging;
this.iDataSource = iDataSource;
this.protocolHandler = protocolHandler;
this.pidParser = pidParser;
this.iMessaging = iMessaging;
this.iRequestMatcher = iRequestMatcher;
this.configureModePidDictionary();
if (protocolHandler != null)
{
protocolHandler.addModeParser(this);
}
}
///
/// Finalizes an instance of the class.
///
~ModeParser()
{
this.close();
}
///
/// Close the service.
///
public void close()
{
if (this.protocolHandler != null)
{
this.protocolHandler.removeModeParser(this);
this.protocolHandler = null;
}
}
///
/// Register a panel able to receive data.
///
/// Panel to register.
public void registerPanel(IDataPanel panel)
{
this.dataPanels.Add(panel);
}
///
/// Remove registered panel.
///
/// Panel to unregister.
public void unregisterPanel(IDataPanel panel)
{
this.dataPanels.Remove(panel);
}
///
/// Receive data to be parsed and presented.
///
/// Data to be presented.
/// Source address of message.
/// Detected protocol by ELM/AGV adapter.
public void receiveMessageData(byte[] payload, uint srcAddress, uint detectedProtocol)
{
bool popNext = false;
this.requestData = null;
if (payload != null)
{
byte mode_int = payload[BYTE_MODE];
uint? destinationAddress = DataRequester.getDestinationAddress(this.iMessaging.protocolHandler, srcAddress);
/*
* Some ECUs allows for periodic transmission of data, and therefore
* no matching request exist so we have to take care of those cases
* here.
*/
switch (mode_int)
{
default:
this.requestData = this.iRequestMatcher.getMatchingRequest(destinationAddress, mode_int, payload);
break;
}
this.iMessaging.sendMsg();
if (this.probePids)
{
popNext = this.handleOtherResponses(mode_int, payload, srcAddress, detectedProtocol);
}
else
{
switch (mode_int)
{
case 0x41: // Show current data.
popNext = this.handleBasicPids(mode_int, payload, srcAddress);
break;
case 0x42: // Show freeze frame data.
popNext = this.handleFreezeFramePids(mode_int, payload, srcAddress);
break;
case 0x44: // DTC Clear Diag Codes.
// No action to consider.
popNext = true;
break;
case 0x45: // Test results (Oxygen, Non-CAN).
// Not available on CAN.
popNext = true;
break;
case 0x48: // Control operation of onboard component.
popNext = true;
break;
case 0x62: // Extended PIDs
popNext = this.handleExtendedPids(mode_int, payload, srcAddress);
break;
case 0x7f: // Negative Response
this.handleNrc(payload);
popNext = true;
break;
default:
popNext = this.handleOtherResponses(mode_int, payload, srcAddress, detectedProtocol);
break;
}
}
}
this.iMessaging.sendMsg();
}
///
/// Set the pending requests that can be performed after the current request has had an answer.
///
/// List of pending requests.
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Justification = "Reviewed.")]
public void setPendingRequests(IList pendingModeRequests)
{
foreach (IRequestData req in pendingModeRequests)
{
this.iMessaging.queueMsg(req);
}
}
///
/// Set up a dictionary of the known Mode/PID combinations.
/// Notice that the list we use is the list that is filtered depending on preferred units. (Metric or Imperial)
///
public void configureModePidDictionary()
{
this.modePidDictionary = new Hashtable();
foreach (XmlClass.pidgroup pidGroup in this.iDataSource.restrictedPidgroups)
{
foreach (XmlClass.pidgroup.pidlist item in pidGroup.pids)
{
uint key = getDictionaryKey(pidGroup.mode_int, item.pid_int);
if (!this.modePidDictionary.ContainsKey(key))
{
this.modePidDictionary.Add(key, item);
}
// Since PID 0x02 is identical with PID 0x01 we just copy the list.
// For PID 0x22 the first 256 PIDs are identical with PID 0x01, so we copy that too.
if (pidGroup.mode_int == 0x01)
{
uint key02 = getDictionaryKey(0x02, item.pid_int);
uint key22 = getDictionaryKey(0x22, item.pid_int);
if (!this.modePidDictionary.ContainsKey(key02))
{
this.modePidDictionary.Add(key02, item);
}
if (!this.modePidDictionary.ContainsKey(key22))
{
this.modePidDictionary.Add(key22, item);
}
}
}
}
}
///
/// Fetch the matching PID Item for the Mode/PID combination.
///
/// Current mode byte value.
/// ID of PID to fetch.
/// Matching PID item or a temporarily generated PID item if not found.
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1720:IdentifiersShouldNotContainTypeNames", MessageId = "int", Justification = "Reviewed.")]
public XmlClass.pidgroup.pidlist findPidItem(uint mode_int, uint pid)
{
XmlClass.pidgroup.pidlist pidItem = null;
// Notice that we need to mask off the bit set on responses.
uint key = getDictionaryKey((mode_int & 0xbf), pid);
if (this.modePidDictionary.ContainsKey(key))
{
pidItem = (XmlClass.pidgroup.pidlist)this.modePidDictionary[key];
}
// Do fallback handling. Better to show something than to crash.
// This can be improved a bit to add some default sensor.
if (pidItem == null)
{
pidItem = new XmlClass.pidgroup.pidlist();
pidItem.pid_int = (uint)pid;
pidItem.name = " * UNKNOWN PID " + string.Format("0x{0:x2}", pid) + ", mode=" + string.Format("0x{0:x2}", mode_int) + " * ";
this.iLogging.appendText("Received PID '" + string.Format("0x{0:x2}", pid) + "' is not configured.\r\n");
}
return pidItem;
}
///
/// Create lookup key for dictionary searches.
///
/// Mode part of key (0x00 to 0xff)
/// PID or Address part of key (0x000000 to 0xffffff)
/// Composite key value.
private static uint getDictionaryKey(uint mode, uint pid)
{
return ((mode << 24) & 0xff000000) | (pid & 0xffffff);
}
///
/// Basic PIDs are 8 bits, 0x00 to 0xff.
///
/// Current mode byte value.
/// Message payload.
/// Source address of received data.
/// 'true' if it's OK to pop the next message to send and send it.
private bool handleBasicPids(byte mode_int, byte[] payload, uint srcAddress)
{
bool popNext = false;
uint pid = (uint)(payload[BYTE_PID] & 0xff);
int headerSize = 2;
XmlClass.pidgroup.pidlist pidItem = this.findPidItem(mode_int, pid);
byte[] pidPayload = Utils.extractData(payload, headerSize);
try
{
popNext = this.pidParser.parsePid(pidItem, mode_int, 0, pidPayload, srcAddress);
}
catch (IndexOutOfRangeException ex)
{
this.iLogging.appendText("Insufficient data for PID, mode=0x" + mode_int.ToString("x2") + ", PID=0x" + pidItem.pid_int.ToString("x4") + " - " + pidItem.name + "\r\n" + ex.Message + "\r\n\r\n" + ex.StackTrace + "\r\n");
}
return popNext;
}
///
/// Freeze Frame data are 8 bits PID, 0x00 to 0xff and 8 bits Frame #.
///
/// Current mode byte value.
/// Message payload.
/// Source address of received data.
/// 'true' if it's OK to pop the next message to send and send it.
private bool handleFreezeFramePids(byte mode_int, byte[] payload, uint srcAddress)
{
bool popNext = false;
uint pid = (uint)(payload[BYTE_PID] & 0xff);
byte frame = payload[BYTE_FRAME];
int headerSize = 3;
XmlClass.pidgroup.pidlist pidItem = this.findPidItem(mode_int, pid);
byte[] pidPayload = Utils.extractData(payload, headerSize);
try
{
popNext = this.pidParser.parsePid(pidItem, mode_int, frame, pidPayload, srcAddress);
}
catch (IndexOutOfRangeException ex)
{
this.iLogging.appendText("Insufficient data for PID, mode=0x" + mode_int.ToString("x2") + ", PID=0x" + pidItem.pid_int.ToString("x4") + " - " + pidItem.name + "\r\n" + ex.Message + "\r\n\r\n" + ex.StackTrace + "\r\n");
}
return popNext;
}
///
/// Extended PIDs are 16 bits, 0x0000 to 0xffff.
/// Notice that 0x0000 to 0x00ff shall be identical with basic PIDs.
///
/// Current mode byte value.
/// Message payload.
/// Source address of received data.
/// 'true' if it's OK to pop the next message to send and send it.
private bool handleExtendedPids(byte mode_int, byte[] payload, uint srcAddress)
{
bool popNext = false;
uint pid = (uint)((payload[BYTE_PID] << 8 | payload[BYTE_PID + 1]) & 0xffff);
int headerSize = 3;
XmlClass.pidgroup.pidlist pidItem = this.findPidItem(mode_int, pid);
byte[] pidPayload = Utils.extractData(payload, headerSize);
try
{
popNext = this.pidParser.parsePid(pidItem, mode_int, 0, pidPayload, srcAddress);
}
catch (IndexOutOfRangeException ex)
{
this.iLogging.appendText("Insufficient data for PID, mode=0x" + mode_int.ToString("x2") + ", PID=0x" + pidItem.pid_int.ToString("x4") + " - " + pidItem.name + "\r\n" + ex.Message + "\r\n\r\n" + ex.StackTrace + "\r\n");
}
return popNext;
}
///
/// Some panels can have additional functionality that
/// is taking care of cases that aren't the default.
///
/// Loop through all panels that has registered and break
/// on the first panel that has captured the data.
///
///
/// Notice that some panels may capture data and not
/// tell about it since the data can correctly be
/// captured by more than one panel and presented.
///
///
/// Current mode byte value.
/// Payload array.
/// Source address of received data.
/// Detected protocol by ELM/AGV adapter.
/// 'true' if it's OK to pop the next message to send and send it.
private bool handleOtherResponses(byte mode_int, byte[] payload, uint srcAddress, uint detectedProtocol)
{
bool popNext = true;
foreach (IDataPanel iDataPanel in this.dataPanels)
{
try
{
if (iDataPanel.parse(mode_int, payload, this.requestData, ref popNext, srcAddress, detectedProtocol))
{
// break;
}
}
catch (Exception ex)
{
this.iLogging.appendText(ex.GetType().ToString() + ": " + ex.Message + "\r\n" + ex.StackTrace + "\r\n");
}
}
return popNext;
}
///
/// Handle a negative response from ECU.
///
/// This method takes the best effort to try to identify
/// the cause and present an explanation to the user.
///
///
/// Payload array.
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity", Justification = "Suitable in this case.")]
private void handleNrc(byte[] payload)
{
uint service = payload[BYTE_PID];
string fault = string.Empty;
for (int i = 0; i < this.iDataSource.modes.Count; i++)
{
if (service == this.iDataSource.modes[i].mode_int)
{
fault = string.Format("0x{0:x2}", this.iDataSource.modes[i].mode_int) + ": " + this.iDataSource.modes[i].name + "\r\n\r\n";
}
}
int severity = LogLevel.LOG_WARN;
switch (payload[BYTE_ERRCODE])
{
case 0x10:
fault += "General Reject - Service rejected by ECU.\r\n\r\n"
+ "This response code indicates that the service is rejected\r\n"
+ "but the server (ECU) does not specify the reason of the rejection.";
break;
case 0x11:
fault += "Service Not Supported - Service not supported by ECU.\r\n\r\n"
+ "This response code indicates that the requested action will not\r\n"
+ "be taken because the server (ECU) does not support the requested service.";
break;
case 0x12:
fault += "Sub Function Not Supported -Invalid Format\r\n\r\n"
+ "This response code indicates that the requested action will not\r\n"
+ "be taken because the server (ECU) does not support the arguments of\r\n"
+ "the request message or the format of the argument bytes do not match\r\n"
+ "the prescribed format for the specified service.";
break;
case 0x13:
fault += "Incorrect Message Length Or Invalid Format\r\n\r\n"
+ "This response code indicates that the requested action will not be taken because the\r\n"
+ "length of the received request message does not match the prescribed length for the\r\n"
+ "specified service or because the format of the parameters does not match the\r\n"
+ "prescribed format for the specified service.";
break;
case 0x14:
fault += "Sub Function Not Supported -Invalid Format\r\n\r\n"
+ "This response code shall be reported by the server if the response to be generated\r\n"
+ "exceeds the maximum number of bytes available by the underlying network layer.\r\n"
+ "EXAMPLE This problem may occur when several DIDs are requested at a time and the\r\n"
+ "combination of all DIDs in the response exceeds the limit of the underlying transport protocol.\r\n";
break;
case 0x21:
fault += "Busy - Repeat Request\r\nThis response code indicates that the\r\n"
+ "server (ECU) is temporarily too busy to perform the requested operation.\r\n"
+ "For ISO 15765-4 protocol the client (external test equipment) shall behave\r\n"
+ "as defined in ISO 15765-4. In a multi-client (more than one external test\r\n"
+ "equipment, e.g. telematic client) environment the diagnostic request\r\n"
+ "message of one client might be blocked temporarily by a negative response\r\n"
+ "message with response code $21 while another client finishes\r\n"
+ "a diagnostic task.\r\n\r\n"
+ "Therefore this negative response code is only allowed to be used during the\r\n"
+ "initialization sequence of the protocol.\r\n\r\n"
+ "NOTE If the server (ECU) is able to perform the diagnostic task but needs\r\n"
+ "additional time to finish the task and prepares the response message,\r\n"
+ "the negative response message with response code $78 are used instead of $21.";
break;
case 0x22:
fault += "Conditions Not Correct Or Request Sequence Error\r\n\r\n"
+ "This response code indicates that the requested action will not be taken\r\n"
+ "because the server (ECU) prerequisite conditions are not met. This request\r\n"
+ "may also occur when sequence-sensitive requests are issued in the wrong order.";
break;
case 0x24:
fault += "Request Sequence Error\r\n\r\n"
+ "This response code indicates that the requested action will not be taken because the\r\n"
+ "server expects a different sequence of request messages or message to that sent by\r\n"
+ "the client. This may occur when sequence-sensitive requests are issued in the wrong\r\n"
+ "order.\r\n"
+ "EXAMPLE A successful SecurityAccess service specifies a sequence of requestSeed and\r\n"
+ "sendKey as sub-functions in the request messages. If the sequence is sent differently by the\r\n"
+ "client, the server shall send a negative response message with the negative response code\r\n"
+ "24 hex - requestSequenceError.\r\n";
break;
case 0x25:
fault += "No Response From Subnet Component\r\n\r\n"
+ "This response code indicates that the server has received the request but the\r\n"
+ "requested action could not be performed by the server, as a subnet component\r\n"
+ "which is necessary to supply the requested information did not respond within the\r\n"
+ "specified time.\r\n"
+ "The noResponseFromSubnetComponent negative response shall be implemented\r\n"
+ "by gateways in electronic systems which contain electronic subnet components and\r\n"
+ "which do not directly respond to the client’s request. The gateway may receive the\r\n"
+ "request for the subnet component and then request the necessary information from\r\n"
+ "the subnet component. If the subnet component fails to respond, the server shall use\r\n"
+ "this negative response to inform the client about the failure of the subnet component.\r\n"
+ "This response code is, in general, supported by each diagnostic service, unless\r\n"
+ "otherwise stated in the data-link-specific implementation document; therefore, it is\r\n"
+ "not listed in the list of applicable response codes of the diagnostic services.\r\n";
break;
case 0x26:
fault += "Failure Prevents Execution Of Requested Action\r\n\r\n"
+ "This response code indicates that the requested action will not be taken because a\r\n"
+ "failure condition, identified by a DTC (with at least one DTC status bit for TestFailed,\r\n"
+ "Pending, Confirmed or TestFailedSinceLastClear set to 1), has occurred and that\r\n"
+ "this failure condition prevents the server from performing the requested action.\r\n"
+ "This NRC can, for example, direct the technician to read DTCs in order to identify\r\n"
+ "and fix the problem.\r\n"
+ "NOTE This implies that diagnostic services used to access DTCs shall not implement this\r\n"
+ "NRC, as an external test tool may check for the above NRC and automatically request DTCs\r\n"
+ "whenever the above NRC has been received.\r\n"
+ "This response code is, in general, supported by each diagnostic service (except the\r\n"
+ "services mentioned above), unless otherwise stated in the data-link-specific\r\n"
+ "implementation document; therefore, it is not listed in the list of applicable response\r\n"
+ "codes of the diagnostic services.\r\n";
break;
case 0x31:
fault += "Request Out Of Range\r\n\r\n"
+ "This response code indicates that the requested action will not be taken because the\r\n"
+ "server has detected that the request message contains a parameter which attempts\r\n"
+ "to substitute a value beyond its range of authority (e.g. attempting to substitute a\r\n"
+ "data byte of 111 when the data is only defined to 100), or which attempts to access a\r\n"
+ "dataIdentifier/routineIdentifer that is not supported or not supported in active session.\r\n"
+ "This response code shall be implemented for all services which allow the client to\r\n"
+ "read data, write data or adjust functions by data in the server.\r\n";
break;
case 0x33:
fault += "Security Access Denied\r\n\r\n"
+ "This response code indicates that the requested action will not be taken because the\r\n"
+ "server’s security strategy has not been satisfied by the client.\r\n"
+ "The server shall send this response code if one of the following cases occurs:\r\n"
+ " - the test conditions of the server are not met;\r\n"
+ " - the required message sequence, e.g. DiagnosticSessionControl, securityAccess, is not met;\r\n"
+ " - the client has sent a request message which requires an unlocked server.\r\n"
+ "Besides the mandatory use of this negative response code as specified in the\r\n"
+ "applicable services within this part of ISO 14229, this negative response code can\r\n"
+ "also be used for any case where security is required and is not yet granted to\r\n"
+ "perform the required service.\r\n";
break;
case 0x35:
fault += "Invalid Key\r\n\r\n"
+ "This response code indicates that the server has not given security access because\r\n"
+ "the key sent by the client did not match with the key in the server’s memory. This\r\n"
+ "counts as an attempt to gain security. The server shall remain locked and increment\r\n"
+ "its internal securityAccessFailed counter.\r\n";
break;
case 0x36:
fault += "Exceed Number Of Attempts\r\n\r\n"
+ "This response code indicates that the requested action will not be taken because the\r\n"
+ "client has unsuccessfully attempted to gain security access more times than the\r\n"
+ "server’s security strategy will allow.\r\n";
break;
case 0x37:
fault += "Required Time Delay Not Expired\r\n\r\n"
+ "This response code indicates that the requested action will not be taken because the\r\n"
+ "client’s latest attempt to gain security access was initiated before the server’s\r\n"
+ "required timeout period had elapsed.\r\n";
break;
case 0x70:
fault += "Upload Download Not Accepted\r\n\r\n"
+ "This response code indicates that an attempt to upload/download to a server’s\r\n"
+ "memory cannot be accomplished due to fault conditions.\r\n";
break;
case 0x71:
fault += "Transfer Data Suspended\r\n\r\n"
+ "This response code indicates that a data transfer operation was halted due to a fault.\r\n"
+ "The active transferData sequence shall be aborted.\r\n";
break;
case 0x72:
fault += "General Programming Failure\r\n\r\n"
+ "This response code indicates that the server detected an error when erasing or\r\n"
+ "programming a memory location in the permanent memory device (e.g. Flash Memory).\r\n";
break;
case 0x73:
fault += "Wrong Block Sequence Counter\r\n\r\n"
+ "This response code indicates that the server detected an error in the sequence of\r\n"
+ "blockSequenceCounter values. Note that the repetition of a TransferData request\r\n"
+ "message with a blockSequenceCounter equal to the one included in the previous\r\n"
+ "TransferData request message shall be accepted by the server.\r\n";
break;
case 0x78:
severity = LogLevel.LOG_INFO;
fault += "Request Correctly Received - Response Pending\r\n\r\n"
+ "This response code indicates that the request message was received\r\n"
+ "correctly, and that any parameters in the request message were valid,\r\n"
+ "but the action to be performed may not be completed yet. This response\r\n"
+ "code can be used to indicate that the request message was properly\r\n"
+ " received and does not need to be re-transmitted,\r\n"
+ "but the server (ECU) is not yet ready to receive another request.\r\n\r\n"
+ "The negative response message with this response code may be repeated\r\n"
+ "by the ECU(s) within P2K-Line = P2CAN = P2*max until the positive response\r\n"
+ "message with the requested data is available.";
break;
case 0x7E:
fault += "Sub Function Not Supported In Active Session\r\n\r\n"
+ "This response code indicates that the requested action will not be taken because the\r\n"
+ "server does not support the requested sub-function in the session currently active.\r\n"
+ "Within the programmingSession, negative response code SFNS\r\n"
+ "(subFunctionNotSupported) may optionally be reported instead of negative response\r\n"
+ "code SNFSIAS (subFunctionNotSupportedInActiveSession). This response code\r\n"
+ "shall only be used when the requested sub-function is known to be supported in\r\n"
+ "another session, otherwise response code SFNS (subFunctionNotSupported) shall\r\n"
+ "be used.\r\n"
+ "This response code shall be supported by each diagnostic service with a subfunction\r\n"
+ "parameter, if not otherwise stated in the data-link-specific implementation\r\n"
+ "document; therefore, it is not listed in the list of applicable response codes of the\r\n"
+ "diagnostic services.\r\n";
break;
case 0x7F:
fault += "Service Not Supported In Active Session\r\n\r\n"
+ "This response code indicates that the requested action will not be taken because the\r\n"
+ "server does not support the requested service in the session currently active. This\r\n"
+ "response code shall only be used when the requested service is known to be\r\n"
+ "supported in another session, otherwise response code SNS (serviceNotSupported)\r\n"
+ "shall be used.\r\n"
+ "This response code is, in general, supported by each diagnostic service, unless\r\n"
+ "otherwise stated in the data-link-specific implementation document; therefore, it is\r\n"
+ "not listed in the list of applicable response codes of the diagnostic services.\r\n";
break;
case 0x81:
fault += "Rpm Too High\r\n\r\n"
+ "This response code indicates that the requested action will not be taken because the\r\n"
+ "server prerequisite condition for RPM is not met (current RPM is above a\r\n"
+ "preprogrammed maximum threshold).\r\n";
break;
case 0x82:
fault += "Rpm Too Low\r\n\r\n"
+ "This response code indicates that the requested action will not be taken because the\r\n"
+ "server prerequisite condition for RPM is not met (current RPM is below a\r\n"
+ "preprogrammed minimum threshold).\r\n";
break;
case 0x83:
fault += "Engine Is Running\r\n\r\n"
+ "This is required for those actuator tests which cannot be actuated while the engine is\r\n"
+ "running. This is different from the RPM too high negative response and needs to be\r\n"
+ "allowed.\r\n";
break;
case 0x84:
fault += "Engine Is Not Running\r\n\r\n"
+ "This is required for those actuator tests which cannot be actuated unless the Engine\r\n"
+ "is running. This is different from the RPM too low negative response and shall be allowed.\r\n";
break;
case 0x85:
fault += "Engine Run Time Too Low\r\n\r\n"
+ "This response code indicates that the requested action will not be taken because the\r\n"
+ "server prerequisite condition for engine run time is not met (current engine run time\r\n"
+ "is below a preprogrammed limit).\r\n";
break;
case 0x86:
fault += "Temperature Too High\r\n\r\n"
+ "This response code indicates that the requested action will not be taken because the\r\n"
+ "server prerequisite condition for temperature is not met (current temperature is\r\n"
+ "above a preprogrammed maximum threshold).\r\n";
break;
case 0x87:
fault += "Temperature Too Low\r\n\r\n"
+ "This response code indicates that the requested action will not be taken because the\r\n"
+ "server prerequisite condition for temperature is not met (current temperature is below\r\n"
+ "a preprogrammed minimum threshold).\r\n";
break;
case 0x88:
fault += "Vehicle Speed Too High\r\n\r\n"
+ "This response code indicates that the requested action will not be taken because the\r\n"
+ "server prerequisite condition for vehicle speed is not met (current VS is above a\r\n"
+ "preprogrammed maximum threshold).\r\n";
break;
case 0x89:
fault += "Vehicle Speed Too Low\r\n\r\n"
+ "This response code indicates that the requested action will not be taken because the\r\n"
+ "server prerequisite condition for vehicle speed is not met (current VS is below a\r\n"
+ "preprogrammed minimum threshold).\r\n";
break;
case 0x8A:
fault += "Throttle/Pedal Too High\r\n\r\n"
+ "This response code indicates that the requested action will not be taken because the\r\n"
+ "server prerequisite condition for throttle/pedal position is not met (current TP/APP is\r\n"
+ "above a preprogrammed maximum threshold).\r\n";
break;
case 0x8B:
fault += "Throttle/Pedal Too Low\r\n\r\n"
+ "This response code indicates that the requested action will not be taken because the\r\n"
+ "server prerequisite condition for throttle/pedal position is not met (current TP/APP is\r\n"
+ "below a preprogrammed minimum threshold).\r\n";
break;
case 0x8C:
fault += "Transmission Range Not In Neutral\r\n\r\n"
+ "This response code indicates that the requested action will not be taken because the\r\n"
+ "server prerequisite condition for being in neutral is not met (current transmission\r\n"
+ "range is not in neutral).\r\n";
break;
case 0x8D:
fault += "transmissionRangeNotInGear\r\n\r\n"
+ "This response code indicates that the requested action will not be taken because the\r\n"
+ "server prerequisite condition for being in gear is not met (current transmission range\r\n"
+ "is not in gear).\r\n";
break;
case 0x8F:
fault += "Brake Switch(es) Not Closed (brake pedal not pressed or not applied)\r\n\r\n"
+ "For safety reasons, this is required before beginning certain tests, and must be\r\n"
+ "maintained for the entire duration of the test.\r\n";
break;
case 0x90:
fault += "Shifter Lever Not In Park\r\n\r\n"
+ "For safety reasons, this is required before beginning certain tests, and must be\r\n"
+ "maintained for the entire duration of the test.\r\n";
break;
case 0x91:
fault += "Torque Converter Clutch Locked\r\n\r\n"
+ "This response code indicates that the requested action will not be taken because the\r\n"
+ "server prerequisite condition for torque converter clutch is not met (current TCC\r\n"
+ "status is above a preprogrammed limit or locked).\r\n";
break;
case 0x92:
fault += "Voltage Too High\r\n\r\n"
+ "This response code indicates that the requested action will not be taken because the\r\n"
+ "server prerequisite condition for voltage at the primary pin of the server (ECU) is not\r\n"
+ "met (current voltage is above a preprogrammed maximum threshold).\r\n";
break;
case 0x93:
fault += "Voltage Too Low\r\n\r\n"
+ "This response code indicates that the requested action will not be taken because the\r\n"
+ "server prerequisite condition for voltage at the primary pin of the server (ECU) is not\r\n"
+ "met (current voltage is below a preprogrammed maximum threshold).\r\n";
break;
default:
fault += " * UNKNOWN * code=" + string.Format("0x{0:x2}", payload[BYTE_ERRCODE]);
break;
}
if (!this.probePids)
{
if (severity >= LogLevel.LOG_WARN)
{
MessageBox.Show(
fault,
"ECU Error Response!",
MessageBoxButtons.OK,
MessageBoxIcon.Hand);
}
}
this.iLogging.appendText(fault);
}
}
}