//----------------------------------------------------------------------- // // 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.OBD { using System; using System.Drawing; using System.Globalization; using System.IO; using System.Threading; using System.Windows.Forms; using global::SharedObjects; using global::SharedObjects.DataMgmt; using global::SharedObjects.GUI; using global::SharedObjects.GUI.SSM; using global::SharedObjects.Misc; using global::SharedObjects.Misc.Objects; using global::SharedObjects.Protocol; /// /// Panel for SSM specific data. /// /// This is specific for Subaru. /// /// public partial class SsmDataPanel : AbstractUserControl, ISsmPanel { /// /// Data source interface instance. /// private IDataSource iDataSource; /// /// Messaging interface instance. /// private IMessaging iMessaging; /// /// Data grid view columns instance. /// private DataGridViewColumnCollection cols; /// /// Initializes a new instance of the class. /// /// Current event logging instance. /// Data source interface instance. /// Messaging interface instance. /// Current vehicle instance. /// Application Tree instance. public SsmDataPanel( ILogging iLogging, IDataSource iDataSource, IMessaging iMessaging, XmlClass.vehicle vehicle, IApplicationTree applicationTree) : base(iLogging, vehicle, applicationTree) { this.iDataSource = iDataSource; this.iMessaging = iMessaging; this.InitializeComponent(); this.cols = this.initRespDgv.Columns; 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))); } /// /// Handle the SSM init response data and present it in the table. /// /// Source ECU address. /// SSM-Id from vehicle. /// ROM-Id from vehicle. /// Capability byte array. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1720:IdentifiersShouldNotContainTypeNames", MessageId = "bytes", Justification = "Reviewed, intentional.")] public void handleSsmInitResponse(uint srcAddress, uint ssmid, string romid, byte[] capBytes) { if (this.initRespDgv.InvokeRequired) { try { this.Invoke(new handleSsmInitResponseFunc(this.handleSsmInitResponse), new object[] { srcAddress, ssmid, romid, capBytes }); } 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 { DataGridViewRowCollection dgvrc = this.initRespDgv.Rows; addRow(dgvrc, srcAddress, "SSM-Id", string.Empty, "0x" + ssmid.ToString("x6")); addRow(dgvrc, srcAddress, "Rom-Id", string.Empty, romid); if (capBytes != null) { addRow(dgvrc, srcAddress, "Number of Capability Bytes", string.Empty, capBytes.Length.ToString()); for (int i = 0; i < capBytes.Length; i++) { int data = (int)(capBytes[i] & 0xff); for (int j = 0; j < 8; j++) { string capability = Utils.getCapability(i, j); string status = (((data >> j) & 0x01) != 0).ToString(); addRow(dgvrc, srcAddress, "Capability [" + i + ":" + j + "] " + capability, "bit", status); } } } } } /// /// Add one row to the SSM data table. /// /// Table to add data to. /// Source address for data. /// Header text. /// Unit description. /// Data value string. private static void addRow(DataGridViewRowCollection dgvrc, uint srcAddress, string header, string unit, string value) { int n1 = dgvrc.Add(1); DataGridViewRow dgvr = dgvrc[n1]; DataGridViewCellCollection dgvcc = dgvr.Cells; dgvcc["ecuAddress"].Value = "0x" + srcAddress.ToString("x2"); dgvcc["valueName"].Value = header; dgvcc["valueUnit"].Value = unit; dgvcc["valueValue"].Value = value; } /// /// Handle the SSM init response data and present it in the table. /// /// Source ECU address. /// SSM-Id from vehicle. /// ROM-Id from vehicle. /// Capability byte array. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1720:IdentifiersShouldNotContainTypeNames", MessageId = "bytes", Justification = "Reviewed, intentional.")] private delegate void handleSsmInitResponseFunc(uint srcAddress, uint ssmid, string romid, byte[] capBytes); /// /// Handle click on SSM init button. /// /// Sending object. /// Event data. private void ssmInitButton_Click(object sender, EventArgs e) { XmlClass.pidgroup pidgroup = null; foreach (XmlClass.pidgroup pidgroupItem in this.iDataSource.pidgroups) { if (pidgroupItem.mode_int == 0xaa) { pidgroup = pidgroupItem; break; } } if (pidgroup != null) { if (pidgroup.pids.Count > 0) { IRequestData rd = new RequestData(null, (byte)TxMsg.SSM_INIT[0], pidgroup.pids[0], new TxMsg(TxMsg.SSM_INIT)); this.iMessaging.queueMsg(rd); this.iMessaging.sendMsg(); } else { MessageBox.Show( "Pid Group [" + pidgroup.id + "] - '" + pidgroup.name + "' does not declare any PID.\r\nAt least one placeholder PID needed.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } } else { MessageBox.Show( "No PID group defined for mode 0xaa", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } } /// /// Handle event where the data grid view changed size. /// /// Sending object. /// Event data. private void initRespDgv_SizeChanged(object sender, EventArgs e) { if (this.initRespDgv != null && this.cols != null) { Size sz = this.initRespDgv.Size; if (sz != null) { int width = sz.Width; width -= 100; // Units column, scrollbar etc. int width1 = width / 2; int width2 = width - width1; // To cover for rounding error. width1 = width1 < 100 ? 100 : width1; width2 = width2 < 100 ? 100 : width2; this.cols["valueName"].Width = width1; this.cols["valueValue"].Width = width2; } } } /// /// Handle click on Save button. /// /// Sending object. /// Event data. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2202:Do not dispose objects multiple times", Justification = "Reviewed.")] private void saveButton_Click(object sender, EventArgs e) { this.saveFileDialog1.FileName = string.Empty; this.saveFileDialog1.DefaultExt = ".csv"; this.saveFileDialog1.AddExtension = true; this.saveFileDialog1.ValidateNames = true; this.saveFileDialog1.Filter = "Excel CSV Format|*.csv"; DialogResult res = this.saveFileDialog1.ShowDialog(); if (res == DialogResult.OK) { Stream fileStream = null; StreamWriter streamWriter = null; try { fileStream = (System.IO.FileStream)this.saveFileDialog1.OpenFile(); streamWriter = new StreamWriter(fileStream, Utils.iso_8859_1); string csvSep = ";"; if (CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator == ".") { csvSep = ","; } DataGridViewRowCollection rows = this.initRespDgv.Rows; streamWriter.WriteLine("\"Name\"" + csvSep + "\"Unit\"" + csvSep + "\"Value\""); foreach (DataGridViewRow row in rows) { DataGridViewCellCollection cells = row.Cells; if (cells["valueName"].Value != null && cells["valueUnit"].Value != null && cells["valueValue"].Value != null) { streamWriter.Write("\""); streamWriter.Write(cells["valueName"].Value.ToString()); streamWriter.Write("\"" + csvSep + "\""); streamWriter.Write(cells["valueUnit"].Value.ToString()); streamWriter.Write("\"" + csvSep); string val = cells["valueValue"].Value.ToString(); try { Convert.ToDouble(val); // Test if numeric. streamWriter.Write(val); } catch { // Value isn't numeric, print as string. streamWriter.Write("\""); streamWriter.Write(val); streamWriter.Write("\""); } streamWriter.WriteLine(); } } } finally { if (streamWriter != null) { try { streamWriter.Close(); } catch { } } if (fileStream != null) { try { fileStream.Close(); } catch { } } } } } /// /// Handle click on Clear button. /// /// Sending object. /// Event data. private void clearButton_Click(object sender, EventArgs e) { DataGridViewRowCollection dgvrc = this.initRespDgv.Rows; dgvrc.Clear(); } } }