//-----------------------------------------------------------------------
//
// 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.
*/
//// #define DEBUG1
namespace UserInterface.GUI
{
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Threading;
using System.Windows.Forms;
using global::CanApp.CAN;
using global::Gauges;
using global::Protocol;
using global::Protocol.OBD;
using global::SharedObjects;
using global::SharedObjects.Api;
using global::SharedObjects.DataMgmt;
using global::SharedObjects.GUI;
using global::SharedObjects.GUI.Popup;
using global::SharedObjects.Misc;
using global::SharedObjects.Misc.Objects;
using global::SharedObjects.Protocol;
using global::UserInterface.GUI.OBD;
using global::UserInterface.GUI.Objects;
using global::UserInterface.GUI.Special;
///
/// Construct connection panel component.
///
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1506:AvoidExcessiveClassCoupling", Justification = "Reviewed.")]
public partial class ConnectionPanel : AbstractUserControl, IEnableButtons
{
///
/// Gets Current protocol handler instance.
///
public IProtocolHandler protocolHandler { get; private set; }
///
/// Preferences interface.
///
private IPreferences iPreferences;
///
/// Protocol panel callback interface.
///
private IProtocolCallback iProtocolCallback;
///
/// Current device connection.
///
private IPassThruConnection passThruConnection;
///
/// Current protocol.
///
private Protocols protocol;
///
/// Current dictionary of OBD codes.
///
private SortedDictionary obdcodes;
///
/// Current message handler instance.
///
private MessageHandler messageHandler;
///
/// Source address.
///
private uint sourceAddress = 0;
///
/// Destination address.
///
private uint destinationAddress;
///
/// Current data list form instance.
///
private DataListForm dataListForm;
///
/// 'true' if 29 bit addressing on ISO15765.
///
private bool is29bit;
///
/// Current Volvo form instance.
///
private VolvoForm volvoForm;
///
/// Current SSM parser instance. (Subaru specific)
///
private SsmParser ssmParser;
///
/// Current Gauge Manager instance.
///
private GaugeManager gaugeManager;
///
/// Current PID parser instance.
///
private PidParser pidParser = null;
///
/// Current Mode parser instance.
///
private ModeParser modeParser = null;
///
/// Current Raw Log Stream.
///
private FileStream rawLogStream = null;
///
/// Current filter manager instance.
///
private FilterHandler filterHandler;
///
/// Gets a value indicating whether Checksum is active or not.
///
public bool checksum { get; private set; }
///
/// Gets Current communication speed.
///
public XmlClass.commspeed speed { get; private set; }
///
/// Gets a value indicating whether connection is open or not.
///
public bool isConnected { get; private set; }
///
/// Gets a value indicating whether a serial dongle is used.
///
public bool isSerial
{
get
{
return this.serialPortHandler != null;
}
}
///
/// The handler instance for the serial port.
///
private SerialPortHandler serialPortHandler;
///
/// Misc functions interface instance.
///
private IMiscFunc iMiscFunc;
///
/// OBD data node in tree.
///
private PanelTreeNode obdNode = null;
///
/// Freeze Frame data node in tree.
///
private PanelTreeNode ffNode = null;
///
/// DTC data node in tree.
///
private PanelTreeNode dtcNode = null;
///
/// DTC data node in tree.
///
private PanelTreeNode probeNode = null;
#if MODE_06
///
/// OBD Diagnostic mode.
///
private PanelTreeNode obdDiagTestNode = null;
#endif
///
/// ISO 14229 DTC data node in tree.
///
private PanelTreeNode dtcIso14229Node = null;
///
/// SSM data node in tree.
///
private PanelTreeNode ssmNode = null;
///
/// Data Source instance.
///
private IDataSource iDataSource;
///
/// Current data requester instance.
///
private DataRequester dataRequester;
///
/// Object to synchronize thread with.
///
private object quickStartSyncObject = new object();
///
/// Flag indicating success of quick init.
///
private bool quickInitSuccess = false;
///
/// Wrapper for current protocol and data.
///
private ProtocolItemWrapper currentProtocolItemWrapper;
///
/// Detected usable source address when probing for device.
///
private string detectedSrcAddress;
///
/// Address builder instance.
///
private AddressBuilder addressBuilder;
///
/// Hint activator instance.
///
private IHintActivator hintActivator;
///
/// Gets or sets data file directory path.
///
private string dataFileDir { get; set; }
///
/// Buffer overrun counter.
///
private int oldOverruns = -1;
///
/// Current messaging engine instance.
///
private MessagingEngine messagingEngine;
///
/// Data request matcher instance.
///
private IRequestMatcher iRequestMatcher;
///
/// Current SSM panel instance.
///
private SsmDataPanel ssmDataPanel = null;
///
/// Initializes a new instance of the class.
///
public ConnectionPanel()
{
this.InitializeComponent();
}
///
/// Initializes a new instance of the class.
///
/// Logging interface.
/// Current vehicle.
/// Application Tree instance.
/// Misc functions interface instance.
/// Preferences interface.
/// Data Source interface.
/// Protocol panel callback interface.
/// Current device connection.
/// Current protocol.
/// Current dictionary of OBD codes.
/// Current serial port handler instance.
/// Detected source address.
/// Hint activator instance.
/// Data file directory path.
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "8", Justification = "Reviewed.")]
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "7", Justification = "Reviewed, intentional.")]
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.ReadabilityRules", "SA1118:ParameterMustNotSpanMultipleLines", Justification = "Reviewed.")]
public ConnectionPanel(
ILogging iLogging,
XmlClass.vehicle vehicle,
IApplicationTree applicationTree,
IMiscFunc iMiscFunc,
IPreferences iPreferences,
IDataSource iDataSource,
IProtocolCallback iProtocolCallback,
IPassThruConnection passThruConnection,
ProtocolItemWrapper currentProtocolItemWrapper,
SortedDictionary obdcodes,
SerialPortHandler serialPortHandler,
string detectedSrcAddress,
IHintActivator hintActivator,
string dataFileDir)
: base(iLogging, vehicle, applicationTree)
{
this.iMiscFunc = iMiscFunc;
this.iPreferences = iPreferences;
this.iDataSource = iDataSource;
this.iProtocolCallback = iProtocolCallback;
this.passThruConnection = passThruConnection;
this.currentProtocolItemWrapper = currentProtocolItemWrapper;
this.protocol = currentProtocolItemWrapper.protocol;
this.obdcodes = obdcodes;
this.serialPortHandler = serialPortHandler;
this.detectedSrcAddress = detectedSrcAddress;
this.hintActivator = hintActivator;
this.dataFileDir = dataFileDir;
this.iRequestMatcher = new RequestMatcher(iLogging);
this.checksum = this.vehicle.checksum;
this.is29bit = (this.currentProtocolItemWrapper != null
&& this.currentProtocolItemWrapper.addressData != null
&& this.currentProtocolItemWrapper.addressData.bits == 29);
this.filterHandler = null;
uint connFlags = (this.currentProtocolItemWrapper != null
&& this.currentProtocolItemWrapper.addressData != null) ? this.currentProtocolItemWrapper.addressData.connFlags : 0;
this.InitializeComponent();
this.probePidsButton.Visible = this.iPreferences.developerMode;
this.checksumCB.Checked = this.checksum;
this.loadSpeedComboBox();
this.configParams.init(iLogging, this.iPreferences, this.iDataSource, passThruConnection, this.protocol);
this.connectionFlags.init(passThruConnection, vehicle, connFlags);
this.ecus.init(vehicle);
this.messageFlags.init(passThruConnection, vehicle, this.is29bit);
this.setSourceAddressCB();
this.addressBuilder = new AddressBuilder(this.currentProtocolItemWrapper, this.vehicle, this.sourceAddress);
this.ecus.Enabled = true;
this.configParams.refreshActiveConfigParams(true);
this.setToolTips();
this.titleTextbox.Text = this.protocol.name;
this.updateAddressBitsList();
if (this.protocol.id == Protocols.CAN)
{
this.connectionTabControl.Controls.Remove(this.connectionEcusTab);
this.connectionTabControl.Controls.Remove(this.connectionParametersTab);
this.connectionTabControl.Controls.Remove(this.connectionProgressTab);
for (int i = 0; i < 64; i++)
{
this.channelNumberCB.Items.Add(i.ToString());
}
this.channelNumberCB.Text = "0";
}
else
{
this.connectionTabControl.Controls.Remove(this.rawCanTab);
if (this.serialPortHandler != null)
{
this.connectionTabControl.Controls.Remove(this.connectionEcusTab);
this.connectionTabControl.Controls.Remove(this.connectionFlagsTab);
this.connectionTabControl.Controls.Remove(this.connectionParametersTab);
}
else
{
this.connectionTabControl.Controls.Remove(this.connectionProgressTab);
}
}
this.populateDestAddressCb();
if (this.iPreferences.defaultTimeout >= this.timeoutUD.Minimum
&& this.iPreferences.defaultTimeout <= this.timeoutUD.Maximum)
{
this.timeoutUD.Value = this.iPreferences.defaultTimeout;
}
this.protocolNameTB.Text = string.Empty;
this.Anchor = ((System.Windows.Forms.AnchorStyles)(
System.Windows.Forms.AnchorStyles.Top
| System.Windows.Forms.AnchorStyles.Bottom
| System.Windows.Forms.AnchorStyles.Left));
this.connectBT.Focus();
this.toolTip1.SetToolTip(
this.overrunsTextBox,
"Attempts to queue a command to the vehicle that's already in queue.\r\n"
+ "This means that the request was discarded with no side effect.");
}
///
/// Provide information about detected protocol.
///
/// Name of protocol.
public void setProtocolInfo(string protocolName)
{
if (this.InvokeRequired)
{
try
{
this.Invoke(new setProtocolInfoFunc(this.setProtocolInfo), new object[] { protocolName });
}
catch (System.Reflection.TargetParameterCountException ex)
{
MessageBox.Show(
"Exception: " + ex.Message + "\r\n",
"Error",
MessageBoxButtons.OK,
MessageBoxIcon.Stop);
}
catch (System.ObjectDisposedException)
{
// Ignore.
}
}
else
{
this.protocolNameTB.Text = protocolName;
}
}
///
/// Close the panel.
///
public void close()
{
this.protocolNameTB.Text = string.Empty;
if (this.ssmNode != null)
{
this.owningNode.Nodes.Remove(this.ssmNode);
this.ssmNode = null;
}
if (this.dtcIso14229Node != null)
{
this.owningNode.Nodes.Remove(this.dtcIso14229Node);
this.dtcIso14229Node = null;
}
if (this.dtcNode != null)
{
this.owningNode.Nodes.Remove(this.dtcNode);
this.dtcNode = null;
}
if (this.probeNode != null)
{
this.owningNode.Nodes.Remove(this.probeNode);
this.probeNode = null;
}
if (this.ffNode != null)
{
this.owningNode.Nodes.Remove(this.ffNode);
this.ffNode = null;
}
if (this.obdNode != null)
{
if (this.obdNode.userControl is CurrentDataPanel)
{
CurrentDataPanel currentDataPanel = (CurrentDataPanel)this.obdNode.userControl;
currentDataPanel.close();
}
}
if (this.messageHandler != null)
{
this.messageHandler.stopThread();
}
if (this.rawLogStream != null)
{
try
{
this.rawLogStream.Close();
}
catch
{
}
}
this.disconnect();
this.iProtocolCallback.closeTab(this, this.protocol, this.owningNode);
}
///
/// Signal that initialization failed when starting connection.
///
public void initFail()
{
MessageBox.Show(
"Initialization failed handshake with device.",
"Failure.",
MessageBoxButtons.OK,
MessageBoxIcon.Error);
this.disconnect();
}
///
/// Loads the Speed combo box and sets default value.
///
public void loadSpeedComboBox()
{
this.speedCB.Items.Clear();
this.canSpeedCB.Items.Clear();
int defaultval = -1;
int n = 0;
foreach (XmlClass.commspeed speedItem in this.iDataSource.commspeeds)
{
bool validSpeed = false;
bool defaultSpeed = false;
switch (this.protocol.families[0])
{
case Protocols.SERIAL:
validSpeed = speedItem.validISO15765;
defaultSpeed = speedItem.defaultISO15765;
break;
case Protocols.VPW_PWM:
validSpeed = speedItem.validJ1850;
defaultSpeed = speedItem.defaultJ1850;
break;
case Protocols.KL_LINE:
validSpeed = speedItem.validISO9141;
defaultSpeed = speedItem.defaultISO9141;
break;
case Protocols.CANBUS:
validSpeed = speedItem.validISO15765;
defaultSpeed = speedItem.defaultISO15765;
break;
}
if (validSpeed)
{
this.speedCB.Items.Add(speedItem);
this.canSpeedCB.Items.Add(speedItem);
if (this.currentProtocolItemWrapper != null
&& this.currentProtocolItemWrapper.commspeed != null)
{
if (this.currentProtocolItemWrapper.commspeed.bps == speedItem.bps)
{
defaultval = n;
}
}
else
{
if (defaultSpeed)
{
this.speed = speedItem;
defaultval = n;
}
}
n++;
}
}
if (defaultval >= 0)
{
this.speedCB.SelectedIndex = defaultval;
this.canSpeedCB.SelectedIndex = defaultval;
}
}
///
/// Wait for initialization of device to finish.
///
/// 'true' if successful initialization.
public bool waitForInit()
{
this.iLogging.appendText("Waiting for initialization to finish.\r\n");
if (!this.quickInitSuccess)
{
lock (this.quickStartSyncObject)
{
if (!Monitor.Wait(this.quickStartSyncObject, 30000))
{
this.iLogging.appendText("quickStartSyncObject timeout.\r\n");
}
}
}
this.iLogging.appendText("Initialization finished, success=" + this.quickInitSuccess + ".\r\n");
return this.quickInitSuccess;
}
///
/// Enable the suitable buttons for the selected protocol.
///
public void enableButtons()
{
if (this.InvokeRequired)
{
try
{
this.Invoke(new enableButtonsFunc(this.enableButtons), new object[] { });
}
catch (System.Reflection.TargetParameterCountException ex)
{
MessageBox.Show(
"Exception: " + ex.Message + "\r\n",
"Error",
MessageBoxButtons.OK,
MessageBoxIcon.Stop);
}
catch (System.ObjectDisposedException)
{
// Ignore.
}
}
else
{
this.disconnectBT.Enabled = true;
this.owningNode.SelectedImageKey = "cog_green.png";
this.owningNode.ImageKey = "cog_green.png";
switch (this.protocol.id)
{
case Protocols.SERIAL_AT_ELM:
case Protocols.SERIAL_AT_AGV:
this.obdButton.Enabled = true;
this.probePidsButton.Enabled = true;
this.gaugesButton.Enabled = true;
this.rawCanButton.Enabled = false;
this.enableVolvoCANButton.Enabled = false;
break;
case Protocols.J1850VPW:
this.obdButton.Enabled = true;
this.probePidsButton.Enabled = true;
this.gaugesButton.Enabled = true;
this.rawCanButton.Enabled = false;
this.enableVolvoCANButton.Enabled = false;
break;
case Protocols.J1850PWM:
this.obdButton.Enabled = true;
this.probePidsButton.Enabled = true;
this.gaugesButton.Enabled = true;
this.rawCanButton.Enabled = false;
this.enableVolvoCANButton.Enabled = false;
break;
case Protocols.ISO9141:
this.obdButton.Enabled = true;
this.probePidsButton.Enabled = true;
this.gaugesButton.Enabled = true;
this.rawCanButton.Enabled = false;
this.enableVolvoCANButton.Enabled = this.hasCapability("VC1"); // true;
break;
case Protocols.ISO14230:
this.obdButton.Enabled = true;
this.probePidsButton.Enabled = true;
this.gaugesButton.Enabled = true;
this.rawCanButton.Enabled = false;
this.enableVolvoCANButton.Enabled = false;
break;
case Protocols.CAN:
this.obdButton.Enabled = false;
this.probePidsButton.Enabled = false;
this.gaugesButton.Enabled = false;
this.rawCanButton.Enabled = true;
this.enableVolvoCANButton.Enabled = false;
break;
case Protocols.ISO15765:
this.obdButton.Enabled = true;
this.probePidsButton.Enabled = true;
this.gaugesButton.Enabled = true;
this.rawCanButton.Enabled = false;
this.enableVolvoCANButton.Enabled = false;
break;
default:
this.obdButton.Enabled = false;
this.probePidsButton.Enabled = false;
this.gaugesButton.Enabled = false;
this.rawCanButton.Enabled = false;
this.enableVolvoCANButton.Enabled = false;
break;
}
lock (this.quickStartSyncObject)
{
this.quickInitSuccess = true;
Monitor.PulseAll(this.quickStartSyncObject);
}
this.isConnected = true;
this.hintActivator.showHints(this);
this.Focus();
this.Cursor = Cursors.Default;
}
}
///
/// Update the progress bar with the initialization progress.
///
/// Step processed.
/// Total steps.
public void updateProgress(int step, int total)
{
if (this.progressBar1.InvokeRequired)
{
try
{
this.Invoke(new updateProgressFunc(this.updateProgress), new object[] { step, total });
}
catch (System.Reflection.TargetParameterCountException ex)
{
MessageBox.Show(
"Exception: " + ex.Message + "\r\n",
"Error",
MessageBoxButtons.OK,
MessageBoxIcon.Stop);
}
catch (System.ObjectDisposedException)
{
// Ignore.
}
}
else
{
this.progressBar1.Value = (int)(100.0 * step / total);
}
}
///
/// Perform connection using the selected protocol.
///
/// 'true' on success.
public bool performConnect()
{
bool success = false;
if (this.InvokeRequired)
{
try
{
success = (bool)this.Invoke(new performConnectFunc(this.performConnect), new object[] { });
}
catch (ThreadAbortException)
{
throw;
}
catch (System.Reflection.TargetParameterCountException ex)
{
MessageBox.Show(
"Exception: " + ex.Message + "\r\n",
"Error",
MessageBoxButtons.OK,
MessageBoxIcon.Stop);
}
catch (System.ObjectDisposedException)
{
// Ignore.
}
}
else
{
try
{
this.Cursor = Cursors.WaitCursor;
this.connectBT.Enabled = false;
this.connectionFlags.Enabled = false;
this.checksumCB.Enabled = false;
this.addressBitsCB.Enabled = false;
this.speedCB.Enabled = false;
this.ecus.Enabled = false;
this.configParams.ReadOnly = true;
this.quickInitSuccess = false;
if (this.connect(this.speed.bps, this.connectionFlags.flags))
{
this.messagingEngine = new MessagingEngine(
this.iLogging,
this.iPreferences,
this.protocolHandler,
this.iRequestMatcher,
this.messageFlags.flags,
this.sourceAddress,
this.destinationAddress);
this.pidParser = new PidParser(this.iLogging, this.messagingEngine);
this.modeParser = new ModeParser(this.iLogging, this.iDataSource, this.protocolHandler, this.pidParser, this.messagingEngine, this.iRequestMatcher);
this.dataRequester = new DataRequester(this.iLogging, this.iPreferences, this.messagingEngine, this.modeParser, this.iDataSource, this.protocolHandler);
this.ssmParser = new SsmParser(this.iLogging, this.iDataSource);
this.modeParser.registerPanel(this.ssmParser);
XmlClass.vehicle.ecuData[] ecuArr = this.getActiveEcus();
if (this.filterHandler == null)
{
this.filterHandler = new FilterHandler(
this.iLogging,
this.passThruConnection,
this.protocolHandler,
ecuArr,
this.messageFlags.flags,
this.currentProtocolItemWrapper);
}
this.messagingEngine.startThread();
success = true;
}
else
{
this.Cursor = Cursors.Default;
}
}
catch (Exception ex)
{
this.Cursor = Cursors.Default;
MessageBox.Show(
ex.Message + "\r\n\r\n" + ex.StackTrace,
"Error",
MessageBoxButtons.OK,
MessageBoxIcon.Exclamation);
this.disconnect();
}
}
return success;
}
///
/// Start the OBD user interface.
///
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "Reviewed.")]
public void startObdUi()
{
if (this.InvokeRequired)
{
try
{
this.Invoke(new startObdUiFunc(this.startObdUi), new object[] { });
}
catch (ThreadAbortException)
{
throw;
}
catch (System.Reflection.TargetParameterCountException ex)
{
MessageBox.Show(
"Exception: " + ex.Message + "\r\n",
"Error",
MessageBoxButtons.OK,
MessageBoxIcon.Stop);
}
catch (System.ObjectDisposedException)
{
// Ignore.
}
}
else
{
if (this.obdNode == null)
{
CurrentDataPanel currentDataPanel = new CurrentDataPanel(
this.iLogging,
this.iPreferences,
this.applicationTree,
this.messagingEngine,
this.iDataSource,
this.vehicle,
this.dataRequester,
this.modeParser,
this.dataFileDir);
this.obdNode = new PanelTreeNode("Current Data", "car.png", "car.png", currentDataPanel);
currentDataPanel.setOwningNode(this.obdNode);
this.owningNode.Nodes.Add(this.obdNode);
this.modeParser.pidParser.addPidReceiver(currentDataPanel.obdDataPanel);
this.modeParser.pidParser.addDataPresentation(currentDataPanel);
this.ssmParser.addDataPresentation(currentDataPanel);
currentDataPanel.init();
}
if (this.ffNode == null)
{
FfDataPanel ffDataPanel = new FfDataPanel(
this.iLogging,
this.applicationTree,
this.messagingEngine,
this.iDataSource,
this.vehicle,
this.dataRequester,
this.dataFileDir);
this.ffNode = new PanelTreeNode("Freeze Frame", "car_yellow.png", "car_yellow.png", ffDataPanel);
ffDataPanel.setOwningNode(this.ffNode);
this.owningNode.Nodes.Add(this.ffNode);
this.modeParser.pidParser.addPidReceiver(ffDataPanel.obdDataPanel);
this.modeParser.pidParser.addDataPresentation(ffDataPanel);
ffDataPanel.init();
}
if (this.dtcNode == null)
{
ObdDtcPanel obdDtc = new ObdDtcPanel(this.iLogging, this.iPreferences, this.applicationTree, this.messagingEngine, this.protocol, this.obdcodes);
this.dtcNode = new PanelTreeNode("DTC", "car_red.png", "car_red.png", obdDtc);
obdDtc.setOwningNode(this.dtcNode);
this.owningNode.Nodes.Add(this.dtcNode);
this.modeParser.registerPanel(obdDtc);
}
#if MODE_06
if (this.obdDiagTestNode == null)
{
OnBoardDiagTestPanel onBoardDiagTestPanel = new OnBoardDiagTestPanel(
this.iLogging,
this.iPreferences,
this.applicationTree,
this,
this.iDataSource,
this.vehicle,
this.dataRequester,
this.modeParser,
this.dataFileDir);
this.obdDiagTestNode = new PanelTreeNode("Diag Test", "folder_wrench.png", "folder_wrench.png", onBoardDiagTestPanel);
onBoardDiagTestPanel.setOwningNode(this.obdDiagTestNode);
this.owningNode.Nodes.Add(this.obdDiagTestNode);
this.modeParser.registerPanel(onBoardDiagTestPanel);
// onBoardDiagTestPanel.init();
}
#endif
#if ISO14229
if (this.dtcIso14229Node == null)
{
ObdIso14229DtcPanel obdDtc = new ObdIso14229DtcPanel(this.iLogging, this.iPreferences, this.applicationTree, this, this.protocol, this.obdcodes);
this.dtcIso14229Node = new PanelTreeNode("ISO14229 DTC", "car_red.png", "car_red.png", obdDtc);
obdDtc.setOwningNode(this.dtcIso14229Node);
this.owningNode.Nodes.Add(this.dtcIso14229Node);
this.modeParser.registerPanel(obdDtc);
}
#endif
bool hasSsm = false;
foreach (XmlClass.vehicle.capability cap in this.vehicle.capabilities)
{
if (cap.name == "SSM")
{
hasSsm = true;
break;
}
}
if (hasSsm && this.ssmDataPanel == null)
{
this.ssmDataPanel = new SsmDataPanel(
this.iLogging,
this.iDataSource,
this.messagingEngine,
this.vehicle,
this.applicationTree);
this.ssmParser.addSsmPanel(this.ssmDataPanel);
this.ssmNode = new PanelTreeNode("SSM", "SubaruIcon.png", "SubaruIcon.png", this.ssmDataPanel);
this.ssmDataPanel.setOwningNode(this.ssmNode);
this.owningNode.Nodes.Add(this.ssmNode);
}
this.owningNode.Expand();
this.applicationTree.selectNode(this.obdNode);
}
}
///
/// Update the send buffer overrun indicator.
/// This value will indicate when too much data is being sent to the vehicle.
/// Two remedies; Increase sample time or decrease number of parameters read.
/// Sporadic increments are not a problem.
///
private delegate void updateOverrunIndicatorFunc();
///
/// Update the send buffer overrun indicator.
/// This value will indicate when too much data is being sent to the vehicle.
/// Two remedies; Increase sample time or decrease number of parameters read.
/// Sporadic increments are not a problem.
///
private void updateOverrunIndicator()
{
if (this.messagingEngine != null)
{
if (this.messagingEngine.overruns != this.oldOverruns)
{
if (this.InvokeRequired)
{
try
{
this.Invoke(new updateOverrunIndicatorFunc(this.updateOverrunIndicator), new object[] { });
}
catch (System.Reflection.TargetParameterCountException ex)
{
MessageBox.Show(
"Exception: " + ex.Message + "\r\n",
"Error",
MessageBoxButtons.OK,
MessageBoxIcon.Stop);
}
catch (System.ObjectDisposedException)
{
// Ignore.
}
this.oldOverruns = this.messagingEngine.overruns;
}
else
{
this.overrunsTextBox.Text = this.messagingEngine.overruns.ToString();
}
}
}
}
///
/// Provide information about detected protocol.
///
/// Name of protocol.
private delegate void setProtocolInfoFunc(string protocolName);
///
/// Update the progress bar with the initialization progress.
///
/// Step processed.
/// Total steps.
private delegate void updateProgressFunc(int step, int total);
///
/// Connect button clicked.
///
/// Sending object.
/// Event data.
private void connectBT_Click(object sender, EventArgs e)
{
this.performConnect();
}
///
/// Perform connection using the selected protocol.
///
/// 'true' on success.
private delegate bool performConnectFunc();
///
/// Start the OBD user interface.
///
private delegate void startObdUiFunc();
///
/// Enable the suitable buttons for the selected protocol.
///
private delegate void enableButtonsFunc();
///
/// Check if vehicle has the given capability.
///
/// Example of capability is 'SSM' which is specific for Subaru.
///
///
/// Capability to test for.
/// 'true' if found.
private bool hasCapability(string capability)
{
bool found = false;
foreach (XmlClass.vehicle.capability cap in this.vehicle.capabilities)
{
if (cap.name.Equals(capability))
{
found = true;
break;
}
}
return found;
}
///
/// Connect to the vehicle.
///
/// Connection Speed.
/// Connection Flags.
/// 'true' the connection was successful.
private bool connect(uint speed, uint connFlags)
{
bool success = false;
this.iLogging.appendText("Speed=" + (speed / 1000) + " kbps\r\n");
string hex = string.Format("{0,8:X}", connFlags);
this.iLogging.appendText("Connect Flags: 0x" + hex + "\r\n");
this.iLogging.appendText("Connect with PassThruConnect(" + this.protocol.id + ", 0x" + hex + ", " + speed + ").\r\n", LogLevel.LOG_DEBUG);
PassThruConstants.resultCode status;
status = this.passThruConnection.Gl_PassThruConnect((int)this.protocol.id, connFlags, speed);
string errtext;
if (!this.iLogging.errTestConnection(this.passThruConnection, status, out errtext))
{
this.iLogging.appendText("Connect res=" + status + ", errtxt=" + errtext + "\r\n");
MessageBox.Show(
"Connect Failed!\r\n" + errtext,
"Error",
MessageBoxButtons.OK,
MessageBoxIcon.Stop);
}
else
{
this.iLogging.appendText("Connect OK!\r\n");
// Apply the configuration parameters.
if (this.protocol.id != Protocols.CAN)
{
this.configParams.applyConfigParameters();
}
this.configParams.refreshActiveConfigParams(false);
this.ecus.Enabled = false;
decimal d = this.timeoutUD.Value;
int timeout = (int)d;
this.messageHandler = new MessageHandler(this.iLogging, timeout, this.passThruConnection, this.protocol);
Thread.Sleep(100);
switch (this.protocol.id)
{
case Protocols.SERIAL_AT_ELM:
this.protocolHandler = new Protocol_Serial_AT_ELM(
this.iLogging,
this.protocol,
this.messageHandler,
this.sourceAddress,
this.checksum,
this.serialPortHandler,
this);
break;
case Protocols.SERIAL_AT_AGV:
this.protocolHandler = new Protocol_Serial_AT_AGV(
this.iLogging,
this.protocol,
this.messageHandler,
this.sourceAddress,
this.checksum,
this.serialPortHandler,
this);
break;
case Protocols.J1850VPW:
case Protocols.J1850PWM:
this.protocolHandler = new Protocol_J1850(
this.iLogging,
this.protocol,
this.messageHandler,
this.sourceAddress,
this.checksum,
this);
break;
case Protocols.ISO9141:
case Protocols.ISO14230:
this.protocolHandler = new Protocol_ISO14230(
this.iLogging,
this.protocol,
this.messageHandler,
this.sourceAddress,
this.checksum,
this);
break;
case Protocols.CAN:
// No protocol handler since CAN is a raw data receiver only.
this.protocolHandler = null;
this.enableButtons();
break;
case Protocols.ISO15765:
this.protocolHandler = new Protocol_ISO15765(
this.iLogging,
this.protocol,
this.messageHandler,
this.sourceAddress,
this.checksum,
this.is29bit,
this);
break;
default:
this.protocolHandler = null;
break;
}
if (this.protocol.id > 0)
{
this.messageHandler.startThread();
}
if (this.protocolHandler != null)
{
this.protocolHandler.init(0x00);
}
this.iLogging.appendText("Initialization finished.\r\n");
success = true;
}
return success;
}
///
/// Update the address bits list alternatives.
///
private void updateAddressBitsList()
{
this.addressBitsCB.Items.Clear();
int i = 0;
if (this.protocol.addressDataList != null)
{
foreach (Protocols.AddressData alt in this.protocol.addressDataList)
{
try
{
this.addressBitsCB.Items.Add(alt.bits.ToString());
if (this.currentProtocolItemWrapper != null
&& this.currentProtocolItemWrapper.addressData != null)
{
this.addressBitsCB.Text = this.currentProtocolItemWrapper.addressData.bits.ToString();
}
else
{
if (i == 0 && !this.is29bit)
{
this.addressBitsCB.SelectedIndex = i;
}
if (i == 1 && this.is29bit)
{
this.addressBitsCB.SelectedIndex = i;
}
}
}
catch (Exception ex)
{
this.iLogging.appendText(ex.Message + "\r\n");
}
i++;
}
this.addressBitsChange(this.addressBitsCB);
this.addressBitsCB.Enabled = false;
}
}
///
/// Disconnect from the current connection.
///
private void disconnect()
{
this.isConnected = false;
if (this.messagingEngine != null)
{
this.messagingEngine.stopThread();
this.messagingEngine = null;
}
if (this.protocolHandler != null)
{
this.protocolHandler.stopProtocol();
}
if (this.modeParser != null)
{
this.modeParser.close();
}
this.owningNode.SelectedImageKey = "cog_edit.png";
this.owningNode.ImageKey = "cog_edit.png";
this.pidParser = null;
this.modeParser = null;
this.connectBT.Enabled = true;
this.disconnectBT.Enabled = false;
this.obdButton.Enabled = false;
this.probePidsButton.Enabled = false;
this.rawCanButton.Enabled = false;
this.enableVolvoCANButton.Enabled = false;
this.connectionFlags.Enabled = true;
this.sourceAddressCB.Enabled = true;
this.destinationAddressCB.Enabled = true;
this.checksumCB.Enabled = true;
this.addressBitsCB.Enabled = false; // this.addressBitsCB.Items.Count > 0;
this.speedCB.Enabled = true;
this.ecus.Enabled = true;
this.messageFlags.Enabled = true;
this.configParams.ReadOnly = false;
if (this.gaugeManager != null)
{
this.gaugeManager.Close();
this.gaugeManager = null;
}
if (this.dataListForm != null)
{
this.dataListForm.Close();
this.dataListForm = null;
}
if (this.passThruConnection != null)
{
this.iLogging.appendText("Disconnect with PassThruDisconnect().\r\n", LogLevel.LOG_DEBUG);
PassThruConstants.resultCode status = this.passThruConnection.Gl_PassThruDisconnect();
string errtext;
if (!this.iLogging.errTestConnection(this.passThruConnection, status, out errtext))
{
this.iLogging.appendText("Disconnect res=" + status + ", errtxt=" + errtext + "\r\n");
MessageBox.Show(
"Disconnect Failed!\r\n" + errtext,
"Error",
MessageBoxButtons.OK,
MessageBoxIcon.Stop);
}
else
{
this.iLogging.appendText("Disconnect OK!\r\n");
}
}
this.hintActivator.showHints(this);
this.Focus();
}
///
/// Set source address combobox value.
///
private void setSourceAddressCB()
{
if (!string.IsNullOrEmpty(this.detectedSrcAddress))
{
this.sourceAddress = Utils.hexParse(this.detectedSrcAddress);
this.sourceAddressCB.Text = this.detectedSrcAddress;
}
else
{
if (string.IsNullOrEmpty(this.vehicle.testeraddress))
{
this.sourceAddress = 0;
this.sourceAddressCB.Text = (string)this.sourceAddressCB.Items[0];
}
else
{
this.sourceAddress = Utils.hexParse(this.vehicle.testeraddress);
this.sourceAddressCB.Text = this.vehicle.testeraddress;
}
}
if (this.messagingEngine != null)
{
this.messagingEngine.sourceAddress = this.sourceAddress;
}
}
///
/// Source address changed by changing selection.
///
/// Sending object.
/// Event data.
private void sourceAddressCB_SelectedIndexChanged(object sender, EventArgs e)
{
this.updateSourceAddress(sender, e);
}
///
/// Source address changed by editing the Combo Box.
///
/// Sending object.
/// Event data.
private void sourceAddressCB_TextChanged(object sender, EventArgs e)
{
this.updateSourceAddress(sender, e);
}
///
/// Validate changed source address.
///
/// Sending object.
/// Event data.
private void sourceAddressCB_Validating(object sender, CancelEventArgs e)
{
this.updateSourceAddress(sender, e);
}
///
/// Handle updates to the source address.
///
/// Sending object.
/// Event data.
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1800:DoNotCastUnnecessarily", Justification = "Reviewed.")]
private void updateSourceAddress(object sender, EventArgs e)
{
ComboBox cb = (ComboBox)sender;
string txt = cb.Text;
if (txt.Trim().Length > 0 && !txt.StartsWith(" "))
{
try
{
this.sourceAddress = Utils.hexParse(txt);
if (this.messagingEngine != null)
{
this.messagingEngine.sourceAddress = this.sourceAddress;
}
this.addressBuilder = new AddressBuilder(this.currentProtocolItemWrapper, this.vehicle, this.sourceAddress);
this.addressBitsChange(this.addressBitsCB);
}
catch
{
if (e is CancelEventArgs)
{
MessageBox.Show(
"Invalid address given, format shall be 0xNN or empty.",
"Failure",
MessageBoxButtons.OK,
MessageBoxIcon.Hand);
CancelEventArgs ce = (CancelEventArgs)e;
ce.Cancel = true;
}
}
}
}
///
/// Destination address changed by changing selection.
///
/// Sending object.
/// Event data.
private void destinationAddressCB_SelectedIndexChanged(object sender, EventArgs e)
{
this.updateDestAddress(sender);
}
///
/// Update the destination address.
///
/// Sending object instance.
private void updateDestAddress(object sender)
{
ComboBox cb = (ComboBox)sender;
this.destinationAddress = 0;
try
{
this.destinationAddress = Utils.hexParse(cb.Text);
if (this.messagingEngine != null)
{
this.messagingEngine.destinationAddress = this.destinationAddress;
}
}
catch
{
}
}
///
/// Destination address changed by editing the Combo Box.
///
/// Sending object.
/// Event data.
private void destinationAddressCB_TextChanged(object sender, EventArgs e)
{
this.updateDestAddress(sender);
}
///
/// Validate changed destination address.
///
/// Sending object.
/// Event data.
private void destinationAddressCB_Validating(object sender, CancelEventArgs e)
{
ComboBox cb = (ComboBox)sender;
string txt = cb.Text;
if (txt.Trim().Length > 0 && !txt.StartsWith(" "))
{
try
{
this.destinationAddress = Utils.hexParse(txt);
if (this.messagingEngine != null)
{
this.messagingEngine.destinationAddress = this.destinationAddress;
}
}
catch
{
MessageBox.Show(
"Invalid address given, format shall be 0xNN or empty.",
"Failure",
MessageBoxButtons.OK,
MessageBoxIcon.Hand);
e.Cancel = true;
}
}
}
///
/// Checksum checkbox changed.
///
/// Sending object.
/// Event data.
private void checksumCB_CheckedChanged(object sender, EventArgs e)
{
CheckBox cb = (CheckBox)sender;
this.checksum = cb.Checked;
}
///
/// Speed changed.
///
/// Sending object.
/// Event data.
private void speedCB_SelectedIndexChanged(object sender, EventArgs e)
{
ComboBox cb = (ComboBox)sender;
int ix = cb.SelectedIndex;
this.speed = (XmlClass.commspeed)this.speedCB.Items[ix];
}
///
/// Disconnect button clicked.
///
/// Sending object.
/// Event data.
private void disconnectBT_Click(object sender, EventArgs e)
{
if (this.ssmNode != null)
{
this.owningNode.Nodes.Remove(this.ssmNode);
this.ssmNode = null;
}
if (this.dtcIso14229Node != null)
{
this.owningNode.Nodes.Remove(this.dtcIso14229Node);
this.dtcIso14229Node = null;
}
if (this.dtcNode != null)
{
this.owningNode.Nodes.Remove(this.dtcNode);
this.dtcNode = null;
}
if (this.probeNode != null)
{
this.owningNode.Nodes.Remove(this.probeNode);
this.probeNode = null;
}
if (this.ffNode != null)
{
this.owningNode.Nodes.Remove(this.ffNode);
this.ffNode = null;
}
if (this.obdNode != null)
{
if (this.obdNode.userControl is CurrentDataPanel)
{
CurrentDataPanel currentDataPanel = (CurrentDataPanel)this.obdNode.userControl;
currentDataPanel.close();
}
this.owningNode.Nodes.Remove(this.obdNode);
this.obdNode = null;
}
if (this.filterHandler != null)
{
this.filterHandler.removeAllFilters();
this.filterHandler = null;
}
this.messageHandler.stopThread();
this.ecus.Enabled = true;
this.configParams.refreshActiveConfigParams(true);
this.disconnect();
}
///
/// Raw CAN button clicked.
///
/// Sending object.
/// Event data.
private void rawCanButton_Click(object sender, EventArgs e)
{
if (this.dataListForm == null || !this.dataListForm.CanFocus)
{
this.dataListForm = new DataListForm(
this.iLogging,
this.iMiscFunc,
this.filterHandler,
this.messageHandler);
}
this.dataListForm.Show();
this.dataListForm.Focus();
}
///
/// Get active ECU:s
///
/// Array of active ECU:s
private XmlClass.vehicle.ecuData[] getActiveEcus()
{
XmlClass.vehicle.ecuData[] newEcuArr;
if (this.ecus.selectedEcus.Length > 0)
{
newEcuArr = this.ecus.selectedEcus;
}
else
{
newEcuArr = this.ecus.allEcus;
}
if (newEcuArr.Length == 0)
{
newEcuArr = this.addressBuilder.ecus.ToArray();
}
return newEcuArr;
}
///
/// Address bits combo box changed.
///
/// Sending object.
/// Event data.
private void addressBitsCB_SelectedIndexChanged(object sender, EventArgs e)
{
ComboBox cb = (ComboBox)sender;
if (cb.Focused)
{
this.addressBitsChange(cb);
}
}
///
/// Handle change of address bits.
///
/// Combo box for address bits.
private void addressBitsChange(ComboBox cb)
{
int bits = 0;
try
{
bits = Convert.ToInt32(cb.Text);
this.is29bit = (bits == 29);
foreach (Protocols.AddressData alt in this.protocol.addressDataList)
{
if (alt.bits == bits)
{
this.destinationAddressCB.Items.Clear();
this.populateDestAddressCb();
}
}
}
catch
{
}
this.is29bit = (bits == 29);
this.sourceAddressCB.Enabled = (bits != 11);
}
///
/// Close button clicked.
///
/// Sending object.
/// Event data.
private void closeTabButton_Click(object sender, EventArgs e)
{
if (MessageBox.Show(
"Do you want to close this panel?",
"Confirm",
MessageBoxButtons.OKCancel,
MessageBoxIcon.Question,
MessageBoxDefaultButton.Button2) == DialogResult.OK)
{
this.close();
}
}
///
/// Enable Volvo CAN button clicked.
///
/// Sending object.
/// Event data.
private void enableVolvoCAN_Click(object sender, EventArgs e)
{
if (this.volvoForm == null || !this.volvoForm.CanFocus)
{
this.volvoForm = new VolvoForm(
this.iLogging,
this.passThruConnection,
this.protocolHandler,
this.messageHandler,
this.messageFlags.flags);
}
this.volvoForm.Show();
this.volvoForm.Focus();
}
///
/// Gauges button clicked.
///
/// Sending object.
/// Event data.
private void gaugesButton_Click(object sender, EventArgs e)
{
if (this.filterHandler == null)
{
XmlClass.vehicle.ecuData[] ecuArr = this.getActiveEcus();
this.filterHandler = new FilterHandler(
this.iLogging,
this.passThruConnection,
this.protocolHandler,
ecuArr,
this.messageFlags.flags,
this.currentProtocolItemWrapper);
}
if (this.gaugeManager == null || !this.gaugeManager.CanFocus)
{
this.gaugeManager = new GaugeManager(
this.iLogging,
this.iDataSource,
this.messagingEngine,
this.modeParser,
this.ssmParser,
this.dataFileDir);
}
this.gaugeManager.Show();
this.gaugeManager.Focus();
}
///
/// Set tool tips for items.
///
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1806:DoNotIgnoreMethodResults", MessageId = "CanApp.CustomToolTip", Justification = "Reviewed, intentional.")]
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "Reviewed, intentional.")]
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.ReadabilityRules", "SA1118:ParameterMustNotSpanMultipleLines", Justification = "Reviewed.")]
private void setToolTips()
{
this.toolTip1.SetToolTip(
this.checksumCB,
"Calculate and add checksum on packets to be sent.\r\n"
+ "This is for data sent via serial protocols, for data via CAN this is ignored.");
}
///
/// Handle click on OBD button.
///
/// Sending object.
/// Event data.
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "Reviewed, intentional.")]
private void obdButton_Click(object sender, EventArgs e)
{
this.startObdUi();
}
///
/// Configure the destination address combo box.
///
private void populateDestAddressCb()
{
if (this.addressBuilder != null && this.addressBuilder.destinationAddresses != null)
{
this.destinationAddressCB.Items.AddRange(this.addressBuilder.destinationAddresses.ToArray());
}
if (this.addressBuilder != null && this.addressBuilder.defaultValue != null)
{
this.destinationAddressCB.Text = this.addressBuilder.defaultValue;
}
else
{
if (this.destinationAddressCB.Items.Count > 0 && this.destinationAddressCB.Items[0] is string)
{
this.destinationAddressCB.Text = (string)this.destinationAddressCB.Items[0];
}
}
}
///
/// Probing of PIDs.
///
/// Sending object.
/// Event data.
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "Reviewed.")]
private void button1_Click(object sender, EventArgs e)
{
ProbePidsPanel probePidsPanel = new ProbePidsPanel(
this.iLogging,
this.vehicle,
this.applicationTree,
this.messagingEngine,
this.iDataSource,
this.modeParser);
this.probeNode = new PanelTreeNode("Browse Pids", "eye.png", "eye.png", probePidsPanel);
probePidsPanel.setOwningNode(this.probeNode);
this.owningNode.Nodes.Add(this.probeNode);
this.probeNode.Expand();
this.applicationTree.selectNode(this.probeNode);
this.modeParser.registerPanel(probePidsPanel);
}
///
/// Refresh the overrun indicator.
///
/// Sending object.
/// Event data.
private void timer1_Tick(object sender, EventArgs e)
{
this.updateOverrunIndicator();
}
}
}