mirror of
https://github.com/DarthAffe/OBD.NET.git
synced 2025-12-13 09:18:31 +00:00
Some improvements
This commit is contained in:
parent
5dfac27120
commit
7e0e2447c7
53
OBD.NET/OBD.NET/Commands/STCommand.cs
Normal file
53
OBD.NET/OBD.NET/Commands/STCommand.cs
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
namespace OBD.NET.Commands
|
||||||
|
{
|
||||||
|
public class STCommand
|
||||||
|
{
|
||||||
|
#region Values
|
||||||
|
|
||||||
|
//TODO DarthAffe 19.03.2017: Implement all commands
|
||||||
|
|
||||||
|
internal static readonly STCommand AddPassFilter = new STCommand("STFAP");
|
||||||
|
internal static readonly STCommand AddBlockFilter = new STCommand("STFAB");
|
||||||
|
internal static readonly STCommand AddFlowControlFilter = new STCommand("STFAFC");
|
||||||
|
internal static readonly STCommand ClearPassFilters = new STCommand("STFCP");
|
||||||
|
internal static readonly STCommand ClearBlockFilters = new STCommand("STFCB");
|
||||||
|
internal static readonly STCommand ClearFlowControlFilters = new STCommand("STFCFC");
|
||||||
|
internal static readonly STCommand Monitor = new STCommand("STM");
|
||||||
|
internal static readonly STCommand MonitorAll = new STCommand("STMA");
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Properties & Fields
|
||||||
|
|
||||||
|
public string Command { get; }
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
protected STCommand(string command)
|
||||||
|
{
|
||||||
|
this.Command = command;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return Command;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Operators
|
||||||
|
|
||||||
|
public static implicit operator string(STCommand command)
|
||||||
|
{
|
||||||
|
return command.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
163
OBD.NET/OBD.NET/Communication/EnhancedSerialPort.cs
Normal file
163
OBD.NET/OBD.NET/Communication/EnhancedSerialPort.cs
Normal file
@ -0,0 +1,163 @@
|
|||||||
|
// Copyright 2013 Antanas Veiverys www.veiverys.com
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.IO;
|
||||||
|
using System.IO.Ports;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
// Source: http://antanas.veiverys.com/mono-serialport-datareceived-event-workaround-using-a-derived-class/
|
||||||
|
namespace OBD.NET.Communication
|
||||||
|
{
|
||||||
|
[DesignerCategory("Code")]
|
||||||
|
public class EnhancedSerialPort : SerialPort
|
||||||
|
{
|
||||||
|
#region Properties & Fields
|
||||||
|
|
||||||
|
// private member access via reflection
|
||||||
|
private int _fd;
|
||||||
|
private FieldInfo _disposedFieldInfo;
|
||||||
|
private object _dataReceived;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region DLLImports
|
||||||
|
|
||||||
|
[DllImport("MonoPosixHelper", SetLastError = true)]
|
||||||
|
private static extern bool poll_serial(int fd, out int error, int timeout);
|
||||||
|
|
||||||
|
[DllImport("libc")]
|
||||||
|
private static extern IntPtr strerror(int errnum);
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
public EnhancedSerialPort()
|
||||||
|
: base()
|
||||||
|
{ }
|
||||||
|
|
||||||
|
public EnhancedSerialPort(IContainer container)
|
||||||
|
: base(container)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
public EnhancedSerialPort(string portName)
|
||||||
|
: base(portName)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
public EnhancedSerialPort(string portName, int baudRate)
|
||||||
|
: base(portName, baudRate)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
public EnhancedSerialPort(string portName, int baudRate, Parity parity)
|
||||||
|
: base(portName, baudRate, parity)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
public EnhancedSerialPort(string portName, int baudRate, Parity parity, int dataBits)
|
||||||
|
: base(portName, baudRate, parity, dataBits)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
public EnhancedSerialPort(string portName, int baudRate, Parity parity, int dataBits, StopBits stopBits)
|
||||||
|
: base(portName, baudRate, parity, dataBits, stopBits)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
public new void Open()
|
||||||
|
{
|
||||||
|
base.Open();
|
||||||
|
|
||||||
|
if (!IsWindows)
|
||||||
|
{
|
||||||
|
FieldInfo fieldInfo = BaseStream.GetType().GetField("fd", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||||
|
_fd = (int)fieldInfo.GetValue(BaseStream);
|
||||||
|
_disposedFieldInfo = BaseStream.GetType().GetField("disposed", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||||
|
fieldInfo = typeof(SerialPort).GetField("data_received", BindingFlags.Instance | BindingFlags.NonPublic);
|
||||||
|
_dataReceived = fieldInfo.GetValue(this);
|
||||||
|
|
||||||
|
new System.Threading.Thread(EventThreadFunction).Start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsWindows
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
PlatformID id = Environment.OSVersion.Platform;
|
||||||
|
return (id == PlatformID.Win32Windows) || (id == PlatformID.Win32NT); // WinCE not supported
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EventThreadFunction()
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Stream stream = BaseStream;
|
||||||
|
if (stream == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (Poll(stream, ReadTimeout))
|
||||||
|
OnDataReceived(null);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} while (IsOpen);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnDataReceived(SerialDataReceivedEventArgs args)
|
||||||
|
{
|
||||||
|
SerialDataReceivedEventHandler handler = Events[_dataReceived] as SerialDataReceivedEventHandler;
|
||||||
|
handler?.Invoke(this, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool Poll(Stream stream, int timeout)
|
||||||
|
{
|
||||||
|
CheckDisposed(stream);
|
||||||
|
if (IsOpen == false)
|
||||||
|
throw new Exception("port is closed");
|
||||||
|
int error;
|
||||||
|
|
||||||
|
bool pollResult = poll_serial(_fd, out error, ReadTimeout);
|
||||||
|
if (error == -1)
|
||||||
|
ThrowIOException();
|
||||||
|
|
||||||
|
return pollResult;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void ThrowIOException()
|
||||||
|
{
|
||||||
|
int errnum = Marshal.GetLastWin32Error();
|
||||||
|
string errorMessage = Marshal.PtrToStringAnsi(strerror(errnum));
|
||||||
|
|
||||||
|
throw new IOException(errorMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CheckDisposed(Stream stream)
|
||||||
|
{
|
||||||
|
bool disposed = (bool)_disposedFieldInfo.GetValue(stream);
|
||||||
|
if (disposed)
|
||||||
|
throw new ObjectDisposedException(stream.GetType().FullName);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,5 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.IO.Ports;
|
using System.IO.Ports;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
namespace OBD.NET.Communication
|
namespace OBD.NET.Communication
|
||||||
{
|
{
|
||||||
@ -7,24 +9,39 @@ namespace OBD.NET.Communication
|
|||||||
{
|
{
|
||||||
#region Properties & Fields
|
#region Properties & Fields
|
||||||
|
|
||||||
private readonly SerialPort _serialPort;
|
private readonly EnhancedSerialPort _serialPort;
|
||||||
|
private readonly int _timeout;
|
||||||
|
|
||||||
public bool IsOpen => _serialPort.IsOpen;
|
public bool IsOpen => _serialPort?.IsOpen ?? false;
|
||||||
|
|
||||||
|
private readonly byte[] _readBuffer = new byte[1024];
|
||||||
|
private readonly StringBuilder _lineBuffer = new StringBuilder();
|
||||||
|
|
||||||
|
private readonly AutoResetEvent _hasPrompt = new AutoResetEvent(true);
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Events
|
||||||
|
|
||||||
|
public event EventHandler<string> MessageReceived;
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Constructors
|
#region Constructors
|
||||||
|
|
||||||
public SerialConnection(string port, int baudRate = 38400, Parity parity = Parity.None,
|
public SerialConnection(string port, int baudRate = 38400, Parity parity = Parity.None, StopBits stopBits = StopBits.One,
|
||||||
StopBits stopBits = StopBits.One, Handshake handshake = Handshake.None, int timeout = 5000)
|
Handshake handshake = Handshake.None, int timeout = 5000)
|
||||||
{
|
{
|
||||||
_serialPort = new SerialPort(port, baudRate, parity)
|
this._timeout = timeout;
|
||||||
|
_serialPort = new EnhancedSerialPort(port, baudRate, parity)
|
||||||
{
|
{
|
||||||
StopBits = stopBits,
|
StopBits = stopBits,
|
||||||
Handshake = handshake,
|
Handshake = handshake,
|
||||||
ReadTimeout = timeout,
|
ReadTimeout = timeout,
|
||||||
WriteTimeout = timeout
|
WriteTimeout = timeout
|
||||||
};
|
};
|
||||||
|
|
||||||
|
_serialPort.DataReceived += SerialPortOnDataReceived;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
@ -34,16 +51,51 @@ namespace OBD.NET.Communication
|
|||||||
public void Connect()
|
public void Connect()
|
||||||
{
|
{
|
||||||
_serialPort.Open();
|
_serialPort.Open();
|
||||||
|
Thread.Sleep(5000);
|
||||||
|
Write("\r");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Write(string text)
|
public void Write(string text)
|
||||||
{
|
{
|
||||||
|
if (!_hasPrompt.WaitOne(_timeout))
|
||||||
|
throw new TimeoutException("No prompt received");
|
||||||
|
|
||||||
_serialPort.Write(text);
|
_serialPort.Write(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte ReadByte()
|
private void SerialPortOnDataReceived(object sender, SerialDataReceivedEventArgs serialDataReceivedEventArgs)
|
||||||
{
|
{
|
||||||
return (byte)_serialPort.ReadByte();
|
int count = _serialPort.Read(_readBuffer, 0, _serialPort.BytesToRead);
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
char c = (char)_readBuffer[i];
|
||||||
|
switch (c)
|
||||||
|
{
|
||||||
|
case '\r':
|
||||||
|
FinishLine();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '>':
|
||||||
|
_hasPrompt.Set();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '\n':
|
||||||
|
case (char)0x00:
|
||||||
|
break; // ignore
|
||||||
|
|
||||||
|
default:
|
||||||
|
_lineBuffer.Append(c);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void FinishLine()
|
||||||
|
{
|
||||||
|
string line = _lineBuffer.ToString();
|
||||||
|
_lineBuffer.Clear();
|
||||||
|
|
||||||
|
MessageReceived?.Invoke(this, line);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
|
|||||||
@ -23,8 +23,6 @@ namespace OBD.NET.Devices
|
|||||||
|
|
||||||
protected Mode Mode { get; set; } = Mode.ShowCurrentData; //TODO DarthAffe 26.06.2016: Implement different modes
|
protected Mode Mode { get; set; } = Mode.ShowCurrentData; //TODO DarthAffe 26.06.2016: Implement different modes
|
||||||
|
|
||||||
protected override string ExpectedNoData => @"(NO DATA)|(SEARCHING)|(STOP)|\?";
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Events
|
#region Events
|
||||||
@ -51,62 +49,88 @@ namespace OBD.NET.Devices
|
|||||||
base.Initialize();
|
base.Initialize();
|
||||||
|
|
||||||
Logger?.WriteLine("Initializing ...", OBDLogLevel.Debug);
|
Logger?.WriteLine("Initializing ...", OBDLogLevel.Debug);
|
||||||
int repeats = 3;
|
|
||||||
bool repeat = true;
|
try
|
||||||
while (repeat)
|
|
||||||
{
|
{
|
||||||
try
|
Logger?.WriteLine("Resetting Device ...", OBDLogLevel.Debug);
|
||||||
{
|
SendCommand(ATCommand.ResetDevice);
|
||||||
Logger?.WriteLine("Resetting Device ...", OBDLogLevel.Debug);
|
Thread.Sleep(1000);
|
||||||
SendCommand(ATCommand.ResetDevice);
|
|
||||||
Thread.Sleep(1000);
|
|
||||||
|
|
||||||
Logger?.WriteLine("Turning Echo Off ...", OBDLogLevel.Debug);
|
Logger?.WriteLine("Turning Echo Off ...", OBDLogLevel.Debug);
|
||||||
SendCommand(ATCommand.EchoOff);
|
SendCommand(ATCommand.EchoOff);
|
||||||
|
|
||||||
Logger?.WriteLine("Turning Linefeeds Off ...", OBDLogLevel.Debug);
|
Logger?.WriteLine("Turning Linefeeds Off ...", OBDLogLevel.Debug);
|
||||||
SendCommand(ATCommand.LinefeedsOff);
|
SendCommand(ATCommand.LinefeedsOff);
|
||||||
|
|
||||||
Logger?.WriteLine("Turning Headers Off ...", OBDLogLevel.Debug);
|
Logger?.WriteLine("Turning Headers Off ...", OBDLogLevel.Debug);
|
||||||
SendCommand(ATCommand.HeadersOff);
|
SendCommand(ATCommand.HeadersOff);
|
||||||
|
|
||||||
Logger?.WriteLine("Turning Spaced Off ...", OBDLogLevel.Debug);
|
Logger?.WriteLine("Turning Spaced Off ...", OBDLogLevel.Debug);
|
||||||
SendCommand(ATCommand.PrintSpacesOff);
|
SendCommand(ATCommand.PrintSpacesOff);
|
||||||
|
|
||||||
Logger?.WriteLine("Setting the Protocol to 'Auto' ...", OBDLogLevel.Debug);
|
Logger?.WriteLine("Setting the Protocol to 'Auto' ...", OBDLogLevel.Debug);
|
||||||
SendCommand(ATCommand.SetProtocolAuto);
|
SendCommand(ATCommand.SetProtocolAuto);
|
||||||
|
|
||||||
repeat = false;
|
Thread.Sleep(1000);
|
||||||
}
|
}
|
||||||
// DarthAffe 21.02.2017: This seems to happen sometimes, i don't know why - just retry.
|
// DarthAffe 21.02.2017: This seems to happen sometimes, i don't know why - just retry.
|
||||||
catch (TimeoutException)
|
catch
|
||||||
{
|
{
|
||||||
if (repeats > 0)
|
Logger?.WriteLine("Failed to initialize the device!", OBDLogLevel.Error);
|
||||||
{
|
throw;
|
||||||
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)
|
public virtual void SendCommand(ATCommand command)
|
||||||
{
|
{
|
||||||
SendCommand(command.Command, command.ExpectedResult);
|
SendCommand(command.Command);
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual T RequestData<T>()
|
public virtual void RequestData<T>()
|
||||||
where T : class, IOBDData, new()
|
where T : class, IOBDData, new()
|
||||||
{
|
{
|
||||||
Logger?.WriteLine("Requesting Type " + typeof(T).Name + " ...", OBDLogLevel.Debug);
|
Logger?.WriteLine("Requesting Type " + typeof(T).Name + " ...", OBDLogLevel.Debug);
|
||||||
|
|
||||||
|
byte pid = ResolvePid<T>();
|
||||||
|
RequestData(pid);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void RequestData(byte pid)
|
||||||
|
{
|
||||||
|
Logger?.WriteLine("Requesting PID " + pid.ToString("X2") + " ...", OBDLogLevel.Debug);
|
||||||
|
SendCommand(((byte)Mode).ToString("X2") + pid.ToString("X2"));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void ProcessMessage(string message)
|
||||||
|
{
|
||||||
|
DateTime timestamp = DateTime.Now;
|
||||||
|
|
||||||
|
RawDataReceived?.Invoke(this, new RawDataReceivedEventArgs(message, timestamp));
|
||||||
|
|
||||||
|
if (message.Length > 4)
|
||||||
|
if (message[0] == '4')
|
||||||
|
{
|
||||||
|
byte mode = (byte)message[1].GetHexVal();
|
||||||
|
if (mode == (byte)Mode)
|
||||||
|
{
|
||||||
|
byte pid = (byte)message.Substring(2, 2).GetHexVal();
|
||||||
|
Type dataType;
|
||||||
|
if (DataTypeCache.TryGetValue(pid, out dataType))
|
||||||
|
{
|
||||||
|
IOBDData obdData = (IOBDData)Activator.CreateInstance(dataType);
|
||||||
|
obdData.Load(message.Substring(4, message.Length - 4));
|
||||||
|
|
||||||
|
IDataEventManager dataEventManager;
|
||||||
|
if (_dataReceivedEventHandlers.TryGetValue(dataType, out dataEventManager))
|
||||||
|
dataEventManager.RaiseEvent(this, obdData, timestamp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual byte ResolvePid<T>()
|
||||||
|
where T : class, IOBDData, new()
|
||||||
|
{
|
||||||
byte pid;
|
byte pid;
|
||||||
if (!PidCache.TryGetValue(typeof(T), out pid))
|
if (!PidCache.TryGetValue(typeof(T), out pid))
|
||||||
{
|
{
|
||||||
@ -115,48 +139,8 @@ namespace OBD.NET.Devices
|
|||||||
PidCache.Add(typeof(T), pid);
|
PidCache.Add(typeof(T), pid);
|
||||||
DataTypeCache.Add(pid, typeof(T));
|
DataTypeCache.Add(pid, typeof(T));
|
||||||
}
|
}
|
||||||
return RequestData(pid) as T;
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual IOBDData RequestData(byte pid)
|
return 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()
|
public override void Dispose()
|
||||||
@ -166,11 +150,17 @@ namespace OBD.NET.Devices
|
|||||||
|
|
||||||
public void Dispose(bool sendCloseProtocol)
|
public void Dispose(bool sendCloseProtocol)
|
||||||
{
|
{
|
||||||
if (sendCloseProtocol)
|
try
|
||||||
{
|
{
|
||||||
SendCommand(ATCommand.CloseProtocol);
|
if (sendCloseProtocol)
|
||||||
Thread.Sleep(500);
|
{
|
||||||
|
SendCommand(ATCommand.CloseProtocol);
|
||||||
|
Thread.Sleep(500);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
catch { }
|
||||||
|
|
||||||
|
_dataReceivedEventHandlers = null;
|
||||||
|
|
||||||
base.Dispose();
|
base.Dispose();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,9 +1,4 @@
|
|||||||
using System;
|
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.Communication;
|
||||||
using OBD.NET.Exceptions;
|
using OBD.NET.Exceptions;
|
||||||
using OBD.NET.Logging;
|
using OBD.NET.Logging;
|
||||||
@ -14,26 +9,22 @@ namespace OBD.NET.Devices
|
|||||||
{
|
{
|
||||||
#region Properties & Fields
|
#region Properties & Fields
|
||||||
|
|
||||||
private readonly byte[] _responseBuffer = new byte[512];
|
|
||||||
|
|
||||||
protected IOBDLogger Logger { get; }
|
protected IOBDLogger Logger { get; }
|
||||||
|
|
||||||
protected SerialConnection Connection { get; }
|
protected SerialConnection Connection { get; }
|
||||||
protected char Prompt { get; set; }
|
|
||||||
protected char Terminator { get; set; }
|
protected char Terminator { get; set; }
|
||||||
|
|
||||||
protected abstract string ExpectedNoData { get; }
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Constructors
|
#region Constructors
|
||||||
|
|
||||||
protected SerialDevice(SerialConnection connection, char prompt = '>', char terminator = '\r', IOBDLogger logger = null)
|
protected SerialDevice(SerialConnection connection, char terminator = '\r', IOBDLogger logger = null)
|
||||||
{
|
{
|
||||||
this.Connection = connection;
|
this.Connection = connection;
|
||||||
this.Prompt = prompt;
|
|
||||||
this.Terminator = terminator;
|
this.Terminator = terminator;
|
||||||
this.Logger = logger;
|
this.Logger = logger;
|
||||||
|
|
||||||
|
connection.MessageReceived += SerialMessageReceived;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
@ -52,34 +43,16 @@ namespace OBD.NET.Devices
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
Logger?.WriteLine("Opened Serial-Connection!", OBDLogLevel.Debug);
|
Logger?.WriteLine("Opened Serial-Connection!", OBDLogLevel.Debug);
|
||||||
|
|
||||||
Thread.Sleep(500);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual string SendCommand(string command, string expectedResult = null)
|
protected virtual void SendCommand(string command)
|
||||||
{
|
{
|
||||||
if (!Connection.IsOpen) return null;
|
if (!Connection.IsOpen) return;
|
||||||
|
|
||||||
command = PrepareCommand(command);
|
command = PrepareCommand(command);
|
||||||
|
|
||||||
Logger?.WriteLine("Writing Command: '" + command.Replace('\r', '\'') + "'", OBDLogLevel.Verbose);
|
Logger?.WriteLine("Writing Command: '" + command.Replace('\r', '\'') + "'", OBDLogLevel.Verbose);
|
||||||
Connection.Write(command);
|
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)
|
protected virtual string PrepareCommand(string command)
|
||||||
@ -92,22 +65,16 @@ namespace OBD.NET.Devices
|
|||||||
return command;
|
return command;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual List<string> ReadResponse()
|
private void SerialMessageReceived(object sender, string message)
|
||||||
{
|
{
|
||||||
byte b;
|
if (string.IsNullOrWhiteSpace(message)) return;
|
||||||
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: '" + message + "'", OBDLogLevel.Verbose);
|
||||||
Logger?.WriteLine("Response: '" + response.Replace("\r", "<\\r>").Replace("\n", "<\\n>") + "'", OBDLogLevel.Verbose);
|
ProcessMessage(message.Trim());
|
||||||
return response.Split('\r').Select(x => x.Replace("\r", string.Empty).Replace("\n", string.Empty).Trim()).Where(x => !string.IsNullOrWhiteSpace(x)).ToList();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected abstract void ProcessMessage(string message);
|
||||||
|
|
||||||
public virtual void Dispose()
|
public virtual void Dispose()
|
||||||
{
|
{
|
||||||
Connection?.Dispose();
|
Connection?.Dispose();
|
||||||
|
|||||||
@ -45,7 +45,9 @@
|
|||||||
<Reference Include="System.Xml" />
|
<Reference Include="System.Xml" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Compile Include="Commands\STCommand.cs" />
|
||||||
<Compile Include="Commands\ATCommand.cs" />
|
<Compile Include="Commands\ATCommand.cs" />
|
||||||
|
<Compile Include="Communication\EnhancedSerialPort.cs" />
|
||||||
<Compile Include="Communication\SerialConnection.cs" />
|
<Compile Include="Communication\SerialConnection.cs" />
|
||||||
<Compile Include="DataTypes\Degree.cs" />
|
<Compile Include="DataTypes\Degree.cs" />
|
||||||
<Compile Include="DataTypes\Minute.cs" />
|
<Compile Include="DataTypes\Minute.cs" />
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user