mirror of
https://github.com/DarthAffe/OBD.NET.git
synced 2025-12-12 16:58:30 +00:00
First somehow working version
This commit is contained in:
parent
b3e8e82da7
commit
5dfac27120
61
OBD.NET/OBD.NET/Commands/ATCommand.cs
Normal file
61
OBD.NET/OBD.NET/Commands/ATCommand.cs
Normal file
@ -0,0 +1,61 @@
|
||||
namespace OBD.NET.Commands
|
||||
{
|
||||
public class ATCommand
|
||||
{
|
||||
#region Values
|
||||
|
||||
//TODO DarthAffe 26.06.2016: Implement all commands
|
||||
|
||||
public static readonly ATCommand RepeatLastCommand = new ATCommand("\r");
|
||||
public static readonly ATCommand ResetDevice = new ATCommand("ATZ");
|
||||
public static readonly ATCommand ReadVoltage = new ATCommand("ATRV");
|
||||
public static readonly ATCommand EchoOn = new ATCommand("ATE1", "^OK$");
|
||||
public static readonly ATCommand EchoOff = new ATCommand("ATE0", "^OK$");
|
||||
public static readonly ATCommand HeadersOn = new ATCommand("ATH1", "^OK$");
|
||||
public static readonly ATCommand HeadersOff = new ATCommand("ATH0", "^OK$");
|
||||
public static readonly ATCommand PrintSpacesOn = new ATCommand("ATS1", "^OK$");
|
||||
public static readonly ATCommand PrintSpacesOff = new ATCommand("ATS0", "^OK$");
|
||||
public static readonly ATCommand LinefeedsOn = new ATCommand("ATL1", "^OK$");
|
||||
public static readonly ATCommand LinefeedsOff = new ATCommand("ATL0", "^OK$");
|
||||
public static readonly ATCommand SetProtocolAuto = new ATCommand("ATSP0", "^OK$");
|
||||
public static readonly ATCommand PrintVersion = new ATCommand("ATI", "^ELM327.*");
|
||||
public static readonly ATCommand CloseProtocol = new ATCommand("ATPC");
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties & Fields
|
||||
|
||||
public string Command { get; }
|
||||
public string ExpectedResult { get; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
private ATCommand(string command, string expectedResult = null)
|
||||
{
|
||||
this.Command = command;
|
||||
this.ExpectedResult = expectedResult;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Command;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Operators
|
||||
|
||||
public static implicit operator string(ATCommand command)
|
||||
{
|
||||
return command.ToString();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
56
OBD.NET/OBD.NET/Communication/SerialConnection.cs
Normal file
56
OBD.NET/OBD.NET/Communication/SerialConnection.cs
Normal file
@ -0,0 +1,56 @@
|
||||
using System;
|
||||
using System.IO.Ports;
|
||||
|
||||
namespace OBD.NET.Communication
|
||||
{
|
||||
public class SerialConnection : IDisposable
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
private readonly SerialPort _serialPort;
|
||||
|
||||
public bool IsOpen => _serialPort.IsOpen;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public SerialConnection(string port, int baudRate = 38400, Parity parity = Parity.None,
|
||||
StopBits stopBits = StopBits.One, Handshake handshake = Handshake.None, int timeout = 5000)
|
||||
{
|
||||
_serialPort = new SerialPort(port, baudRate, parity)
|
||||
{
|
||||
StopBits = stopBits,
|
||||
Handshake = handshake,
|
||||
ReadTimeout = timeout,
|
||||
WriteTimeout = timeout
|
||||
};
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
public void Connect()
|
||||
{
|
||||
_serialPort.Open();
|
||||
}
|
||||
|
||||
public void Write(string text)
|
||||
{
|
||||
_serialPort.Write(text);
|
||||
}
|
||||
|
||||
public byte ReadByte()
|
||||
{
|
||||
return (byte)_serialPort.ReadByte();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_serialPort?.Dispose();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@ -2,6 +2,12 @@
|
||||
{
|
||||
public class Count : GenericData
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
protected override string Unit => null;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public Count(double value, double minValue, double maxValue)
|
||||
|
||||
@ -2,6 +2,12 @@
|
||||
{
|
||||
public class Degree : GenericData
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
protected override string Unit => "°";
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public Degree(double value, double minValue, double maxValue)
|
||||
|
||||
@ -2,6 +2,12 @@
|
||||
{
|
||||
public class DegreeCelsius : GenericData
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
protected override string Unit => "°C";
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public DegreeCelsius(double value, double minValue, double maxValue)
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
|
||||
namespace OBD.NET.DataTypes
|
||||
{
|
||||
public class GenericData
|
||||
public abstract class GenericData
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
@ -11,6 +11,8 @@ namespace OBD.NET.DataTypes
|
||||
public double MaxValue { get; }
|
||||
public bool IsFloatingPointValue { get; }
|
||||
|
||||
protected abstract string Unit { get; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
@ -46,5 +48,14 @@ namespace OBD.NET.DataTypes
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return (IsFloatingPointValue ? Value.ToString("0.00") : Value.ToString()) + (Unit == null ? string.Empty : (" " + Unit));
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,6 +2,12 @@
|
||||
{
|
||||
public class GramPerSec : GenericData
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
protected override string Unit => "g/s";
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public GramPerSec(double value, double minValue, double maxValue)
|
||||
|
||||
@ -2,6 +2,12 @@
|
||||
{
|
||||
public class Kilometre : GenericData
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
protected override string Unit => "km";
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public Kilometre(double value, double minValue, double maxValue)
|
||||
|
||||
@ -2,6 +2,12 @@
|
||||
{
|
||||
public class KilometrePerHour : GenericData
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
protected override string Unit => "km/h";
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public KilometrePerHour(double value, double minValue, double maxValue)
|
||||
|
||||
@ -2,6 +2,12 @@
|
||||
{
|
||||
public class Kilopascal : GenericData
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
protected override string Unit => "kPa";
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public Kilopascal(double value, double minValue, double maxValue)
|
||||
|
||||
@ -2,6 +2,12 @@
|
||||
{
|
||||
public class LitresPerHour : GenericData
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
protected override string Unit => "l/h";
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public LitresPerHour(double value, double minValue, double maxValue)
|
||||
|
||||
@ -2,6 +2,12 @@
|
||||
{
|
||||
public class Milliampere : GenericData
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
protected override string Unit => "mA";
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public Milliampere(double value, double minValue, double maxValue)
|
||||
|
||||
@ -2,6 +2,12 @@
|
||||
{
|
||||
public class Minute : GenericData
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
protected override string Unit => "min";
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public Minute(double value, double minValue, double maxValue)
|
||||
|
||||
@ -2,6 +2,12 @@
|
||||
{
|
||||
public class NewtonMetre : GenericData
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
protected override string Unit => "N";
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public NewtonMetre(double value, double minValue, double maxValue)
|
||||
|
||||
@ -2,6 +2,12 @@
|
||||
{
|
||||
public class Pascal : GenericData
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
protected override string Unit => "Pa";
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public Pascal(double value, double minValue, double maxValue)
|
||||
|
||||
@ -2,6 +2,12 @@
|
||||
{
|
||||
public class Percent : GenericData
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
protected override string Unit => "%";
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public Percent(double value, double minValue, double maxValue)
|
||||
|
||||
@ -2,6 +2,12 @@
|
||||
{
|
||||
public class Ratio : GenericData
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
protected override string Unit => null;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public Ratio(double value, double minValue, double maxValue)
|
||||
|
||||
@ -2,6 +2,12 @@
|
||||
{
|
||||
public class RevolutionsPerMinute : GenericData
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
protected override string Unit => "rpm";
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public RevolutionsPerMinute(double value, double minValue, double maxValue)
|
||||
|
||||
@ -2,6 +2,12 @@
|
||||
{
|
||||
public class Second : GenericData
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
protected override string Unit => "s";
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public Second(double value, double minValue, double maxValue)
|
||||
|
||||
@ -2,6 +2,12 @@
|
||||
{
|
||||
public class Volt : GenericData
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
protected override string Unit => "V";
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public Volt(double value, double minValue, double maxValue)
|
||||
|
||||
196
OBD.NET/OBD.NET/Devices/ELM327.cs
Normal file
196
OBD.NET/OBD.NET/Devices/ELM327.cs
Normal file
@ -0,0 +1,196 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using OBD.NET.Commands;
|
||||
using OBD.NET.Communication;
|
||||
using OBD.NET.Enums;
|
||||
using OBD.NET.Events;
|
||||
using OBD.NET.Events.EventArgs;
|
||||
using OBD.NET.Extensions;
|
||||
using OBD.NET.Logging;
|
||||
using OBD.NET.OBDData;
|
||||
|
||||
namespace OBD.NET.Devices
|
||||
{
|
||||
public class ELM327 : SerialDevice
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
protected Dictionary<Type, IDataEventManager> _dataReceivedEventHandlers = new Dictionary<Type, IDataEventManager>();
|
||||
|
||||
protected static Dictionary<Type, byte> PidCache { get; } = new Dictionary<Type, byte>();
|
||||
protected static Dictionary<byte, Type> DataTypeCache { get; } = new Dictionary<byte, Type>();
|
||||
|
||||
protected Mode Mode { get; set; } = Mode.ShowCurrentData; //TODO DarthAffe 26.06.2016: Implement different modes
|
||||
|
||||
protected override string ExpectedNoData => @"(NO DATA)|(SEARCHING)|(STOP)|\?";
|
||||
|
||||
#endregion
|
||||
|
||||
#region Events
|
||||
|
||||
public delegate void DataReceivedEventHandler<T>(object sender, DataReceivedEventArgs<T> args) where T : IOBDData;
|
||||
|
||||
public delegate void RawDataReceivedEventHandler(object sender, RawDataReceivedEventArgs args);
|
||||
public event RawDataReceivedEventHandler RawDataReceived;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public ELM327(SerialConnection connection, IOBDLogger logger = null)
|
||||
: base(connection, logger: logger)
|
||||
{ }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
Logger?.WriteLine("Initializing ...", OBDLogLevel.Debug);
|
||||
int repeats = 3;
|
||||
bool repeat = true;
|
||||
while (repeat)
|
||||
{
|
||||
try
|
||||
{
|
||||
Logger?.WriteLine("Resetting Device ...", OBDLogLevel.Debug);
|
||||
SendCommand(ATCommand.ResetDevice);
|
||||
Thread.Sleep(1000);
|
||||
|
||||
Logger?.WriteLine("Turning Echo Off ...", OBDLogLevel.Debug);
|
||||
SendCommand(ATCommand.EchoOff);
|
||||
|
||||
Logger?.WriteLine("Turning Linefeeds Off ...", OBDLogLevel.Debug);
|
||||
SendCommand(ATCommand.LinefeedsOff);
|
||||
|
||||
Logger?.WriteLine("Turning Headers Off ...", OBDLogLevel.Debug);
|
||||
SendCommand(ATCommand.HeadersOff);
|
||||
|
||||
Logger?.WriteLine("Turning Spaced Off ...", OBDLogLevel.Debug);
|
||||
SendCommand(ATCommand.PrintSpacesOff);
|
||||
|
||||
Logger?.WriteLine("Setting the Protocol to 'Auto' ...", OBDLogLevel.Debug);
|
||||
SendCommand(ATCommand.SetProtocolAuto);
|
||||
|
||||
repeat = false;
|
||||
}
|
||||
// DarthAffe 21.02.2017: This seems to happen sometimes, i don't know why - just retry.
|
||||
catch (TimeoutException)
|
||||
{
|
||||
if (repeats > 0)
|
||||
{
|
||||
Logger?.WriteLine("Timout while initializing ... retry!", OBDLogLevel.Debug);
|
||||
repeats--;
|
||||
}
|
||||
else
|
||||
{
|
||||
Logger?.WriteLine("Failed to initialize the device!", OBDLogLevel.Error);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Thread.Sleep(1000);
|
||||
}
|
||||
|
||||
public virtual void SendCommand(ATCommand command)
|
||||
{
|
||||
SendCommand(command.Command, command.ExpectedResult);
|
||||
}
|
||||
|
||||
public virtual T RequestData<T>()
|
||||
where T : class, IOBDData, new()
|
||||
{
|
||||
Logger?.WriteLine("Requesting Type " + typeof(T).Name + " ...", OBDLogLevel.Debug);
|
||||
|
||||
byte pid;
|
||||
if (!PidCache.TryGetValue(typeof(T), out pid))
|
||||
{
|
||||
T data = Activator.CreateInstance<T>();
|
||||
pid = data.PID;
|
||||
PidCache.Add(typeof(T), pid);
|
||||
DataTypeCache.Add(pid, typeof(T));
|
||||
}
|
||||
return RequestData(pid) as T;
|
||||
}
|
||||
|
||||
public virtual IOBDData RequestData(byte pid)
|
||||
{
|
||||
Logger?.WriteLine("Requesting PID " + pid.ToString("X2") + " ...", OBDLogLevel.Debug);
|
||||
string result = SendCommand(((byte)Mode).ToString("X2") + pid.ToString("X2"), "4.*");
|
||||
Logger?.WriteLine("Result for PID " + pid.ToString("X2") + ": " + result, OBDLogLevel.Debug);
|
||||
return ProcessData(result);
|
||||
}
|
||||
|
||||
protected virtual IOBDData ProcessData(string data)
|
||||
{
|
||||
if (data == null) return null;
|
||||
|
||||
DateTime timestamp = DateTime.Now;
|
||||
|
||||
RawDataReceived?.Invoke(this, new RawDataReceivedEventArgs(data, timestamp));
|
||||
|
||||
if (data.Length > 4)
|
||||
if (data[0] == '4')
|
||||
{
|
||||
byte mode = (byte)data[1].GetHexVal();
|
||||
if (mode == (byte)Mode)
|
||||
{
|
||||
byte pid = (byte)data.Substring(2, 2).GetHexVal();
|
||||
Type dataType;
|
||||
if (DataTypeCache.TryGetValue(pid, out dataType))
|
||||
{
|
||||
IOBDData obdData = (IOBDData)Activator.CreateInstance(dataType);
|
||||
obdData.Load(data.Substring(4, data.Length - 4));
|
||||
|
||||
IDataEventManager dataEventManager;
|
||||
if (_dataReceivedEventHandlers.TryGetValue(dataType, out dataEventManager))
|
||||
dataEventManager.RaiseEvent(this, obdData, timestamp);
|
||||
|
||||
return obdData;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
}
|
||||
|
||||
public void Dispose(bool sendCloseProtocol)
|
||||
{
|
||||
if (sendCloseProtocol)
|
||||
{
|
||||
SendCommand(ATCommand.CloseProtocol);
|
||||
Thread.Sleep(500);
|
||||
}
|
||||
|
||||
base.Dispose();
|
||||
}
|
||||
|
||||
public void SubscribeDataReceived<T>(DataReceivedEventHandler<T> eventHandler) where T : IOBDData
|
||||
{
|
||||
IDataEventManager eventManager;
|
||||
if (!_dataReceivedEventHandlers.TryGetValue(typeof(T), out eventManager))
|
||||
_dataReceivedEventHandlers.Add(typeof(T), (eventManager = new GenericDataEventManager<T>()));
|
||||
|
||||
((GenericDataEventManager<T>)eventManager).DataReceived += eventHandler;
|
||||
}
|
||||
|
||||
public void UnsubscribeDataReceived<T>(DataReceivedEventHandler<T> eventHandler) where T : IOBDData
|
||||
{
|
||||
IDataEventManager eventManager;
|
||||
if (_dataReceivedEventHandlers.TryGetValue(typeof(T), out eventManager))
|
||||
((GenericDataEventManager<T>)eventManager).DataReceived -= eventHandler;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
18
OBD.NET/OBD.NET/Devices/STN1170.cs
Normal file
18
OBD.NET/OBD.NET/Devices/STN1170.cs
Normal file
@ -0,0 +1,18 @@
|
||||
using OBD.NET.Communication;
|
||||
using OBD.NET.Logging;
|
||||
|
||||
namespace OBD.NET.Devices
|
||||
{
|
||||
public class STN1170 : ELM327 // Fully compatible device
|
||||
{
|
||||
//TODO DarthAffe 26.06.2016: Add ST-Commands and stuff
|
||||
|
||||
#region Constructors
|
||||
|
||||
public STN1170(SerialConnection connection, IOBDLogger logger = null)
|
||||
: base(connection, logger)
|
||||
{ }
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
118
OBD.NET/OBD.NET/Devices/SerialDevice.cs
Normal file
118
OBD.NET/OBD.NET/Devices/SerialDevice.cs
Normal file
@ -0,0 +1,118 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using OBD.NET.Communication;
|
||||
using OBD.NET.Exceptions;
|
||||
using OBD.NET.Logging;
|
||||
|
||||
namespace OBD.NET.Devices
|
||||
{
|
||||
public abstract class SerialDevice : IDisposable
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
private readonly byte[] _responseBuffer = new byte[512];
|
||||
|
||||
protected IOBDLogger Logger { get; }
|
||||
|
||||
protected SerialConnection Connection { get; }
|
||||
protected char Prompt { get; set; }
|
||||
protected char Terminator { get; set; }
|
||||
|
||||
protected abstract string ExpectedNoData { get; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
protected SerialDevice(SerialConnection connection, char prompt = '>', char terminator = '\r', IOBDLogger logger = null)
|
||||
{
|
||||
this.Connection = connection;
|
||||
this.Prompt = prompt;
|
||||
this.Terminator = terminator;
|
||||
this.Logger = logger;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
public virtual void Initialize()
|
||||
{
|
||||
Logger?.WriteLine("Opening Serial-Connection ...", OBDLogLevel.Debug);
|
||||
Connection.Connect();
|
||||
|
||||
if (!Connection.IsOpen)
|
||||
{
|
||||
Logger?.WriteLine("Failed to open Serial-Connection.", OBDLogLevel.Error);
|
||||
throw new SerialException("Failed to open Serial-Connection.");
|
||||
}
|
||||
else
|
||||
Logger?.WriteLine("Opened Serial-Connection!", OBDLogLevel.Debug);
|
||||
|
||||
Thread.Sleep(500);
|
||||
}
|
||||
|
||||
protected virtual string SendCommand(string command, string expectedResult = null)
|
||||
{
|
||||
if (!Connection.IsOpen) return null;
|
||||
|
||||
command = PrepareCommand(command);
|
||||
|
||||
Logger?.WriteLine("Writing Command: '" + command.Replace('\r', '\'') + "'", OBDLogLevel.Verbose);
|
||||
Connection.Write(command);
|
||||
|
||||
Logger?.WriteLine("Waiting for response ...", OBDLogLevel.Debug);
|
||||
List<string> results = ReadResponse();
|
||||
if (expectedResult == null)
|
||||
return results.LastOrDefault();
|
||||
|
||||
// DarthAffe 22.02.2017: We expect the lats result to be the "best".
|
||||
for (int i = results.Count - 1; i >= 0; i--)
|
||||
if (Regex.Match(results[i], expectedResult, RegexOptions.IgnoreCase).Success)
|
||||
return results[i];
|
||||
|
||||
if (results.Any(x => Regex.Match(x, ExpectedNoData, RegexOptions.IgnoreCase).Success))
|
||||
return null;
|
||||
|
||||
Logger?.WriteLine("Unexpected Result: '" + string.Join("<\\r>", results) + "' expected was '" + expectedResult + "'", OBDLogLevel.Error);
|
||||
throw new UnexpectedResultException(string.Join("<\\r>", results), expectedResult);
|
||||
}
|
||||
|
||||
protected virtual string PrepareCommand(string command)
|
||||
{
|
||||
if (command == null) throw new ArgumentNullException(nameof(command));
|
||||
|
||||
if (!command.EndsWith(Terminator.ToString(), StringComparison.Ordinal))
|
||||
command += Terminator;
|
||||
|
||||
return command;
|
||||
}
|
||||
|
||||
protected virtual List<string> ReadResponse()
|
||||
{
|
||||
byte b;
|
||||
int count = 0;
|
||||
do
|
||||
{
|
||||
b = Connection.ReadByte();
|
||||
if (b != 0x00)
|
||||
_responseBuffer[count++] = b;
|
||||
} while (b != Prompt);
|
||||
|
||||
string response = Encoding.ASCII.GetString(_responseBuffer, 0, count - 1); // -1 to remove the prompt
|
||||
Logger?.WriteLine("Response: '" + response.Replace("\r", "<\\r>").Replace("\n", "<\\n>") + "'", OBDLogLevel.Verbose);
|
||||
return response.Split('\r').Select(x => x.Replace("\r", string.Empty).Replace("\n", string.Empty).Trim()).Where(x => !string.IsNullOrWhiteSpace(x)).ToList();
|
||||
}
|
||||
|
||||
public virtual void Dispose()
|
||||
{
|
||||
Connection?.Dispose();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@ -3,7 +3,7 @@
|
||||
/// <summary>
|
||||
/// https://en.wikipedia.org/wiki/OBD-II_PIDs#Modes
|
||||
/// </summary>
|
||||
internal enum Mode
|
||||
public enum Mode
|
||||
{
|
||||
ShowCurrentData = 0x01,
|
||||
ShowFreezeFrameData = 0x02,
|
||||
|
||||
25
OBD.NET/OBD.NET/Events/EventArgs/DataReceivedEventArgs.cs
Normal file
25
OBD.NET/OBD.NET/Events/EventArgs/DataReceivedEventArgs.cs
Normal file
@ -0,0 +1,25 @@
|
||||
using System;
|
||||
using OBD.NET.OBDData;
|
||||
|
||||
namespace OBD.NET.Events.EventArgs
|
||||
{
|
||||
public class DataReceivedEventArgs<T> where T : IOBDData
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
public T Data { get; }
|
||||
public DateTime Timestamp { get; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public DataReceivedEventArgs(T data, DateTime timestamp)
|
||||
{
|
||||
this.Data = data;
|
||||
this.Timestamp = timestamp;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
24
OBD.NET/OBD.NET/Events/EventArgs/RawDataReceivedEventArgs.cs
Normal file
24
OBD.NET/OBD.NET/Events/EventArgs/RawDataReceivedEventArgs.cs
Normal file
@ -0,0 +1,24 @@
|
||||
using System;
|
||||
|
||||
namespace OBD.NET.Events.EventArgs
|
||||
{
|
||||
public class RawDataReceivedEventArgs
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
public string Data { get; }
|
||||
public DateTime Timestamp { get; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public RawDataReceivedEventArgs(string data, DateTime timestamp)
|
||||
{
|
||||
this.Data = data;
|
||||
this.Timestamp = timestamp;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
33
OBD.NET/OBD.NET/Events/GenericDataEventManager.cs
Normal file
33
OBD.NET/OBD.NET/Events/GenericDataEventManager.cs
Normal file
@ -0,0 +1,33 @@
|
||||
using System;
|
||||
using OBD.NET.Devices;
|
||||
using OBD.NET.Events.EventArgs;
|
||||
using OBD.NET.OBDData;
|
||||
|
||||
namespace OBD.NET.Events
|
||||
{
|
||||
public class GenericDataEventManager<T> : IDataEventManager where T : IOBDData
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
#endregion
|
||||
|
||||
#region Events
|
||||
|
||||
internal event ELM327.DataReceivedEventHandler<T> DataReceived;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
public void RaiseEvent(object sender, IOBDData data, DateTime timestamp)
|
||||
{
|
||||
DataReceived?.Invoke(sender, new DataReceivedEventArgs<T>((T)data, timestamp));
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
10
OBD.NET/OBD.NET/Events/IDataEventManager.cs
Normal file
10
OBD.NET/OBD.NET/Events/IDataEventManager.cs
Normal file
@ -0,0 +1,10 @@
|
||||
using System;
|
||||
using OBD.NET.OBDData;
|
||||
|
||||
namespace OBD.NET.Events
|
||||
{
|
||||
public interface IDataEventManager
|
||||
{
|
||||
void RaiseEvent(object sender, IOBDData data, DateTime timestamp);
|
||||
}
|
||||
}
|
||||
27
OBD.NET/OBD.NET/Exceptions/SerialException.cs
Normal file
27
OBD.NET/OBD.NET/Exceptions/SerialException.cs
Normal file
@ -0,0 +1,27 @@
|
||||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace OBD.NET.Exceptions
|
||||
{
|
||||
public class SerialException : Exception
|
||||
{
|
||||
#region Constructors
|
||||
|
||||
public SerialException()
|
||||
{ }
|
||||
|
||||
public SerialException(string message)
|
||||
: base(message)
|
||||
{ }
|
||||
|
||||
public SerialException(string message, Exception innerException)
|
||||
: base(message, innerException)
|
||||
{ }
|
||||
|
||||
protected SerialException(SerializationInfo info, StreamingContext context)
|
||||
: base(info, context)
|
||||
{ }
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
47
OBD.NET/OBD.NET/Exceptions/UnexpectedResultException.cs
Normal file
47
OBD.NET/OBD.NET/Exceptions/UnexpectedResultException.cs
Normal file
@ -0,0 +1,47 @@
|
||||
using System;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace OBD.NET.Exceptions
|
||||
{
|
||||
public class UnexpectedResultException : Exception
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
public string Result { get; }
|
||||
public string ExpectedResult { get; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
|
||||
public UnexpectedResultException(string result, string expectedResult)
|
||||
:this($"Unexpected result '{result}'. Expected was '{expectedResult}'", result, expectedResult)
|
||||
{
|
||||
this.Result = result;
|
||||
this.ExpectedResult = expectedResult;
|
||||
}
|
||||
|
||||
public UnexpectedResultException(string message, string result, string expectedResult)
|
||||
: base(message)
|
||||
{
|
||||
this.Result = result;
|
||||
this.ExpectedResult = expectedResult;
|
||||
}
|
||||
|
||||
public UnexpectedResultException(string message, Exception innerException, string result, string expectedResult)
|
||||
: base(message, innerException)
|
||||
{
|
||||
this.Result = result;
|
||||
this.ExpectedResult = expectedResult;
|
||||
}
|
||||
|
||||
protected UnexpectedResultException(SerializationInfo info, StreamingContext context, string result, string expectedResult)
|
||||
: base(info, context)
|
||||
{
|
||||
this.Result = result;
|
||||
this.ExpectedResult = expectedResult;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
24
OBD.NET/OBD.NET/Extensions/HexExtension.cs
Normal file
24
OBD.NET/OBD.NET/Extensions/HexExtension.cs
Normal file
@ -0,0 +1,24 @@
|
||||
using System;
|
||||
|
||||
namespace OBD.NET.Extensions
|
||||
{
|
||||
public static class HexExtension
|
||||
{
|
||||
public static int GetHexVal(this char hex)
|
||||
{
|
||||
return hex - (hex < 58 ? 48 : (hex < 97 ? 55 : 87));
|
||||
}
|
||||
|
||||
public static int GetHexVal(this string hex)
|
||||
{
|
||||
if ((hex.Length % 2) == 1)
|
||||
throw new ArgumentException("The binary key cannot have an odd number of digits");
|
||||
|
||||
int result = 0;
|
||||
foreach (char c in hex)
|
||||
result = (result << 4) + (GetHexVal(c));
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
7
OBD.NET/OBD.NET/Logging/IOBDLogger.cs
Normal file
7
OBD.NET/OBD.NET/Logging/IOBDLogger.cs
Normal file
@ -0,0 +1,7 @@
|
||||
namespace OBD.NET.Logging
|
||||
{
|
||||
public interface IOBDLogger
|
||||
{
|
||||
void WriteLine(string text, OBDLogLevel level);
|
||||
}
|
||||
}
|
||||
10
OBD.NET/OBD.NET/Logging/OBDLogLevel.cs
Normal file
10
OBD.NET/OBD.NET/Logging/OBDLogLevel.cs
Normal file
@ -0,0 +1,10 @@
|
||||
namespace OBD.NET.Logging
|
||||
{
|
||||
public enum OBDLogLevel
|
||||
{
|
||||
None,
|
||||
Error,
|
||||
Verbose,
|
||||
Debug
|
||||
}
|
||||
}
|
||||
@ -45,6 +45,8 @@
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Commands\ATCommand.cs" />
|
||||
<Compile Include="Communication\SerialConnection.cs" />
|
||||
<Compile Include="DataTypes\Degree.cs" />
|
||||
<Compile Include="DataTypes\Minute.cs" />
|
||||
<Compile Include="DataTypes\LitresPerHour.cs" />
|
||||
@ -63,7 +65,19 @@
|
||||
<Compile Include="DataTypes\Percent.cs" />
|
||||
<Compile Include="DataTypes\DegreeCelsius.cs" />
|
||||
<Compile Include="DataTypes\GenericData.cs" />
|
||||
<Compile Include="Devices\SerialDevice.cs" />
|
||||
<Compile Include="Devices\ELM327.cs" />
|
||||
<Compile Include="Devices\STN1170.cs" />
|
||||
<Compile Include="Enums\Mode.cs" />
|
||||
<Compile Include="Events\EventArgs\RawDataReceivedEventArgs.cs" />
|
||||
<Compile Include="Events\EventArgs\DataReceivedEventArgs.cs" />
|
||||
<Compile Include="Events\GenericDataEventManager.cs" />
|
||||
<Compile Include="Events\IDataEventManager.cs" />
|
||||
<Compile Include="Exceptions\SerialException.cs" />
|
||||
<Compile Include="Exceptions\UnexpectedResultException.cs" />
|
||||
<Compile Include="Extensions\HexExtension.cs" />
|
||||
<Compile Include="Logging\IOBDLogger.cs" />
|
||||
<Compile Include="Logging\OBDLogLevel.cs" />
|
||||
<Compile Include="OBDData\20-3F\AbsoluteBarometricPressure.cs" />
|
||||
<Compile Include="OBDData\40-5F\AbsoluteEvapSystemVaporPressure.cs" />
|
||||
<Compile Include="OBDData\40-5F\AbsoluteLoadValue.cs" />
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using OBD.NET.Extensions;
|
||||
|
||||
namespace OBD.NET.OBDData
|
||||
{
|
||||
@ -7,7 +7,7 @@ namespace OBD.NET.OBDData
|
||||
{
|
||||
#region Properties & Fields
|
||||
|
||||
public int PID { get; }
|
||||
public byte PID { get; }
|
||||
private int _length;
|
||||
|
||||
private byte[] _rawData;
|
||||
@ -34,13 +34,13 @@ namespace OBD.NET.OBDData
|
||||
|
||||
#region Constructors
|
||||
|
||||
public AbstractOBDData(int pid, int length)
|
||||
public AbstractOBDData(byte pid, int length)
|
||||
{
|
||||
this.PID = pid;
|
||||
this._length = length;
|
||||
}
|
||||
|
||||
public AbstractOBDData(int pid, int length, byte[] rawData)
|
||||
public AbstractOBDData(byte pid, int length, byte[] rawData)
|
||||
: this(pid, length)
|
||||
{
|
||||
this.RawData = rawData;
|
||||
@ -50,13 +50,16 @@ namespace OBD.NET.OBDData
|
||||
|
||||
#region Methods
|
||||
|
||||
public void Read(Stream stream)
|
||||
public void Load(string data)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (((data.Length % 2) == 1) || ((data.Length / 2) != _length))
|
||||
throw new ArgumentException("The provided data is not valid", nameof(data));
|
||||
|
||||
_rawData = new byte[_length];
|
||||
if (stream.Read(_rawData, 0, _length) != _length)
|
||||
throw new InvalidDataException("Couldn't read enough bytes from the stream");
|
||||
for (int i = 0; i < _length; ++i)
|
||||
_rawData[i] = (byte)((data[i << 1].GetHexVal() << 4) + (data[(i << 1) + 1].GetHexVal()));
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
||||
@ -1,11 +1,9 @@
|
||||
using System.IO;
|
||||
|
||||
namespace OBD.NET.OBDData
|
||||
namespace OBD.NET.OBDData
|
||||
{
|
||||
public interface IOBDData
|
||||
{
|
||||
int PID { get; }
|
||||
byte PID { get; }
|
||||
|
||||
void Read(Stream stream);
|
||||
void Load(string data);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user