//----------------------------------------------------------------------- // // 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 SharedObjects.Misc { using System; using System.Collections.Generic; using System.Drawing; using System.Globalization; using System.IO; using System.Runtime.Serialization; using System.Runtime.Serialization.Formatters.Binary; using System.Windows.Forms; using global::SharedObjects.Api; /// /// Collection of static utility methods that are useful in many places. /// public static class Utils { /// /// Constant for Carriage Return and Line Feed. /// public const string CRLF = "\r\n"; /// /// Scale factor to convert ticks to milliseconds. /// public const long TICKS_PER_MILLISECOND = TimeSpan.TicksPerSecond / 1000; /// /// External site to get more OBD code info at. /// public const string DEFAULT_OBD_CODE_SITE = "http://www.obd-codes.com/"; /// /// Constant for Serial Port Property. /// public const string SERIAL_PORT = "SerialPort"; /// /// Constant for Serial Port Property. /// public const string GPS_SERIAL_PORT = "GpsSerialPort"; /// /// Constant for Serial Port Property. /// public const string SERIAL_SPEED = "SerialSpeed"; /// /// Constant for Serial Port Property. /// public const string SERIAL_DATABITS = "SerialDatabits"; /// /// Constant for Serial Port Property. /// public const string SERIAL_PARITY = "SerialParity"; /// /// Constant for Serial Port Property. /// public const string SERIAL_STOPBITS = "SerialStopbits"; /// /// No unit preference. /// public const string UNITS_GENERAL = "0 = General"; /// /// Prefer metric units. /// public const string UNITS_METRIC = "1 = Metric"; /// /// Prefer imperial units. /// public const string UNITS_IMPERIAL = "2 = Imperial"; /// /// Array of possible data directories. /// /// Three different locations where the files can be found. /// Seems to be necessary due to variations in operating systems. /// /// public static readonly string[] DEFAULT_DATA_FILE_DIR = { "%ALLUSERSPROFILE%\\Bedug.com\\CAN Data Miner\\AppData\\", "%ALLUSERSPROFILE%\\Application Data\\Bedug.com\\CAN Data Miner\\AppData\\", "%APPDATA%\\Bedug.com\\CAN Data Miner\\AppData\\", "%APPDATA%\\Application Data\\Bedug.com\\CAN Data Miner\\AppData\\", }; /// /// Encoding instance for some cases like CSV files. /// /// Normal encoding is UTF-8. /// /// [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2104:DoNotDeclareReadOnlyMutableReferenceTypes", Justification = "Reviewed, intentional.")] public static readonly System.Text.Encoding iso_8859_1 = System.Text.Encoding.GetEncoding("iso-8859-1"); /// /// Array of supported unit categories. /// /// Notice that "General" means that data will be presented in both metric and imperial. /// /// [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2105:ArrayFieldsShouldNotBeReadOnly", Justification = "Reviewed, intentional.")] public static readonly string[] unitCategories = { UNITS_GENERAL, UNITS_METRIC, UNITS_IMPERIAL, }; /// /// Array of valid OBD code groups. /// private static char[] dtcChar1 = { 'P', 'C', 'B', 'U' }; /// /// Clones the given object. /// /// Object type /// Source object. /// Cloned object. public static T Clone(T source) { if (!typeof(T).IsSerializable) { throw new ArgumentException("Type must be serializable", "source"); } if (object.ReferenceEquals(source, null)) { return default(T); } IFormatter iFormatter = new BinaryFormatter(); Stream stream = new MemoryStream(); using (stream) { iFormatter.Serialize(stream, source); stream.Seek(0, SeekOrigin.Begin); return (T)iFormatter.Deserialize(stream); } } /// /// Part of hash calculation. /// /// Hash to update. /// Hash to add. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1045:DoNotPassTypesByReference", MessageId = "0#", Justification = "Reviewed, intentional.")] [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly", MessageId = "reHash", Justification = "Reviewed, intentional.")] public static void reHash(ref int hash, int newHash) { long h1 = (long)hash << 1; long h2 = (long)hash >> 31; h1 = (h1 & 0xfffffffeL) | (h2 & 0x01L); h1 ^= newHash; hash = (int)h1; } /// /// Calculate the checksum of the provided byte array. /// /// This routine will stop the calculation either when 'count' /// items has been considered or when the end of the array /// is encountered. /// /// /// Byte array to process. /// Start position in byte array. /// Number of elements to calculate with. /// Calculated checksum, lowest 8 bit. public static int getChecksum(byte[] ba, int start, int count) { int cs = 0; if (ba != null) { for (int i = start; i < (start + count) && i < ba.Length; i++) { cs = (cs + ba[i]) & 0xff; } } return cs; } /// /// Comparing function for sorting. /// /// Item 1 /// Item 2 /// Result of compare. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "1", Justification = "Validation OK.")] [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Justification = "Validation OK.")] public static int modegroups_sorter(XmlClass.modeitem gr1, XmlClass.modeitem gr2) { if (gr1 == null && gr2 == null) { return 0; } if (gr1 == null && gr2 != null) { return -1; } if (gr1 != null && gr2 == null) { return 1; } if (gr1.mode_int < gr2.mode_int) { return -1; } if (gr1.mode_int > gr2.mode_int) { return 1; } int res = 0; if (gr1.name != null && gr2.name != null) { res = gr1.name.CompareTo(gr2.name); } return res; } /// /// Comparing function for sorting. /// /// Item 1 /// Item 2 /// Result of compare. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "1", Justification = "Validation OK.")] [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Justification = "Validation OK.")] public static int filter_sorter(XmlClass.filter gr1, XmlClass.filter gr2) { if (gr1 == null && gr2 == null) { return 0; } if (gr1 == null && gr2 != null) { return -1; } if (gr1 != null && gr2 == null) { return 1; } int res = 0; if (gr1.name != null && gr2.name != null) { res = gr1.name.CompareTo(gr2.name); } return res; } /// /// Comparing function for sorting. /// /// Item 1 /// Item 2 /// Result of compare. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "1", Justification = "Validation OK.")] [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Justification = "Validation OK.")] public static int icon_sorter(XmlClass.icon gr1, XmlClass.icon gr2) { if (gr1 == null && gr2 == null) { return 0; } if (gr1 == null && gr2 != null) { return -1; } if (gr1 != null && gr2 == null) { return 1; } int res = 0; if (gr1.key != null && gr2.key != null) { res = gr1.key.CompareTo(gr2.key); } return res; } /// /// Comparing function for sorting. /// /// Item 1 /// Item 2 /// Result of compare. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "1", Justification = "Validation OK.")] [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Justification = "Validation OK.")] public static int pidgroups_sorter(XmlClass.pidgroup gr1, XmlClass.pidgroup gr2) { if (gr1 == null && gr2 == null) { return 0; } if (gr1 == null && gr2 != null) { return -1; } if (gr1 != null && gr2 == null) { return 1; } uint b1 = 0; uint b2 = 0; try { b1 = Convert.ToUInt32(gr1.id); } catch { } try { b2 = Convert.ToUInt32(gr2.id); } catch { } if (b1 < b2) { return -1; } if (b1 > b2) { return 1; } int n1 = 0; if (gr1.name != null && gr2.name != null) { n1 = gr1.name.CompareTo(gr2.name); } return n1; } /// /// Comparing function for sorting. /// /// Item 1 /// Item 2 /// Result of compare. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "1", Justification = "Validation OK.")] [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Justification = "Validation OK.")] public static int pidgroups_sorter(XmlClass.vehicle.pidgroup gr1, XmlClass.vehicle.pidgroup gr2) { if (gr1 == null && gr2 == null) { return 0; } if (gr1 == null && gr2 != null) { return -1; } if (gr1 != null && gr2 == null) { return 1; } uint b1 = 0; uint b2 = 0; try { b1 = Convert.ToUInt32(gr1.id); } catch { } try { b2 = Convert.ToUInt32(gr2.id); } catch { } if (b1 < b2) { return -1; } if (b1 > b2) { return 1; } int n1 = 0; if (gr1.name != null && gr2.name != null) { n1 = gr1.name.CompareTo(gr2.name); } return n1; } // telltaleitem_sorter /// /// Comparing function for sorting. /// /// Item 1 /// Item 2 /// Result of compare. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "1", Justification = "Validation OK.")] [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Justification = "Validation OK.")] public static int telltaleitem_sorter(XmlClass.telltaleitem gr1, XmlClass.telltaleitem gr2) { if (gr1 == null && gr2 == null) { return 0; } if (gr1 == null && gr2 != null) { return -1; } if (gr1 != null && gr2 == null) { return 1; } int res = 0; if (gr1.telltaleGroupNumber < gr2.telltaleGroupNumber) { res = -1; } if (gr1.telltaleGroupNumber > gr2.telltaleGroupNumber) { res = 1; } if (res == 0) { if (gr1.telltalePriority < gr2.telltalePriority) { res = -1; } if (gr1.telltalePriority > gr2.telltalePriority) { res = 1; } } if (res == 0) { res = string.Compare(gr1.telltaleicon, gr2.telltaleicon); } return res; } /// /// Comparing function for sorting. /// /// Item 1 /// Item 2 /// Result of compare. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "1", Justification = "Validation OK.")] [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Justification = "Validation OK.")] public static int gaugeitem_sorter(XmlClass.gaugeitem gr1, XmlClass.gaugeitem gr2) { if (gr1 == null && gr2 == null) { return 0; } if (gr1 == null && gr2 != null) { return -1; } if (gr1 != null && gr2 == null) { return 1; } int res = 0; if (gr1.gaugeNumber < gr2.gaugeNumber) { res = -1; } if (gr1.gaugeNumber > gr2.gaugeNumber) { res = 1; } return res; } /// /// Comparing function for sorting. /// /// Item 1 /// Item 2 /// Result of compare. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "1", Justification = "Validation OK.")] [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Justification = "Validation OK.")] public static int commspeed_sorter(XmlClass.commspeed gr1, XmlClass.commspeed gr2) { if (gr1 == null && gr2 == null) { return 0; } if (gr1 == null && gr2 != null) { return -1; } if (gr1 != null && gr2 == null) { return 1; } int res = 0; if (gr1.bps < gr2.bps) { res = -1; } if (gr1.bps > gr2.bps) { res = 1; } return res; } /// /// Comparing function for sorting. /// /// Item 1 /// Item 2 /// Result of compare. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "1", Justification = "Validation OK.")] [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Justification = "Validation OK.")] public static int unitlist_sorter(XmlClass.unititem gr1, XmlClass.unititem gr2) { if (gr1 == null && gr2 == null) { return 0; } if (gr1 == null && gr2 != null) { return -1; } if (gr1 != null && gr2 == null) { return 1; } int res = 0; if (gr1.name != null && gr2.name != null) { res = gr1.name.CompareTo(gr2.name); } return res; } /// /// Comparing function for sorting. /// /// Item 1 /// Item 2 /// Result of compare. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "1", Justification = "Validation OK.")] [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Justification = "Validation OK.")] public static int vehicle_sorter(XmlClass.vehicle gr1, XmlClass.vehicle gr2) { if (gr1 == null && gr2 == null) { return 0; } if (gr1 == null && gr2 != null) { return -1; } if (gr1 != null && gr2 == null) { return 1; } int res = 0; if (gr1.name != null && gr2.name != null) { res = gr1.name.CompareTo(gr2.name); } return res; } /// /// Comparing function for sorting. /// /// Item 1 /// Item 2 /// Result of compare. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "1", Justification = "Validation OK.")] [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Justification = "Validation OK.")] public static int eculist_sorter(XmlClass.vehicle.ecuData gr1, XmlClass.vehicle.ecuData gr2) { if (gr1 == null && gr2 == null) { return 0; } if (gr1 == null && gr2 != null) { return -1; } if (gr1 != null && gr2 == null) { return 1; } int res = 0; if (gr1.id != null && gr2.id != null) { res = gr1.id.CompareTo(gr2.id); } return res; } /// /// Comparing function for sorting. /// /// Item 1 /// Item 2 /// Result of compare. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "1", Justification = "Validation OK.")] [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Justification = "Validation OK.")] public static int addrlist_sorter(XmlClass.vehicle.addrlist gr1, XmlClass.vehicle.addrlist gr2) { if (gr1 == null && gr2 == null) { return 0; } if (gr1 == null && gr2 != null) { return -1; } if (gr1 != null && gr2 == null) { return 1; } int res = 0; if (gr1.broadcast && !gr2.broadcast) { res = -1; } if (!gr1.broadcast && gr2.broadcast) { res = 1; } if (res == 0 && gr1.address != null && gr2.address != null) { res = gr1.address.CompareTo(gr2.address); } return res; } /// /// Comparing function for sorting. /// /// Item 1 /// Item 2 /// Result of compare. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "1", Justification = "Validation OK.")] [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Justification = "Validation OK.")] public static int parameterlist_sorter(XmlClass.parameteritem gr1, XmlClass.parameteritem gr2) { if (gr1 == null && gr2 == null) { return 0; } if (gr1 == null && gr2 != null) { return -1; } if (gr1 != null && gr2 == null) { return 1; } int res = 0; if (gr1.id < gr2.id) { res = -1; } if (gr1.id > gr2.id) { res = 1; } return res; } /// /// Comparing function for sorting. /// /// Item 1 /// Item 2 /// Result of compare. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "1", Justification = "Validation OK.")] [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Justification = "Validation OK.")] public static int pidlist_sorter(XmlClass.pidgroup.pidlist gr1, XmlClass.pidgroup.pidlist gr2) { if (gr1 == null && gr2 == null) { return 0; } if (gr1 == null && gr2 != null) { return -1; } if (gr1 != null && gr2 == null) { return 1; } if (gr1.pid_int < gr2.pid_int) { return -1; } if (gr1.pid_int > gr2.pid_int) { return 1; } return 0; } /// /// Comparing function for sorting. /// /// Item 1 /// Item 2 /// Result of compare. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity", Justification = "Reviewed.")] [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "1", Justification = "Validation OK.")] [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Justification = "Validation OK.")] public static int sensordata_sorter(XmlClass.pidgroup.pidlist.sensordata gr1, XmlClass.pidgroup.pidlist.sensordata gr2) { if (gr1 == null && gr2 == null) { return 0; } if (gr1 == null && gr2 != null) { return -1; } if (gr1 != null && gr2 == null) { return 1; } if (gr1.id < gr2.id) { return -1; } if (gr1.id > gr2.id) { return 1; } if (gr1.offset < gr2.offset) { return -1; } if (gr1.offset > gr2.offset) { return 1; } if (gr1.startbit == null && gr2.startbit == null) { return 0; } if (gr1.startbit == null && gr2.startbit != null) { return -1; } if (gr1.startbit != null && gr2.startbit == null) { return 1; } uint b1 = 0; uint b2 = 0; try { b1 = Convert.ToUInt32(gr1.startbit); } catch { } try { b2 = Convert.ToUInt32(gr2.startbit); } catch { } if (b1 < b2) { return -1; } if (b1 > b2) { return 1; } int n1 = 0; if (gr1.unit != null && gr2.unit != null) { n1 = gr1.unit.CompareTo(gr2.unit); } if (n1 == 0 && gr1.name != null && gr2.name != null) { n1 = gr1.name.CompareTo(gr2.name); } return n1; } /// /// C# implementation of 'strlen'. /// /// Byte array to check length on. /// Length of byte array until first NUL. public static int strlen(byte[] ba) { int i = 0; if (ba != null) { while (i < ba.Length && ba[i] != 0) { i++; } } return i; } /// /// Parse a string containing a hex number (which must start with "0x") /// The string may contain additional text but anything after the first /// space is ignored. /// /// String containing hex. /// Parsed value public static uint hexParse(string value) { uint parsedVal = 0; if (value != null) { value = value.ToUpperInvariant(); if (value.StartsWith("0X")) { int n = value.IndexOf(' '); if (n > 0) { value = value.Substring(0, n); } value = value.Substring(2); parsedVal = Convert.ToUInt32(value, 16); } else { throw new Exception("Not Hex."); } } return parsedVal; } /// /// Agnostic conversion that allows both ',' and '.' as a decimal separator. /// /// Value to parse. /// Result of conversion, 0 if failed to convert. public static double getDouble(object val) { double value = 0; try { value = Convert.ToDouble(val); } catch { try { value = Convert.ToDouble(val, CultureInfo.CreateSpecificCulture("en-US")); } catch { value = Convert.ToDouble(val, CultureInfo.CreateSpecificCulture("sv-SE")); } } return value; } /// /// Get capability string from byte value. /// /// Byte to look at. /// Bit to match /// String with capability in text. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2233:OperationsShouldNotOverflow", MessageId = "7-bit", Justification = "Reviewed.")] [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1720:IdentifiersShouldNotContainTypeNames", MessageId = "byte", Justification = "Suitable in this case.")] public static string getCapability(int capByte, int bit) { string capStr = " * Unknown * "; if (capByte < capabilities.Length) { string[] sa = capabilities[capByte]; capStr = sa[7 - bit]; } return capStr; } /// /// Parse a DTC code string, display a message box if it wasn't good. /// /// Code to parse, e.g. "P0420" /// DTC value public static int parseDtcCode(string code) { int dtcData = -1; try { dtcData = parseDtcCodeExtension(code); } catch (Exception ex) { MessageBox.Show( ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Stop); } return dtcData; } /// /// Get DTC value from payload. /// /// Payload data. /// Position in payload data. /// DTC String. E.g. P0420 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1045:DoNotPassTypesByReference", MessageId = "1#", Justification = "Reviewed, intentional.")] public static string getDtc(byte[] payload, ref int n) { string dtcStr = null; if (payload != null) { byte b1 = payload[n++]; byte b2 = payload[n++]; int ix = ((b1 >> 6) & 0x03); dtcStr = new string(dtcChar1[ix], 1); int n1 = ((b1 >> 4) & 0x03); dtcStr += string.Format("{0:0}", (int)n1); dtcStr += string.Format("{0:x1}", (int)(b1 & 0xf)); dtcStr += string.Format("{0:x2}", (int)b2); dtcStr = dtcStr.ToUpper(CultureInfo.InvariantCulture); } return dtcStr; } /// /// Parse a DTC code string, throw an exception if it wasn't good. /// /// Code to parse, e.g. "P0420" /// DTC value public static int parseDtcCodeExtension(string code) { int dtcData = -1; if (code != null) { // Get rid of trailing junk after code, separator ':' or ' ' (space). int n1 = code.IndexOf(':'); if (n1 > 0) { code = code.Substring(0, n1); } n1 = code.IndexOf(' '); if (n1 > 0) { code = code.Substring(0, n1); } // Only when it's 5 characters it's a real code like 'P0420' if (code.Length == 5) { char[] ca = code.ToCharArray(); int ch1 = -1; for (int i = 0; i < dtcChar1.Length; i++) { if (dtcChar1[i] == ca[0]) { ch1 = i; break; } } if (ch1 >= 0) { try { int ch2 = ca[1] - '0'; int b1 = Convert.ToUInt16(code.Substring(2, 1), 16); int b2 = Convert.ToUInt16(code.Substring(3), 16); b1 = (b1 & 0x0f) | ((ch2 & 0x03) << 4) | ((ch1 & 0x03) << 6); dtcData = b1 << 8 | b2; } catch (Exception e) { throw new Exception("Probably invalid data, remaining characters after\nfirst character may only be '0-9' and 'A-F'.\n\n" + e.Message); } } else { throw new Exception("Invalid first character of code,\nmust be one of 'P', 'C', 'B' or 'U'"); } } else { throw new Exception("Invalid code '" + code + "', must be 5 characters like: 'P0420'"); } } return dtcData; } /// /// Copy string into message byte by byte. /// /// Notice that this function is "unclean" and casts "char" to "byte" with /// possible loss of data. This is usually not a problem since characters /// that are handled shall be in the ASCII range. /// /// /// Message to copy to. /// String to copy. /// Start position in message data and last position after copy. /// Start position in source and last position after copy. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1045:DoNotPassTypesByReference", MessageId = "3#", Justification = "Reviewed, intentional.")] [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1045:DoNotPassTypesByReference", MessageId = "2#", Justification = "Reviewed, intentional.")] [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Justification = "Reviewed.")] [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1045:DoNotPassTypesByReference", MessageId = "0#", Justification = "Reviewed, intentional.")] public static void moveString(ref IPassThruMsg rxmsg1, string str, ref int n, ref int i) { if (rxmsg1 != null && str != null) { char[] vin = str.ToCharArray(); while (i < vin.Length) { rxmsg1.Data[n++] = (byte)vin[i]; i++; } } } /// /// Add text to message from textbox. /// /// Message to set data in. /// Position in data in message. /// Number of bytes processed. /// Text content. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1045:DoNotPassTypesByReference", MessageId = "2#", Justification = "Reviewed, intentional.")] [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1045:DoNotPassTypesByReference", MessageId = "1#", Justification = "Reviewed, intentional.")] [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1045:DoNotPassTypesByReference", MessageId = "0#", Justification = "Reviewed, intentional.")] public static void addText(ref IPassThruMsg rxmsg1, ref int n, ref int i, string text) { if (text != null) { i = 0; if (text.Length > 0) { moveString(ref rxmsg1, text, ref n, ref i); pad(ref rxmsg1, ref n, ref i, 16); } } } /// /// Pad value string. /// /// Message to set data in. /// Position in data in message. /// Number of bytes processed. /// Number of bytes to pad to. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1045:DoNotPassTypesByReference", MessageId = "2#", Justification = "Reviewed, intentional.")] [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1045:DoNotPassTypesByReference", MessageId = "1#", Justification = "Reviewed, intentional.")] [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1045:DoNotPassTypesByReference", MessageId = "0#", Justification = "Reviewed, intentional.")] [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Justification = "Reviewed, intentional.")] public static void pad(ref IPassThruMsg rxmsg1, ref int n, ref int i, int padValue) { while (i < padValue) { rxmsg1.Data[n++] = (byte)0x20; i++; } } /// /// Extract the data from the header. /// /// Essentially skips the number of bytes indicated by 'headerSize' and returns a new array. /// /// /// Payload to extract from. /// Size of header (number of bytes to skip from provided data) /// Extracted payload data. public static byte[] extractData(byte[] payload, int headerSize) { byte[] pidPayload = null; if (payload != null) { if (payload.Length >= headerSize) { pidPayload = new byte[payload.Length - headerSize]; Array.Copy(payload, headerSize, pidPayload, 0, payload.Length - headerSize); } else { throw new Exception("Payload is shorter than required header length."); } } return pidPayload; } /// /// Compare COM port names. /// [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1034:NestedTypesShouldNotBeVisible", Justification = "Reviewed.")] [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1702:CompoundWordsShouldBeCasedCorrectly", MessageId = "ComPort", Justification = "Reviewed.")] public class ComPortComparer : IComparer { /// /// Initializes a new instance of the class. /// public ComPortComparer() { } /// /// Compare COM port names. /// /// COM port A /// COM port B /// Result of the compare operation. public int Compare(string a, string b) { int res = 0; if (a != null && b != null) { if (a.Length >= 3 && b.Length >= 3) { string a1 = a.Substring(3); string b1 = b.Substring(3); int a1i = 0; int b1i = 0; try { a1i = Convert.ToInt32(a1); } catch { } try { b1i = Convert.ToInt32(b1); } catch { } if (a1i > b1i) { res = 1; } if (a1i < b1i) { res = -1; } } else { if (a.Length >= 3 && b.Length < 3) { res = 1; } else { if (a.Length < 3 && b.Length >= 3) { res = -1; } } } } return res; } } /// /// Resize an image to the given size using the proportions of the original image. /// /// There is an additional scaling that allows for shrinking of the image to make it fit better. /// /// /// Notice: This works best if height and width has the same value. /// /// /// Image to process. /// Height of new image. /// Width of new image. /// Additional scaling. /// Scaled image. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Justification = "Reviewed.")] [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "Reviewed.")] public static Bitmap getScaledImage(Image img, int height, int width, float scale) { float proportion = (float)img.Height / (float)img.Width; int w; int h; if (proportion < 1) { h = (int)(scale * height * proportion); w = (int)(scale * width); } else { h = (int)(scale * height); w = (int)(scale * width / proportion); } Bitmap bmp = new Bitmap(w, h); using (Graphics g = Graphics.FromImage(bmp)) { g.DrawImage(img, new Rectangle(0, 0, bmp.Width, bmp.Height)); } return bmp; } /// /// Resize an image to the given size using the proportions of the original image. /// /// There is an additional scaling that allows for shrinking of the image to make it fit better. /// /// /// Notice: This works best if height and width has the same value. /// /// /// Image to process. /// Height of new image. /// Width of new image. /// Additional scaling. /// Scaled image. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0", Justification = "Reviewed.")] [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "Reviewed.")] public static Bitmap getScaledImage2(Image img, int height, int width, float scale) { float proportion = (float)img.Height / (float)img.Width; int w; int h; int x; int y; if (proportion < 1) { h = (int)(scale * height * proportion); w = (int)(scale * width); x = 0; y = (height - h) / 2; } else { h = (int)(scale * height); w = (int)(scale * width / proportion); x = (width - w) / 2; y = 0; } Bitmap bmp = new Bitmap(height, width); using (Graphics g = Graphics.FromImage(bmp)) { g.DrawImage(img, new Rectangle(x, y, w, h)); } return bmp; } /// /// Get the list as a hex string. /// /// List of bytes. /// String with hex values. public static string listToHexString(IList response) { string rspStr = string.Empty; if (response != null) { foreach (byte b1 in response) { if (!string.IsNullOrEmpty(rspStr)) { rspStr += " "; } rspStr += b1.ToString("X2"); } } return rspStr; } /// /// Convert a byte array to a string with hex values. /// /// Raw data. /// Start position in data. /// String with hex codes. public static string arrayToString(byte[] data, uint startindex) { string inData = string.Empty; if (data != null) { uint p1 = startindex; while (p1 < data.Length) { if (!string.IsNullOrEmpty(inData)) { inData += " "; } inData += data[p1++].ToString("X2"); } } return inData; } /// /// Check if raw value potentially is invalid. /// /// Sensor to check for. /// Raw value to check. /// 'true' if potentially invalid. (raw has all bits to 1) public static bool checkNaData(XmlClass.pidgroup.pidlist.sensordata sensor, uint rawValue) { bool naFlag = false; if (sensor != null) { switch (sensor.count) { case 1: naFlag = rawValue == 0xff; break; case 2: naFlag = rawValue == 0xffff; break; case 3: naFlag = rawValue == 0xffffff; break; case 4: naFlag = rawValue == 0xffffffff; break; } } return naFlag; } /// /// List of SSM capabilities. /// This list is incomplete. /// private static string[][] capabilities = { new string [] { "7 Engine Load", "6 Coolant Temperature", "5 Air/Fuel Correction #1", "4 Air/Fuel Learning #1", "3 Air/Fuel Correction #2", "2 Air/Fuel Learning #2", "1 Manifold Absolute Pressure", "0 Engine Speed", }, new string [] { "7 Vehicle Speed", "6 Ignition Timing", "5 Intake Air Temperature", "4 Mass Air Flow", "3 Throttle Opening Angle", "2 Front O2 Sensor #1", "1 Rear O2 Sensor", "0 Front O2 Sensor #2", }, new string [] { "7 Battery Voltage", "6 Air Flow Sensor Voltage", "5 Throttle Sensor Voltage", "4 Differential Pressure Sensor Voltage", "3 Fuel Injection #1 Pulse Width", "2 Fuel Injection #2 Pulse Width", "1 Knock Correction", "0 Atmospheric Pressure", }, new string [] { "7 Manifold Relative Pressure", "6 Pressure Differential Sensor", "5 Fuel Tank Pressure", "4 CO Adjustment", "3 Learned Ignition Timing", "2 Accelerator Opening Angle", "1 Fuel Temperature", "0 Front O2 Heater #1", }, new string [] { "7 Rear O2 Heater Current", "6 Front O2 Heater #2", "5 Fuel Level", "4 -------------------------", "3 Primary Wastegate Duty Cycle", "2 Secondary Wastegate Duty Cycle", "1 CPC Valve Duty Ratio", "0 Tumble Valve Position Sensor Right", }, new string [] { "7 Tumble Valve Position Sensor Left", "6 Idle Speed Control Valve Duty Ratio", "5 Air/Fuel Lean Correction", "4 Air/Fuel Heater Duty", "3 Idle Speed Control Valve Step", "2 Number of Ex. Gas Recirc Steps", "1 Alternator Duty", "0 Fuel Pump Duty", }, new string [] { "7 VVT Advance Angle Right", "6 VVT Advance Angle Left", "5 OCV Duty Right", "4 OCV Duty Left", "3 OCV Current Right", "2 OCV Current Left", "1 Air/Fuel Sensor #1 Current", "0 Air/Fuel Sensor #2 Current", }, new string [] { "7 Air/Fuel Sensor #1 Resistance", "6 Air/Fuel Sensor #2 Resistance", "5 Air/Fuel Sensor #1", "4 Air/Fuel Sensor #2", "3 Air/Fuel Correction #3", "2 Air/Fuel Learning #3", "1 Rear O2 Heater Voltage", "0 Air/Fuel Adjustment Voltage", }, new string [] { "7 -------------------------", "6 -------------------------", "5 Gear Position", "4 -------------------------", "3 -------------------------", "2 -------------------------", "1 -------------------------", "0 -------------------------", }, new string [] { "7 -------------------------", "6 -------------------------", "5 -------------------------", "4 Air/Fuel Sensor #1 Heater Current", "3 Air/Fuel Sensor #2 Heater Current", "2 -------------------------", "1 -------------------------", "0 -------------------------", }, new string [] { "7 -------------------------", "6 -------------------------", "5 -------------------------", "4 -------------------------", "3 -------------------------", "2 -------------------------", "1 -------------------------", "0 -------------------------", }, new string [] { "7 -------------------------", "6 AT Vehicle ID", "5 Test Mode Connector", "4 Read Memory Connector", "3 -------------------------", "2 -------------------------", "1 -------------------------", "0 -------------------------", }, new string [] { "7 Neutral Position Switch", "6 Idle Switch", "5 -------------------------", "4 Intercooler AutoWash Switch", "3 Ignition Switch", "2 Power Steering Switch", "1 Air Conditioning Switch", "0 -------------------------", }, new string [] { "7 Handle Switchv", "6 Starter Switch", "5 Front O2 Rich Signal", "4 Rear O2 Rich Signal", "3 Front O2 #2 Rich Signal", "2 Knock Signal 1", "1 Knock Signal 2", "0 Electrical Load Signal", }, new string [] { "7 Crank Position Sensor", "6 Cam Position Senso", "5 Defogger Switch", "4 Blower Switch", "3 Interior Light Switch", "2 Wiper Switch", "1 Air-Con Lock Signal", "0 Air-Con Mid Pressure Switch", }, new string [] { "7 Air-Con Compressor Signal", "6 Radiator Fan Relay #3", "5 Radiator Fan Relay #1", "4 Radiator Fan Relay #2", "3 Fuel Pump Relay", "2 Intercooler Auto-Wash Relay", "1 CPC Solenoid Valve", "0 Blow-By Leak Connector", }, new string [] { "7 PCV Solenoid Valve", "6 TGV Output", "5 TGV Drive", "4 Variable Intake Air Solenoid", "3 Pressure Sources Change", "2 Vent Solenoid Valve", "1 P/S Solenoid Valve", "0 Assist Air Solenoid Valve", }, new string [] { "7 Tank Sensor Control Valve", "6 Relief Valve Solenoid 1", "5 Relief Valve Solenoid 2", "4 TCS Relief Valve Solenoid", "3 Ex. Gas Positive Pressure", "2 Ex. Gas Negative Pressure", "1 Intake Air Solenoid", "0 Muffler Control", }, new string [] { "7 -------------------------", "6 -------------------------", "5 -------------------------", "4 -------------------------", "3 Retard Signal from AT", "2 Fuel Cut Signal from AT", "1 Ban of Torque Down", "0 Request Torque Down VDC", }, new string [] { "7 Torque Control Signal #1", "6 Torque Control Signal #2", "5 Torque Permission Signal", "4 EAM signal", "3 AT coop. lock up signal", "2 AT coop. lean burn signal", "1 AT coop. rich spike signal", "0 AET Signal", }, new string [] { "7 -------------------------", "6 -------------------------", "5 -------------------------", "4 -------------------------", "3 -------------------------", "2 -------------------------", "1 -------------------------", "0 -------------------------", }, new string [] { "7 -------------------------", "6 -------------------------", "5 -------------------------", "4 -------------------------", "3 -------------------------", "2 -------------------------", "1 -------------------------", "0 -------------------------", }, new string [] { "7 -------------------------", "6 -------------------------", "5 -------------------------", "4 -------------------------", "3 -------------------------", "2 -------------------------", "1 -------------------------", "0 -------------------------", }, new string [] { "7 -------------------------", "6 -------------------------", "5 -------------------------", "4 -------------------------", "3 -------------------------", "2 -------------------------", "1 -------------------------", "0 -------------------------", }, new string [] { "7 -------------------------", "6 -------------------------", "5 -------------------------", "4 -------------------------", "3 -------------------------", "2 -------------------------", "1 -------------------------", "0 -------------------------", }, new string [] { "7 -------------------------", "6 -------------------------", "5 -------------------------", "4 -------------------------", "3 -------------------------", "2 -------------------------", "1 -------------------------", "0 -------------------------", }, new string [] { "7 -------------------------", "6 -------------------------", "5 -------------------------", "4 -------------------------", "3 -------------------------", "2 -------------------------", "1 -------------------------", "0 -------------------------", }, new string [] { "7 -------------------------", "6 -------------------------", "5 -------------------------", "4 -------------------------", "3 -------------------------", "2 -------------------------", "1 -------------------------", "0 -------------------------", }, new string [] { "7 -------------------------", "6 -------------------------", "5 -------------------------", "4 -------------------------", "3 -------------------------", "2 -------------------------", "1 -------------------------", "0 -------------------------", }, new string [] { "7 -------------------------", "6 -------------------------", "5 -------------------------", "4 -------------------------", "3 -------------------------", "2 -------------------------", "1 -------------------------", "0 -------------------------", }, new string [] { "7 -------------------------", "6 -------------------------", "5 Throttle Motor Duty", "4 Throttle Motor Voltage", "3 -------------------------", "2 -------------------------", "1 -------------------------", "0 -------------------------", }, new string [] { "7 -------------------------", "6 -------------------------", "5 -------------------------", "4 -------------------------", "3 -------------------------", "2 -------------------------", "1 -------------------------", "0 -------------------------", }, new string [] { "7 Sub Throttle Sensor", "6 Main Throttle Sensor", "5 Sub Accelerator Sensor", "4 Main Accelerator Sensor", "3 Brake Booster Pressure", "2 Fuel Pressure (High)", "1 Exhaust Gas Temperature", "0 -------------------------", }, new string [] { "7 Cold Start Injector", "6 SCV Step", "5 Memorized Cruise Speed", "4 -------------------------", "3 -------------------------", "2 -------------------------", "1 -------------------------", "0 -------------------------", }, new string [] { "7 -------------------------", "6 -------------------------", "5 -------------------------", "4 -------------------------", "3 -------------------------", "2 -------------------------", "1 -------------------------", "0 -------------------------", }, new string [] { "7 Exhaust VVT Advance Angle Right", "6 Exhaust VVT Advance Angle Left", "5 Exhaust OCV Duty Right", "4 Exhaust OCV Duty Left", "3 Exhaust OCV Current Right", "2 Exhaust OCV Current Left", "1 -------------------------", "0 -------------------------", }, new string [] { "7 -------------------------", "6 ETC Motor Relay", "5 -------------------------", "4 -------------------------", "3 -------------------------", "2 -------------------------", "1 -------------------------", "0 -------------------------", }, new string [] { "7 Clutch Switch", "6 Stop Light Switch", "5 Set/Coast Switch", "4 Resume/Accelerate Switch", "3 Brake Switch", "2 -------------------------", "1 Accelerator Switch", "0 -------------------------", }, new string [] { "7 -------------------------", "6 -------------------------", "5 -------------------------", "4 -------------------------", "3 -------------------------", "2 -------------------------", "1 -------------------------", "0 -------------------------", }, new string [] { "7 -------------------------", "6 -------------------------", "5 -------------------------", "4 -------------------------", "3 -------------------------", "2 -------------------------", "1 -------------------------", "0 -------------------------", }, new string [] { "7 -------------------------", "6 -------------------------", "5 -------------------------", "4 -------------------------", "3 -------------------------", "2 -------------------------", "1 -------------------------", "0 -------------------------", }, new string [] { "7 -------------------------", "6 -------------------------", "5 -------------------------", "4 -------------------------", "3 -------------------------", "2 -------------------------", "1 -------------------------", "0 -------------------------", }, new string [] { "7 -------------------------", "6 -------------------------", "5 -------------------------", "4 -------------------------", "3 -------------------------", "2 -------------------------", "1 -------------------------", "0 -------------------------", }, new string [] { "7 -------------------------", "6 -------------------------", "5 -------------------------", "4 -------------------------", "3 -------------------------", "2 -------------------------", "1 -------------------------", "0 -------------------------", }, new string [] { "7 -------------------------", "6 -------------------------", "5 -------------------------", "4 -------------------------", "3 -------------------------", "2 -------------------------", "1 -------------------------", "0 -------------------------", }, new string [] { "7 -------------------------", "6 -------------------------", "5 -------------------------", "4 -------------------------", "3 -------------------------", "2 -------------------------", "1 -------------------------", "0 -------------------------", }, new string [] { "7 -------------------------", "6 -------------------------", "5 -------------------------", "4 -------------------------", "3 -------------------------", "2 -------------------------", "1 -------------------------", "0 -------------------------", }, new string [] { "7 Roughness Monitor Cylinder #1", "6 Roughness Monitor Cylinder #2", "5 Roughness Monitor Cylinder #3", "4 Roughness Monitor Cylinder #4", "3 -------------------------", "2 -------------------------", "1 -------------------------", "0 -------------------------", }, }; } }