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