//----------------------------------------------------------------------- // // 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 UserInterface.GUI { using System; using System.Collections.Generic; using System.Drawing; using System.Linq; using System.Windows.Forms; using global::SharedObjects; using global::SharedObjects.Api; using global::SharedObjects.DataMgmt; using global::SharedObjects.Misc; using global::SharedObjects.Protocol; /// /// Configuration parameters control /// public partial class ConfigParams : UserControl { /// /// Gets or sets a value indicating whether the readonly flag is set or not. /// public bool ReadOnly { get { return this.configDgv.ReadOnly; } set { this.configDgv.ReadOnly = value; } } /// /// Logging interface. /// private ILogging iLogging; /// /// Current device connection. /// private IPassThruConnection passThruConnection; /// /// Current protocol. /// private Protocols protocol; /// /// Style for a disabled cell. /// private DataGridViewCellStyle disabledCellStyle; /// /// Style for a normal enabled cell. /// private DataGridViewCellStyle normalCellStyle; /// /// Data source interface instance. /// private IDataSource iDataSource; /// /// Current preferences instance. /// private IPreferences iPreferences; /// /// Initializes a new instance of the class. /// public ConfigParams() { this.iPreferences = null; this.InitializeComponent(); } /// /// Initialize the table. /// /// Logging interface. /// Preferences instance. /// Data source interface instance. /// Current device connection. /// Current protocol. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1500:VariableNamesShouldNotMatchFieldNames", MessageId = "iPreferences", Justification = "Reviewed, intentional.")] [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1500:VariableNamesShouldNotMatchFieldNames", MessageId = "passThruConnection", Justification = "Reviewed, intentional.")] [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1500:VariableNamesShouldNotMatchFieldNames", MessageId = "iLogging", Justification = "Reviewed, intentional.")] [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1500:VariableNamesShouldNotMatchFieldNames", MessageId = "protocol", Justification = "Reviewed, intentional.")] [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1500:VariableNamesShouldNotMatchFieldNames", MessageId = "iDataSource", Justification = "Reviewed, intentional.")] public void init(ILogging iLogging, IPreferences iPreferences, IDataSource iDataSource, IPassThruConnection passThruConnection, Protocols protocol) { this.iLogging = iLogging; this.iPreferences = iPreferences; this.iDataSource = iDataSource; this.passThruConnection = passThruConnection; this.protocol = protocol; this.refreshConfigParams(); this.setToolTips(); this.normalCellStyle = this.configDgv.RowsDefaultCellStyle.Clone(); this.disabledCellStyle = this.configDgv.RowsDefaultCellStyle.Clone(); this.normalCellStyle.BackColor = Color.White; this.disabledCellStyle.BackColor = Color.LightGray; this.configDgv.RowsDefaultCellStyle = this.disabledCellStyle; this.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); } /// /// Refresh the active config parameters. /// /// 'true' If it shall be possible to edit the parameter values. public void refreshActiveConfigParams(bool editable) { DataGridViewRowCollection configRows = this.configDgv.Rows; foreach (XmlClass.parameteritem item in this.iDataSource.parameters) { foreach (DataGridViewRow configRow in configRows) { DataGridViewCellCollection configRowCells = configRow.Cells; if (configRowCells["configParam"].Value.Equals(item.name)) { if (item.protocols == null || item.protocols.Length == 0) { this.setCellStyle(editable, configRow); configRow.ReadOnly = !editable; configRow.Visible = true; configRowCells["currentValue"].Value = this.getParamValue(item); } else { configRow.Visible = false; foreach (int protocolId in item.protocols) { if (this.protocol.id == protocolId) { this.setCellStyle(editable, configRow); configRow.ReadOnly = !editable; configRow.Visible = true; configRowCells["currentValue"].Value = this.getParamValue(item); break; } } } } } } } /// /// Apply config parameters. /// public void applyConfigParameters() { DataGridViewRowCollection rows = this.configDgv.Rows; for (int i = 0; i < this.configDgv.Rows.Count; i++) { DataGridViewRow row = rows[i]; if (row.Visible) { DataGridViewCellCollection rowCells = row.Cells; string configParamValue = (string)rowCells["configParam"].Value; foreach (XmlClass.parameteritem item in this.iDataSource.parameters) { if (item.name.Equals(configParamValue)) { string val = (string)rowCells["configValue"].Value; if (val != null && val.Length > 0) { int parsedval = parseValue(val); this.iLogging.appendText("IoctlSetParameter(" + item.id + ", 0x" + parsedval.ToString("x2") + ").\r\n", LogLevel.LOG_DEBUG); PassThruConstants.resultCode status = this.passThruConnection.IoctlSetParameter((uint)item.id, (uint)parsedval); string errTxt = string.Empty; bool cont = this.iLogging.errTestConnection(this.passThruConnection, status, out errTxt); this.iLogging.appendText("IoctlSetParameter() status=" + status + ": " + errTxt + ", cont=" + cont + ".\r\n", LogLevel.LOG_DEBUG); if (!cont) { MessageBox.Show( "IoctlSetParameter(" + item.id + ", 0x" + parsedval.ToString("x2") + ")\r\n" + errTxt, "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); throw new Exception("Can't connect."); } } break; } } } } } /// /// Parse a string value to 'int', return -1 on failure. /// /// Value to parse /// Parsed value private static int parseValue(string val) { int parsedval = -1; // Negative means failure later on. try { parsedval = Convert.ToInt32(val); } catch { try { parsedval = (int)Utils.hexParse(val); } catch { } } return parsedval; } /// /// 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.configDgv, "Additional configuration parameters to be used when connecting\r\n" + "Empty field means that the parameter will be ignored.\r\n" + "\r\n" + "Some useful parameters:\r\n" + "DATA_RATE: 5 to 1000000\r\n" + "LOOPBACK: 0(Off) or 1(On)\r\n" + "NODE_ADDRESS: 0x00 to 0xFF for protocol J1850PWM\r\n" + "NETWORK_LINE: 0(Bus Normal) 1(Bus Plus) 2(Bus Minus)\r\n" + "PARITY: 0(No Parity) 1(Odd Parity) 2(Even Parity)\r\n" + "DATA_BITS: 0(8 bits) 1(7 bits)\r\n" + "\r\n" + "For full description of values see SAE J2534"); } /// /// Set the style of a cell. /// /// 'true' if editable. /// Current data grid view row. private void setCellStyle(bool editable, DataGridViewRow configRow) { foreach (DataGridViewCell cell in configRow.Cells) { if (editable) { cell.Style = this.normalCellStyle; } else { cell.Style = this.disabledCellStyle; } } } /// /// Get current parameter value. /// /// Parameter item. /// Parameter value. private string getParamValue(XmlClass.parameteritem item) { uint value = 0; string valueStr = string.Empty; if (item != null && this.passThruConnection != null) { if (this.passThruConnection.IoctlGetParameter(item.id, out value) == 0) { valueStr = value.ToString(); } } return valueStr; } /// /// Refresh config parameters. /// private void refreshConfigParams() { DataGridViewRowCollection rows = this.configDgv.Rows; List existing = new List(); int removed = 0; int added = 0; int updated = 0; for (int i = (rows.Count - 1); i >= 0; i--) { DataGridViewRow vehicleRow = rows[i]; DataGridViewCellCollection rowCells = vehicleRow.Cells; XmlClass.parameteritem item = (XmlClass.parameteritem)rowCells["configItem"].Value; if (!this.iDataSource.parameters.Contains(item)) { rows.RemoveAt(i); removed++; } else { existing.Add(item); rowCells["configParam"].Value = item.name; rowCells["currentValue"].Value = this.getParamValue(item); updated++; } } foreach (XmlClass.parameteritem item in this.iDataSource.parameters) { if (!existing.Contains(item)) { string valueStr = this.getParamValue(item); int n0 = rows.Add(1); DataGridViewRow vehicleRow = rows[n0]; DataGridViewCellCollection rowCells = vehicleRow.Cells; rowCells["configItem"].Value = item; rowCells["configParam"].Value = item.name; // currentValue rowCells["currentValue"].Value = valueStr; if (this.iPreferences != null) { switch (item.name) { case "ISO15765_BS": rowCells["configValue"].Value = this.iPreferences.blockSize.ToString(); break; case "ISO15765_STMIN": rowCells["configValue"].Value = this.iPreferences.frameSpacing.ToString(); break; default: rowCells["configValue"].Value = string.Empty; break; } } else { rowCells["configValue"].Value = string.Empty; } added++; } } } /// /// Validate cell values. /// /// Sending object. /// Event data. private void configDgv_CellValidating(object sender, DataGridViewCellValidatingEventArgs e) { DataGridView dataGridView = (DataGridView)sender; if (dataGridView.Visible) { int ix = e.RowIndex; int ic = e.ColumnIndex; DataGridViewTextBoxCell cell = dataGridView[ic, ix] as DataGridViewTextBoxCell; if (cell != null) { if (ic == 2) { string val = e.FormattedValue.ToString(); if (val.Length > 0) { int parsedval = parseValue(val); if (parsedval >= 0) { DataGridViewRowCollection rows = dataGridView.Rows; DataGridViewRow row = rows[ix]; DataGridViewCellCollection rowCells = row.Cells; string configParamValue = (string)rowCells["configParam"].Value; foreach (XmlClass.parameteritem item in this.iDataSource.parameters) { if (item.name.Equals(configParamValue)) { if (parsedval < item.min) { MessageBox.Show( "'" + val + "' is less than permitted minimum of " + item.min, "Warning", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); e.Cancel = true; } else { if (parsedval > item.max) { MessageBox.Show( "'" + val + "' is greater than permitted maximum of " + item.max, "Warning", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); e.Cancel = true; } } break; } } } else { MessageBox.Show( "'" + val + "' is invalid - cell must be a decimal (NNNN) or hex (0xNNNN) value or be empty.", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); e.Cancel = true; } } } } } } } }