//----------------------------------------------------------------------- // // 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 { using System; using global::DeviceApi; using global::SharedObjects; using global::SharedObjects.Api; using global::SharedObjects.GUI; using global::SharedObjects.Misc; using global::SharedObjects.Protocol; // // Handler for J1850 protocol // TODO, fix implementation, this is just a stub now! // // Stuff found at: http://www.hptuners.com/forum/showthread.php?t=2017 // // Byte1 = priority (bits 7,6 and 5. 0=high 7=low), addresing mode and other flags, // Byte2 = physical ID of destination, $10 = PCM // Byte3 = physical ID of source, $F1 = off-board tool // // J2178 Part 4 *is only for message types: 0,1,2,8,9,10 and 11. // There are 16 message types defined by bits 3,2,1,0 of the first byte of the 3 byte header. // Each of those message types for J2178-4 is FUNCTIONAL addressing. The only supported destination address for FUNCTIONAL addressing on GM that I know of is $6A - legislated diagnostics. // // If you want to send a message to the PCM via a physically addressed message using $10 as the PCM's physical address you'd best use message type 12. ie low 4 bits of byte 1 of 3 byte header should be 1100. // The physical ID's are listed in section 9 of J2178-1 // $10..$17 are reserved for engine controllers. // GM normally uses $10. // // You ared right GM does not use IFR - it's part of the 3 byte header, bit 3=1 means IFR not allowed. // // // // // ...the only link I have that's worth a darn is // // http://www.diy-efi.org/gmecm/ecm_info/obd2/ // // It has a lot of stuff, but OLD. (1994). Lord know's I don't want to shell out $140 for the 2002 copy of hs-3000... just for a part timer/hobbiest/shade tree mechanic like myself.... // // // // // Does this help any? // // Functional Messages // =================== // Request current value of PID ($00..$20) // Send: $68,$6A,$F1,$01,$PID // Recv: $48,$6B,$10,$41,$PID,[up to 5 data bytes] // // Request freeze frame value of PID ($00..$20) // Send: $68,$6A,$F1,$02,$PID // Recv: $48,$6B,$10,$42,$PID,[up to 5 data bytes] // // Physical Messages // ================= // Request GM VIN // Send: $6C,$10,$F1,$3C,$01,$F2 // Recv: $6C,$F1,$10,$7C,$01,$00,$36,$48,$38,$56,$54,$18 // Send: $6C,$10,$F1,$3C,$02,$F3 // Recv: $6C,$F1,$10,$7C,$02,$4B,$36,$39,$46,$59,$4C,$5E // Send: $6C,$10,$F1,$3C,$03,$F4 // Recv: $6C,$F1,$10,$7C,$03,$30,$31,$32,$33,$34,$35,$F6 // Vin: 6H8VTK69FYL012345 // // Request GM PCM# // Send: $6C,$10,$F1,$3C,$04 // Recv: $6C,$F1,$10,$7C,$04,$00,$F7,$81,$C2 // PCM#: $00F781C2 = 16220610 // // Request enhanced PID ($0000..$FFFF) // Send: $6C,$10,$F1,$22,$PID-msb,$PID-lsb,$01 // Recv: $6C,$F1,$10,$62,$PID-msb,$PID-lsb,[up to 5 data bytes] // // Enhanced PIDs $0000..$0020 are identical to generic PIDs ($00..$20). // // ... the j2178_p1 says "engine control = 0x10 - 0x17. That's 8 nodes... // We know what 10 is (and the functionality is described in spec j2190, // but what about the rest of the nodes (and there functionality)? // // Just send a supported, but harmless command to each of the 255 possible nodes - like "Stop transmitting diagnostic data" - mode $25. // // ... // Send: $01,$01,$41,$04,$6C,$10,$F1,$25,$D9 // Recv: $01,$01,$C1,$04,$6C,$F1,$10,$65,$99 // This means ID $10 exists on the class-2 bus // Send: $01,$01,$41,$04,$6C,$11,$F1,$25,$DA // Recv: No response - ID $11 does not exist. // ... // // You can then match up the ID's with the ID ranges to figure out which is which. /// /// Implementation of the J1850 protocols. /// public class Protocol_J1850 : Protocol_Common, IProtocolHandler, IMsgCallback { /// /// Possible address bits alternatives. /// private static readonly string[] possibleAddressbits = { "8" }; /// /// Initializes a new instance of the class. /// /// Logging interface. /// Current protocol. /// Current message handler instance. /// Source address. /// Checksum flag. /// Callback interface for enabling the buttons when a protocol is fully initialized. public Protocol_J1850( ILogging iLogging, Protocols protocol, MessageHandler messageHandler, uint srcAddr, bool checksum, IEnableButtons iEnableButtons) : base(iLogging, protocol, messageHandler, srcAddr, checksum, iEnableButtons) { throw new NotImplementedException("Protocol_J1850 is not implemented."); /* // Register this protocol handler with the message handler. this.messageHandler.setProtocolCallback(this); */ } /// /// Get the address bit alternatives for the protocol. /// /// Array of alternatives. public static string[] addressBitAlternatives() { return possibleAddressbits; } /// /// Indicates if protocol is in 29 bit mode. /// /// 'true' if protocol is in 29 bit mode. public bool is29bit() { return false; } /// /// Initialize protocol. /// /// TX Flags for any messages that are created during initialization. public void init(int txFlags) { } /// /// Start protocol. /// public void start() { } /// /// Stop protocol. /// public void stopProtocol() { } /// /// Receive one message and dispatch it to receivers. /// /// Message to receive. public void receiveMessage(IPassThruMsg rxmsg) { } /// /// Get payload part from message. /// /// Message to get payload data from. /// Payload byte array. public override byte[] getPayload(IPassThruMsg msg) { byte[] payload = extractPayload(msg, 4); return payload; } /// /// Send one message where the header info already is set in the payload. /// /// Source address (address of tester). /// Tx Flags /// Message Payload which includes address data. public void sendProbeMessage(uint srcAddr, int txFlags, byte[] payload) { this.sendMessage(0xf0, 0x33, txFlags, payload); } /// /// Send one message to the given receiver address. /// /// Source address. /// Destination address. /// TX Flags. /// Payload data. /// Error message in case of a problem. public string sendMessage(uint sourceAddress, uint destinationAddress, int txFlags, byte[] payload) { return string.Empty; } /// /// Set the address(es) of the message. /// /// Message to set data in. /// Source Address. /// Destination Address. public void setAddress(ref IPassThruMsg txmsg, uint sourceAddress, uint destinationAddress) { } /// /// Set the address(es) of the message. /// /// This is a fully composed address, usually used by filters. /// /// /// Message to set data in. /// Combined Address. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Justification = "Reviewed.")] public void setAddress(ref IPassThruMsg txmsg, uint address) { txmsg.Data[1] = (byte)((address >> 8) & 0xff); txmsg.Data[2] = (byte)(address & 0xff); txmsg.DataSize = 3; } /// /// Set additional header data in addition to the address. /// /// Message to add data to. /// Size of message. /// 'true' if the destination address is functional address. public void setHeader(ref IPassThruMsg txmsg, uint size, bool functionalTargetAddressing) { // TODO. } /// /// Add the payload to the message. /// /// Byte array of payload to send. /// Message to update with payload. /// Hex string with message, to be used for logging. private static string addPayload(byte[] payload, ref IPassThruMsg txmsg) { string dataStr = string.Empty; for (int i = 0; i < payload.Length; i++) { txmsg.Data[txmsg.DataSize++] = payload[i]; dataStr += string.Format("{0:x2} ", payload[i]); } return dataStr; } /// /// Call the message handler and send the formatted message structure. /// /// TX Flags. /// Message to send. /// Status code, 0=success. private PassThruConstants.resultCode sendMessage(int txFlags, IPassThruMsg txmsg) { // Set message flags. txmsg.TxFlags = txFlags; return this.messageHandler.sendMessage(txmsg); } /// /// Add checksum if requested. /// Notice that CAN and ISO 15765 doesn't need a checksum. /// But it's up to the user to decide, so we just check /// if the checkbox is checked. /// /// Message to add checksum to. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Justification = "Reviewed.")] private void addChecksum(ref IPassThruMsg txmsg) { if (this.checksum) { int cs = Utils.getChecksum(txmsg.Data, 0, txmsg.DataSize); txmsg.Data[txmsg.DataSize++] = (byte)(cs & 0xff); } } } }