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