//-----------------------------------------------------------------------
//
// 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 Gauges
{
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Globalization;
using System.Windows.Forms;
using global::SharedObjects.Misc;
///
/// Class for editing details for a gauge.
///
public partial class GaugeDetails : Form
{
///
/// Gets gauge item instance.
///
public XmlClass.gaugeitem gaugeitem { get; private set; }
///
/// Gets PID name.
///
public string pidName { get; private set; }
///
/// Gets PID name.
///
public string digitalPidName { get; private set; }
///
/// List of PID groups.
///
private IList pidgrouplist;
///
/// Current PID group.
///
private XmlClass.pidgroup pidgroup;
///
/// Current PID group.
///
private XmlClass.pidgroup digitalPidgroup;
///
/// Current PID.
///
private XmlClass.pidgroup.pidlist pid;
///
/// Current Digital PID.
///
private XmlClass.pidgroup.pidlist digitalPid;
///
/// Current sensor.
///
private XmlClass.pidgroup.pidlist.sensordata sensor;
///
/// Current sensor.
///
private XmlClass.pidgroup.pidlist.sensordata digitalSensor;
///
/// Number of major scale steps on gauge.
///
private uint majorScaleSteps;
///
/// Number of minor scale steps on gauge.
///
private uint minorScaleSteps;
///
/// What to divide the value with to get a reasonable presentation.
///
/// E.g. engine RPM makes sense to divide with 100.
///
///
private float divisor;
///
/// What to divide the value with to get a reasonable presentation.
///
/// E.g. engine RPM makes sense to divide with 100.
///
///
private float digitalDivisor;
///
/// Array of used gauges, used to avoid double-booking gauges.
///
private uint[] usedItems;
///
/// Fallback digital format.
///
private string defaultDigitalFormat = "000.00";
///
/// Initializes a new instance of the class.
///
/// PID group list.
/// Gauge item.
/// The number the gauge has.
/// Array of used gauges to avoid assigning the same gauge twice.
public GaugeDetails(IList pidgrouplist, XmlClass.gaugeitem gaugeitem, uint gaugeNumber, uint[] usedItems)
{
this.pidgrouplist = pidgrouplist;
this.gaugeitem = gaugeitem;
this.usedItems = usedItems;
if (this.gaugeitem == null)
{
this.gaugeitem = new XmlClass.gaugeitem();
}
this.InitializeComponent();
this.gaugeitem.gaugeNumber = gaugeNumber;
this.gaugeNumTB.Text = gaugeNumber.ToString();
this.pidGroupsCB.Items.Clear();
this.itemCB.Items.Clear();
this.sensorCB.Items.Clear();
this.digitalPidGroupsCB.Items.Clear();
this.digitalItemCB.Items.Clear();
this.digitalSensorCB.Items.Clear();
this.pidGroupsCB.SelectedIndex = -1;
this.digitalPidGroupsCB.SelectedIndex = -1;
int pidGrpIx = -1;
int digitalPidGrpIx = -1;
int i = 0;
this.digitalPidGroupsCB.Items.Add(" Disabled ");
foreach (XmlClass.pidgroup pidGrp in this.pidgrouplist)
{
this.pidGroupsCB.Items.Add(pidGrp.name);
this.digitalPidGroupsCB.Items.Add(pidGrp.name);
if (this.gaugeitem != null
&& this.gaugeitem.pidgroupid == pidGrp.id)
{
pidGrpIx = i;
}
if (this.gaugeitem != null
&& this.gaugeitem.digitalPidgroupid == pidGrp.id)
{
digitalPidGrpIx = i + 1;
}
i++;
}
if (this.pidGroupsCB.Items.Count > 0)
{
if (pidGrpIx >= 0 && pidGrpIx < this.pidGroupsCB.Items.Count)
{
this.pidGroupsCB.SelectedIndex = pidGrpIx;
}
else
{
this.pidGroupsCB.SelectedIndex = 0;
}
if (digitalPidGrpIx >= 0 && digitalPidGrpIx < this.digitalPidGroupsCB.Items.Count)
{
this.digitalPidGroupsCB.SelectedIndex = digitalPidGrpIx;
}
else
{
this.digitalPidGroupsCB.SelectedIndex = 0;
}
}
if (this.gaugeitem != null)
{
this.majorScaleSteps = this.gaugeitem.majorScaleSteps;
this.minorScaleSteps = this.gaugeitem.minorScaleSteps;
this.divisor = (this.gaugeitem.divisor == 0) ? 1.0F : this.gaugeitem.divisor;
this.digitalDivisor = (this.gaugeitem.digitalDivisor == 0) ? 1.0F : this.gaugeitem.digitalDivisor;
this.gaugeTextTB.Text = this.gaugeitem.gaugetext;
this.digitalGaugeTextTB.Text = this.gaugeitem.digitalGaugetext;
this.digitalFormat.Text = string.IsNullOrEmpty(this.gaugeitem.digitalFormat) ? "000.00" : this.gaugeitem.digitalFormat;
}
else
{
this.majorScaleSteps = 10;
this.minorScaleSteps = 3;
this.divisor = 1;
this.digitalDivisor = 1;
this.gaugeTextTB.Text = string.Empty;
this.digitalGaugeTextTB.Text = string.Empty;
this.digitalFormat.Text = "000.00";
}
this.defaultDigitalFormat = this.digitalFormat.Text;
this.divisorTextbox.Text = this.divisor.ToString();
this.digitalDivisorTextbox.Text = this.digitalDivisor.ToString();
this.majorScaleStepsTB.Text = this.majorScaleSteps.ToString();
this.minorScaleStepsTB.Text = this.minorScaleSteps.ToString();
}
///
/// Numeric validation of input data.
///
/// Sending object.
/// Event data.
/// Parsed numeric value.
private static uint numericIntValidation(object sender, CancelEventArgs e)
{
TextBox tb = (TextBox)sender;
uint scaleSteps = 0;
try
{
scaleSteps = Convert.ToUInt32(tb.Text);
}
catch
{
MessageBox.Show(
"Field must be numeric.",
"Data Failure",
MessageBoxButtons.OK,
MessageBoxIcon.Exclamation);
e.Cancel = true;
}
return scaleSteps;
}
///
/// Test for float value.
///
/// Sending object.
/// Event data.
/// Parsed float value.
private static float numericFloatValidation(object sender, CancelEventArgs e)
{
TextBox tb = (TextBox)sender;
float value = 0;
try
{
value = Convert.ToSingle(tb.Text);
}
catch
{
MessageBox.Show(
"Field must be numeric.",
"Data Failure",
MessageBoxButtons.OK,
MessageBoxIcon.Exclamation);
e.Cancel = true;
}
return value;
}
///
/// PidGroup combobox change.
///
/// Current PID group.
/// Combobox that changed.
/// List of valid PID groups.
/// Offset value in combo box index.
/// New PID group or 'null' if not applicable.
private static XmlClass.pidgroup pidGroupChange(
XmlClass.pidgroup pidgroup,
ComboBox cb,
IList pidgrouplist,
int offset)
{
if (cb.SelectedIndex >= offset && cb.SelectedIndex < cb.Items.Count)
{
pidgroup = pidgrouplist[cb.SelectedIndex - offset];
}
else
{
if (offset == 1)
{
pidgroup = null;
}
}
return pidgroup;
}
///
/// Update Item Combo Box.
///
/// Current PID group.
/// Items combobox
/// Gauge PID id
private static void updateItemCB(XmlClass.pidgroup pidgroup, ComboBox itemCB, uint gaugePid_int)
{
int pidIx = -1;
int i = 0;
foreach (XmlClass.pidgroup.pidlist pidItem in pidgroup.pids)
{
itemCB.Items.Add(pidItem.name);
if (gaugePid_int == pidItem.pid_int)
{
pidIx = i;
}
i++;
}
if (pidIx >= 0 && pidIx < itemCB.Items.Count)
{
itemCB.SelectedIndex = pidIx;
}
else
{
if (itemCB.Items.Count > 0)
{
itemCB.SelectedIndex = 0;
}
}
}
///
/// Update item combo box.
///
/// Combo box.
/// PID to get items for.
/// Sensor combo box instance.
/// Current list of PIDs
/// Current gauge item.
/// Name of selected PID.
private static string itemCbChange(
ComboBox cb,
ref XmlClass.pidgroup.pidlist pid,
ComboBox sensorCB,
List pids,
XmlClass.gaugeitem gaugeitem)
{
string pidName = string.Empty;
sensorCB.Items.Clear();
pid = pids[cb.SelectedIndex];
pidName = pid.name;
int sensorIx = -1;
int i = 0;
foreach (XmlClass.pidgroup.pidlist.sensordata sensorItem in pid.sensors)
{
string sensorInfo = string.Empty;
if (sensorItem.name != null)
{
sensorInfo += sensorItem.name + " ";
}
sensorInfo += "(" + sensorItem.unit + ")";
sensorCB.Items.Add(sensorInfo);
int sensorBit = -1;
if (sensorItem.unit == "bit" || sensorItem.unit == "bits")
{
try
{
sensorBit = Convert.ToInt32(sensorItem.startbit);
}
catch
{
}
}
if (gaugeitem != null
&& gaugeitem.sensor_unit != null
&& gaugeitem.sensor_unit.Equals(sensorItem.unit)
&& gaugeitem.sensor_offset == sensorItem.offset
&& (sensorBit == -1 || gaugeitem.sensor_startbit == sensorBit))
{
sensorIx = i;
}
i++;
}
if (sensorIx >= 0 && sensorIx < sensorCB.Items.Count)
{
sensorCB.SelectedIndex = sensorIx;
}
else
{
if (sensorCB.Items.Count > 0)
{
sensorCB.SelectedIndex = 0;
}
}
return pidName;
}
///
/// OK button clicked.
///
/// Sending object.
/// Event data.
private void okButton_Click(object sender, EventArgs e)
{
this.gaugeitem.pidgroupid = this.pidgroup.id;
this.gaugeitem.pid_int = this.pid.pid_int;
this.gaugeitem.sensor_unit = this.sensor.unit;
this.gaugeitem.sensor_offset = this.sensor.offset;
this.gaugeitem.majorScaleSteps = this.majorScaleSteps;
this.gaugeitem.minorScaleSteps = this.minorScaleSteps;
this.gaugeitem.gaugetext = this.gaugeTextTB.Text;
this.gaugeitem.divisor = this.divisor;
int sensorBit = -1;
try
{
sensorBit = Convert.ToInt32(this.sensor.startbit);
}
catch
{
}
this.gaugeitem.sensor_startbit = sensorBit;
if (this.digitalPidgroup != null)
{
this.gaugeitem.digitalPidgroupid = this.digitalPidgroup.id;
this.gaugeitem.digitalPid_int = this.digitalPid.pid_int;
this.gaugeitem.digitalSensor_unit = this.digitalSensor.unit;
this.gaugeitem.digitalSensor_offset = this.digitalSensor.offset;
this.gaugeitem.digitalGaugetext = this.digitalGaugeTextTB.Text;
this.gaugeitem.digitalDivisor = this.digitalDivisor;
this.gaugeitem.digitalFormat = this.digitalFormat.Text;
int digitalSensorBit = -1;
try
{
digitalSensorBit = Convert.ToInt32(this.digitalSensor.startbit);
}
catch
{
}
this.gaugeitem.digitalSensor_startbit = digitalSensorBit;
}
else
{
this.gaugeitem.digitalPidgroupid = 0;
this.gaugeitem.digitalPid_int = 0;
this.gaugeitem.digitalSensor_unit = string.Empty;
this.gaugeitem.digitalSensor_offset = 0;
this.gaugeitem.digitalGaugetext = string.Empty;
this.gaugeitem.digitalDivisor = 1;
this.gaugeitem.digitalFormat = "000.0";
this.gaugeitem.digitalSensor_startbit = -1;
}
this.DialogResult = DialogResult.OK;
this.Close();
}
///
/// Cancel button clicked.
///
/// Sending object.
/// Event data.
private void cancelButton_Click(object sender, EventArgs e)
{
this.DialogResult = DialogResult.Cancel;
this.Close();
}
///
/// Scale text box changed.
///
/// Sending object.
/// Event data.
private void scaleTextbox_Validating(object sender, CancelEventArgs e)
{
this.majorScaleSteps = numericIntValidation(sender, e);
}
///
/// PID group changed.
///
/// Sending object.
/// Event data.
private void pidGroupsCB_SelectedIndexChanged(object sender, EventArgs e)
{
this.pidgroup = pidGroupChange(
this.pidgroup,
(ComboBox)sender,
this.pidgrouplist,
0);
this.itemCB.Items.Clear();
this.sensorCB.Items.Clear();
this.pidName = string.Empty;
if (this.pidgroup != null)
{
updateItemCB(this.pidgroup, this.itemCB, this.gaugeitem.pid_int);
}
}
///
/// PID group changed.
///
/// Sending object.
/// Event data.
private void digitalPidGroupsCB_SelectedIndexChanged(object sender, EventArgs e)
{
this.digitalPidgroup = pidGroupChange(
this.digitalPidgroup,
(ComboBox)sender,
this.pidgrouplist,
1);
this.digitalItemCB.Items.Clear();
this.digitalSensorCB.Items.Clear();
this.digitalPidName = string.Empty;
if (this.digitalPidgroup != null)
{
updateItemCB(this.digitalPidgroup, this.digitalItemCB, this.gaugeitem.digitalPid_int);
}
}
///
/// Item combo box changed.
///
/// Sending object.
/// Event data.
private void itemCB_SelectedIndexChanged(object sender, EventArgs e)
{
ComboBox cb = (ComboBox)sender;
if (this.pidgroup != null && cb.SelectedIndex >= 0 && cb.SelectedIndex < cb.Items.Count)
{
this.pidName = itemCbChange(cb, ref this.pid, this.sensorCB, this.pidgroup.pids, this.gaugeitem);
}
}
///
/// Selection of item for digital gauge changed.
///
/// Sending object.
/// Event data.
private void digitalItemCB_SelectedIndexChanged(object sender, EventArgs e)
{
ComboBox cb = (ComboBox)sender;
if (this.digitalPidgroup != null && cb.SelectedIndex >= 0 && cb.SelectedIndex < cb.Items.Count)
{
this.digitalPidName = itemCbChange(cb, ref this.digitalPid, this.digitalSensorCB, this.digitalPidgroup.pids, this.gaugeitem);
}
}
///
/// Sensor combo box changed.
///
/// Sending object.
/// Event data.
private void sensorCB_SelectedIndexChanged(object sender, EventArgs e)
{
ComboBox cb = (ComboBox)sender;
if (cb.SelectedIndex >= 0 && cb.SelectedIndex < this.itemCB.Items.Count)
{
this.sensor = this.pid.sensors[cb.SelectedIndex];
}
}
///
/// Sensor combo box changed.
///
/// Sending object.
/// Event data.
private void digitalSensorCB_SelectedIndexChanged(object sender, EventArgs e)
{
ComboBox cb = (ComboBox)sender;
if (cb.SelectedIndex >= 0 && cb.SelectedIndex < this.itemCB.Items.Count)
{
this.digitalSensor = this.digitalPid.sensors[cb.SelectedIndex];
}
}
///
/// Divisor text box changed.
///
/// Sending object.
/// Event data.
private void divisorTextbox_Validating(object sender, CancelEventArgs e)
{
this.divisor = numericFloatValidation(sender, e);
}
///
/// Divisor text box changed.
///
/// Sending object.
/// Event data.
private void digitalDivisorTextbox_Validating(object sender, CancelEventArgs e)
{
this.digitalDivisor = numericFloatValidation(sender, e);
}
///
/// Minor scale steps changed.
///
/// Sending object.
/// Event data.
private void minorScaleStepsTB_Validating(object sender, CancelEventArgs e)
{
this.minorScaleSteps = numericIntValidation(sender, e);
}
///
/// Select gauge.
///
/// Sending object.
/// Event data.
private void button1_Click(object sender, EventArgs e)
{
GaugeSelector gs = new GaugeSelector(this.gaugeitem.gaugeNumber, this.usedItems);
try
{
if (gs.ShowDialog() == System.Windows.Forms.DialogResult.OK && gs.selectedItem != null)
{
this.gaugeitem.gaugeNumber = (uint)gs.selectedItem;
this.gaugeNumTB.Text = this.gaugeitem.gaugeNumber.ToString();
}
}
finally
{
gs.Dispose();
}
}
///
/// Validate format mask.
///
/// Sending object.
/// Event data.
private void digitalFormat_Validating(object sender, CancelEventArgs e)
{
TextBox tb = (TextBox)sender;
string mask = tb.Text;
tb.BackColor = Color.White;
try
{
string mask1 = mask.Replace("0", string.Empty);
mask1 = mask1.Replace(".", string.Empty);
if (mask1.Length > 0)
{
throw new Exception("Only '0' (zero) and '.' are permitted.");
}
string[] sa = mask.Split(new char[] { '.' });
if (sa.Length > 2)
{
throw new Exception("At most one '.' is permitted.");
}
// Finish with an attempt to apply the format mask to a value too.
float number = (float)Math.PI;
string num = number.ToString(mask, CultureInfo.InvariantCulture);
if (num.Length == 0)
{
throw new Exception("Formatting with mask '" + mask + "' produced an empty string.");
}
}
catch (Exception ex)
{
tb.BackColor = Color.LightPink;
if (MessageBox.Show("Invalid format mask '" + mask + "'\r\n" + ex.Message + "\r\n", "Error", MessageBoxButtons.OKCancel, MessageBoxIcon.Hand) == System.Windows.Forms.DialogResult.OK)
{
e.Cancel = true;
}
else
{
tb.BackColor = Color.White;
tb.Text = this.defaultDigitalFormat;
}
}
}
}
}