//-----------------------------------------------------------------------
//
// 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);
}
}
}
}