//-----------------------------------------------------------------------
//
// 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.ComponentModel;
using System.IO.Ports;
using System.Linq;
using System.Management;
using System.Windows.Forms;
using global::DataSource;
using global::DataSource.FileAccess;
using global::SharedObjects;
using global::SharedObjects.DataMgmt;
using global::SharedObjects.Misc;
using global::UserInterface.GUI.Popup;
///
/// Preferences panel declaration.
///
public partial class PreferencesPanel : UserControl, IPreferences
{
///
/// Refresh interval alternatives.
///
private static readonly string[] refreshIntervalArray =
{
"1:1",
"1:10",
"1:30",
"1:60",
"1:300",
};
///
/// Gets Refresh interval alternatives.
///
public IList refreshIntervals
{
get
{
return refreshIntervalArray.ToList();
}
}
///
/// Gets The currently selected unit category. (0=General, 1=Metric, 2=Imperial.)
///
/// Notice that "General" means that data will be presented in both metric and imperial.
///
///
public int selectedUnitCategory { get; private set; }
///
/// Gets default timeout value.
///
public int defaultTimeout { get; private set; }
///
/// Gets threshold for when a secondary Y axis shall be used in charts.
///
public int secondaryYThreshold { get; private set; }
///
/// Gets OBD code database URI string.
///
public string obdCodeDatabase { get; private set; }
///
/// Gets a value indicating whether hints shall be enabled (when false) or disabled (when true).
///
public bool advancedMode { get; private set; }
///
/// Gets a value indicating whether features useful for development shall be available.
///
/// Notice that some of the features may be dangerous.
///
///
public bool developerMode { get; private set; }
///
/// Gets Time in milliseconds to pause after sending a message.
///
public int sendDelay { get; private set; }
///
/// Gets Number of blocks accepted from peer before sending CTS.
///
public byte blockSize { get; private set; }
///
/// Gets Time in milliseconds to request that peer spaces it's frames with.
///
public byte frameSpacing { get; private set; }
///
/// Gets Name of GPS port.
///
public string gpsSerialPortName { get; private set; }
///
/// Preferences file access instance.
///
private PreferencesFileAccess preferencesFileAccess;
///
/// Data source interface instance.
///
private IDataSource iDataSource;
///
/// The beginners hint engine.
///
private HintEngine hintEngine;
///
/// Event logging instance.
///
private ILogging iLogging;
///
/// Gets preferences list instance.
///
public IDictionary preferences
{
get
{
return this.preferencesFileAccess.preferences;
}
}
///
/// Initializes a new instance of the class.
///
/// Current logging instance.
/// Data file directory path.
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "Reviewed.")]
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1806:DoNotIgnoreMethodResults", MessageId = "CanApp.CustomToolTip", Justification = "Reviewed.")]
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.ReadabilityRules", "SA1118:ParameterMustNotSpanMultipleLines", Justification = "Reviewed.")]
public PreferencesPanel(ILogging iLogging, string dataFileDir)
{
this.iLogging = iLogging;
this.selectedUnitCategory = 0;
this.advancedMode = false;
this.InitializeComponent();
this.preferencesFileAccess = new PreferencesFileAccess(iLogging, DataSourceImplementation.PREFERENCES_FILE, dataFileDir);
this.preferencesFileAccess.load();
this.loadPreferences();
this.initPreferredUnits();
this.gpsSerialPortName = this.getPreference(Utils.GPS_SERIAL_PORT);
this.iLogging.appendText("this.gpsSerialPortName='" + this.gpsSerialPortName + "'\r\n");
string[] portNames = SerialPort.GetPortNames();
List portInfo = new List();
using (ManagementObjectSearcher searcher = new ManagementObjectSearcher("root\\CIMV2", "SELECT * FROM Win32_PnPEntity WHERE ClassGuid = '{4d36e978-e325-11ce-bfc1-08002be10318}'"))
{
foreach (ManagementObject queryObj in searcher.Get())
{
portInfo.Add(queryObj["Caption"].ToString());
}
}
Array.Sort(portNames, new Utils.ComPortComparer());
int ix = 1;
int selIx = -1;
this.gpsSerialPortNameComboBox.Items.Clear();
this.gpsSerialPortNameComboBox.Items.Add(" Disabled ");
foreach (string portName in portNames)
{
string dispName = portName;
foreach (string caption in portInfo)
{
if (caption.Contains("(" + portName + ")"))
{
dispName = caption;
break;
}
}
this.gpsSerialPortNameComboBox.Items.Add(dispName);
if (this.gpsSerialPortName != null && this.gpsSerialPortName.Trim().Length > 0 && dispName.Contains("(" + this.gpsSerialPortName + ")"))
{
selIx = ix;
}
ix++;
}
if (selIx >= 0)
{
this.gpsSerialPortNameComboBox.SelectedIndex = selIx;
}
else
{
this.gpsSerialPortNameComboBox.SelectedIndex = 0;
}
this.toolTip1.SetToolTip(this.advancedModeCB, "Disables the application hint balloons.");
this.toolTip1.SetToolTip(
this.sendDelayNumericUpDown,
"Time to wait after sending one message to the ECU.\r\n"
+ "Some ECUs can't handle full speed data traffic from the test tool.");
}
///
/// Register the hint engine so it can be turned on or off.
///
/// Hint engine instance.
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1500:VariableNamesShouldNotMatchFieldNames", MessageId = "hintEngine", Justification = "Reviewed, intentional.")]
public void registerHintEngine(HintEngine hintEngine)
{
this.hintEngine = hintEngine;
}
///
/// Set the data source instance.
///
/// Data source interface instance.
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1500:VariableNamesShouldNotMatchFieldNames", MessageId = "iDataSource", Justification = "Reviewed, intentional.")]
public void setDataSource(IDataSource iDataSource)
{
this.iDataSource = iDataSource;
}
///
/// Get integer preference value.
///
/// Name of preference.
/// Integer value of preference, returns 0 at failure.
public int getIntPreference(string preferenceName)
{
string value = this.getPreference(preferenceName);
int intValue = 0;
try
{
intValue = Convert.ToInt32(value);
}
catch
{
}
return intValue;
}
///
/// Get Preference value by name.
///
/// Name of preference to get value for.
/// String preference value.
public string getPreference(string preferenceName)
{
string value = null;
if (this.preferencesFileAccess.preferences.ContainsKey(preferenceName))
{
XmlClass.preference pref = this.preferencesFileAccess.preferences[preferenceName];
value = pref.value;
}
return value;
}
///
/// Set Preference value.
///
/// Name of preference.
/// Preference value.
public void setPreference(string preferenceName, string value)
{
XmlClass.preference pref;
if (this.preferencesFileAccess.preferences.ContainsKey(preferenceName))
{
pref = this.preferencesFileAccess.preferences[preferenceName];
pref.value = value;
}
else
{
pref = new XmlClass.preference();
pref.name = preferenceName;
pref.value = value;
this.preferencesFileAccess.preferences.Add(preferenceName, pref);
}
this.preferencesFileAccess.save();
}
///
/// Load the preferences from file.
///
private void loadPreferences()
{
this.selectedUnitCategory = this.getIntPreference(PreferencesFileAccess.UNITS);
string site = this.getPreference(PreferencesFileAccess.OBDINFOSITE);
if (site == null || site.Trim().Length == 0)
{
site = Utils.DEFAULT_OBD_CODE_SITE;
}
this.obdCodeDatabaseURI.Text = site;
this.obdCodeDatabase = site;
this.defaultTimeout = this.getIntPreference(PreferencesFileAccess.DEFAULT_TIMEOUT);
if (this.defaultTimeout < this.timeoutUD.Minimum || this.defaultTimeout > this.timeoutUD.Maximum)
{
this.defaultTimeout = 1000;
this.setPreference(PreferencesFileAccess.DEFAULT_TIMEOUT, this.defaultTimeout.ToString());
}
if (this.defaultTimeout >= this.timeoutUD.Minimum && this.defaultTimeout <= this.timeoutUD.Maximum)
{
this.timeoutUD.Value = this.defaultTimeout;
}
this.secondaryYThreshold = this.getIntPreference(PreferencesFileAccess.SECONDARY_Y_THRESHOLD);
if (this.secondaryYThreshold >= this.secondaryYThresholdUD.Minimum && this.secondaryYThreshold <= this.secondaryYThresholdUD.Maximum)
{
this.secondaryYThresholdUD.Value = this.secondaryYThreshold;
}
int flag = this.getIntPreference(PreferencesFileAccess.ADVANCED_MODE);
this.advancedMode = flag != 0;
this.advancedModeCB.Checked = this.advancedMode;
if (this.hintEngine != null)
{
this.hintEngine.activate(!this.advancedMode);
}
this.sendDelay = this.getIntPreference(PreferencesFileAccess.SEND_DELAY);
// Error means that we probably are out of range.
try
{
this.sendDelayNumericUpDown.Value = this.sendDelay;
}
catch
{
// Default to 20ms.
this.sendDelayNumericUpDown.Value = 20;
}
this.blockSize = (byte)this.getIntPreference(PreferencesFileAccess.BLOCK_SIZE);
// Error means that we probably are out of range.
try
{
this.blockSizeNumericUpDown.Value = this.blockSize;
}
catch
{
// Default to 3 frames.
this.blockSizeNumericUpDown.Value = 3;
this.blockSize = 3;
}
this.frameSpacing = (byte)this.getIntPreference(PreferencesFileAccess.FRAME_SPACING);
// Error means that we probably are out of range.
try
{
this.frameSpacingNumericUpDown.Value = this.frameSpacing;
}
catch
{
// Default to 20 milliseconds.
this.frameSpacingNumericUpDown.Value = 20;
this.frameSpacing = 20;
}
}
///
/// Preferred units changed event.
///
/// Sending object.
/// Event data.
private void preferredUnits_SelectedIndexChanged(object sender, EventArgs e)
{
ComboBox cb = (ComboBox)sender;
this.selectedUnitCategory = cb.SelectedIndex;
this.setPreference(PreferencesFileAccess.UNITS, this.selectedUnitCategory.ToString());
if (this.iDataSource != null)
{
this.iDataSource.loadPidgroups();
}
}
///
/// Initialize the preferred units.
///
private void initPreferredUnits()
{
this.preferredUnits.Items.Clear();
foreach (string str in Utils.unitCategories)
{
this.preferredUnits.Items.Add(str);
}
if (this.selectedUnitCategory >= 0 && this.selectedUnitCategory < this.preferredUnits.Items.Count)
{
this.preferredUnits.SelectedIndex = this.selectedUnitCategory;
}
}
///
/// Timeout value has been changed by the user.
///
/// Sending object.
/// Event data.
private void timeoutUD_ValueChanged(object sender, EventArgs e)
{
this.defaultTimeout = (int)this.timeoutUD.Value;
this.setPreference(PreferencesFileAccess.DEFAULT_TIMEOUT, this.defaultTimeout.ToString());
}
///
/// Validate the URI.
///
/// Sending object.
/// Event data.
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1806:DoNotIgnoreMethodResults", MessageId = "System.Uri", Justification = "Reviewed, intentional.")]
private void obdCodeDatabaseURI_Validating(object sender, CancelEventArgs e)
{
string txt = this.obdCodeDatabaseURI.Text;
try
{
new Uri(txt);
}
catch (UriFormatException ex)
{
string errtxt = ex.Message + "\r\n";
errtxt += "Click OK to go back to old (default) value, Cancel to edit the current invalid value.";
if (MessageBox.Show(
errtxt,
"Error",
MessageBoxButtons.OKCancel,
MessageBoxIcon.Error,
MessageBoxDefaultButton.Button2) == DialogResult.Cancel)
{
e.Cancel = true;
}
else
{
this.obdCodeDatabaseURI.Text = this.obdCodeDatabase;
}
}
}
///
/// When URI has been validated.
///
/// Sending object.
/// Event data.
private void obdCodeDatabaseURI_Validated(object sender, EventArgs e)
{
this.obdCodeDatabase = this.obdCodeDatabaseURI.Text;
}
///
/// Test the URI.
///
/// Sending object.
/// Event data.
private void uriTestButton_Click(object sender, EventArgs e)
{
try
{
System.Diagnostics.Process.Start(this.obdCodeDatabase + "P0420");
}
catch (Win32Exception ex)
{
MessageBox.Show(
"'" + this.obdCodeDatabase + "'\r\n" + ex.Message,
"Error",
MessageBoxButtons.OK,
MessageBoxIcon.Error);
}
}
///
/// Changes of the Secondary Y axis threshold.
///
/// Sending object.
/// Event data.
private void secondaryYThresholdUD_ValueChanged(object sender, EventArgs e)
{
this.secondaryYThreshold = (int)this.secondaryYThresholdUD.Value;
this.setPreference(PreferencesFileAccess.SECONDARY_Y_THRESHOLD, this.secondaryYThreshold.ToString());
}
///
/// Handle checkbox toggle.
///
/// Sending object.
/// Event data.
private void advancedModeCB_CheckedChanged(object sender, EventArgs e)
{
this.advancedMode = this.advancedModeCB.Checked;
this.setPreference(PreferencesFileAccess.ADVANCED_MODE, this.advancedMode ? "1" : "0");
if (this.hintEngine != null)
{
this.hintEngine.activate(!this.advancedMode);
}
}
///
/// Handle change of GPS serial port name.
///
/// Sending object.
/// Event data.
private void gpsSerialPortNameComboBox_SelectedIndexChanged(object sender, EventArgs e)
{
string str = this.gpsSerialPortNameComboBox.Text;
string s2 = null;
if (str.StartsWith(" "))
{
s2 = string.Empty;
}
else
{
int ix = str.IndexOf("(COM");
if (ix >= 0)
{
s2 = str.Substring(ix + 1);
int ix2 = s2.IndexOf(')');
s2 = s2.Substring(0, ix2);
}
else
{
if (str.StartsWith("COM"))
{
s2 = str;
}
}
this.iLogging.appendText("Port='" + s2 + "'\r\n");
}
if (s2 != null)
{
this.gpsSerialPortName = s2;
this.setPreference(Utils.GPS_SERIAL_PORT, this.gpsSerialPortName);
}
}
///
/// Toggle developer mode.
///
/// Sending object.
/// Event data.
private void developerModeCB_CheckedChanged(object sender, EventArgs e)
{
this.developerMode = this.developerModeCB.Checked;
this.setPreference(PreferencesFileAccess.DEVELOPER_MODE, this.developerMode ? "1" : "0");
}
///
/// Handle change of send delay.
///
/// Sending object.
/// Event data.
private void sendDelayNumericUpDown_ValueChanged(object sender, EventArgs e)
{
NumericUpDown numericUpDown = (NumericUpDown)sender;
this.sendDelay = (int)numericUpDown.Value;
this.setPreference(PreferencesFileAccess.SEND_DELAY, this.sendDelay.ToString());
}
///
/// Handle change of block size.
///
/// Sending object.
/// Event data.
private void blockSizeNumericUpDown_ValueChanged(object sender, EventArgs e)
{
NumericUpDown numericUpDown = (NumericUpDown)sender;
this.blockSize = (byte)numericUpDown.Value;
this.setPreference(PreferencesFileAccess.BLOCK_SIZE, this.blockSize.ToString());
}
///
/// Handle change of frame spacing.
///
/// Sending object.
/// Event data.
private void frameSpacingNumericUpDown_ValueChanged(object sender, EventArgs e)
{
NumericUpDown numericUpDown = (NumericUpDown)sender;
this.frameSpacing = (byte)numericUpDown.Value;
this.setPreference(PreferencesFileAccess.FRAME_SPACING, this.frameSpacing.ToString());
}
}
}