mirror of
https://github.com/DarthAffe/OBD.NET.git
synced 2025-12-13 09:18:31 +00:00
refactoring SerialDevice
This commit is contained in:
parent
9d6d1cd36b
commit
02bd8630a2
@ -29,13 +29,13 @@ namespace OBD.NET.Communication
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Connects the serial port.
|
/// Connects the serial port.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
bool Connect();
|
void Connect();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Connects the serial port async
|
/// Connects the serial port async
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
Task<bool> ConnectAsync();
|
Task ConnectAsync();
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@ -80,51 +80,11 @@ namespace OBD.NET.Devices
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async Task InitializeAsync()
|
|
||||||
{
|
|
||||||
await base.InitializeAsync();
|
|
||||||
|
|
||||||
Logger?.WriteLine("Initializing ...", OBDLogLevel.Debug);
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Logger?.WriteLine("Resetting Device ...", OBDLogLevel.Debug);
|
|
||||||
await SendCommandAsync(ATCommand.ResetDevice);
|
|
||||||
Logger?.WriteLine("Turning Echo Off ...", OBDLogLevel.Debug);
|
|
||||||
await SendCommandAsync(ATCommand.EchoOff);
|
|
||||||
|
|
||||||
Logger?.WriteLine("Turning Linefeeds Off ...", OBDLogLevel.Debug);
|
|
||||||
await SendCommandAsync(ATCommand.LinefeedsOff);
|
|
||||||
|
|
||||||
Logger?.WriteLine("Turning Headers Off ...", OBDLogLevel.Debug);
|
|
||||||
await SendCommandAsync(ATCommand.HeadersOff);
|
|
||||||
|
|
||||||
Logger?.WriteLine("Turning Spaced Off ...", OBDLogLevel.Debug);
|
|
||||||
await SendCommandAsync(ATCommand.PrintSpacesOff);
|
|
||||||
|
|
||||||
Logger?.WriteLine("Setting the Protocol to 'Auto' ...", OBDLogLevel.Debug);
|
|
||||||
await SendCommandAsync(ATCommand.SetProtocolAuto); //TODO rewrite
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
// DarthAffe 21.02.2017: This seems to happen sometimes, i don't know why - just retry.
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
Logger?.WriteLine("Failed to initialize the device!", OBDLogLevel.Error);
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual void SendCommand(ATCommand command)
|
public virtual void SendCommand(ATCommand command)
|
||||||
{
|
{
|
||||||
SendCommand(command.Command);
|
SendCommand(command.Command);
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual async Task SendCommandAsync(ATCommand command)
|
|
||||||
{
|
|
||||||
await SendCommandAsync(command.Command);
|
|
||||||
}
|
|
||||||
|
|
||||||
public virtual void RequestData<T>()
|
public virtual void RequestData<T>()
|
||||||
where T : class, IOBDData, new()
|
where T : class, IOBDData, new()
|
||||||
{
|
{
|
||||||
@ -134,27 +94,12 @@ namespace OBD.NET.Devices
|
|||||||
RequestData(pid);
|
RequestData(pid);
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual async Task RequestDataAsync<T>()
|
|
||||||
where T : class, IOBDData, new()
|
|
||||||
{
|
|
||||||
Logger?.WriteLine("Requesting Type " + typeof(T).Name + " ...", OBDLogLevel.Debug);
|
|
||||||
|
|
||||||
byte pid = ResolvePid<T>();
|
|
||||||
await RequestDataAsync(pid);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected virtual void RequestData(byte pid)
|
protected virtual void RequestData(byte pid)
|
||||||
{
|
{
|
||||||
Logger?.WriteLine("Requesting PID " + pid.ToString("X2") + " ...", OBDLogLevel.Debug);
|
Logger?.WriteLine("Requesting PID " + pid.ToString("X2") + " ...", OBDLogLevel.Debug);
|
||||||
SendCommand(((byte)Mode).ToString("X2") + pid.ToString("X2"));
|
SendCommand(((byte)Mode).ToString("X2") + pid.ToString("X2"));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual async Task RequestDataAsync(byte pid)
|
|
||||||
{
|
|
||||||
Logger?.WriteLine("Requesting PID " + pid.ToString("X2") + " ...", OBDLogLevel.Debug);
|
|
||||||
await SendCommandAsync(((byte)Mode).ToString("X2") + pid.ToString("X2"));
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void ProcessMessage(string message)
|
protected override void ProcessMessage(string message)
|
||||||
{
|
{
|
||||||
DateTime timestamp = DateTime.Now;
|
DateTime timestamp = DateTime.Now;
|
||||||
|
|||||||
@ -4,6 +4,9 @@ using OBD.NET.Exceptions;
|
|||||||
using OBD.NET.Logging;
|
using OBD.NET.Logging;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using OBD.NET.Common.Communication.EventArgs;
|
using OBD.NET.Common.Communication.EventArgs;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
|
||||||
namespace OBD.NET.Devices
|
namespace OBD.NET.Devices
|
||||||
{
|
{
|
||||||
@ -12,8 +15,15 @@ namespace OBD.NET.Devices
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class SerialDevice : IDisposable
|
public abstract class SerialDevice : IDisposable
|
||||||
{
|
{
|
||||||
private System.Collections.Generic.Queue<string> commandQueue;
|
private BlockingCollection<string> commandQueue;
|
||||||
|
|
||||||
|
private readonly StringBuilder _lineBuffer = new StringBuilder();
|
||||||
|
|
||||||
|
private readonly AutoResetEvent commandFinishedEvent = new AutoResetEvent(true);
|
||||||
|
|
||||||
|
private Task commandWorkerTask;
|
||||||
|
private CancellationTokenSource commandCancellationToken;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Logger instance
|
/// Logger instance
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -34,7 +44,7 @@ namespace OBD.NET.Devices
|
|||||||
|
|
||||||
private SerialDevice()
|
private SerialDevice()
|
||||||
{
|
{
|
||||||
commandQueue = new System.Collections.Generic.Queue<string>();
|
commandQueue = new BlockingCollection<string>();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected SerialDevice(ISerialConnection connection, char terminator = '\r', IOBDLogger logger = null)
|
protected SerialDevice(ISerialConnection connection, char terminator = '\r', IOBDLogger logger = null)
|
||||||
@ -49,12 +59,7 @@ namespace OBD.NET.Devices
|
|||||||
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
private void OnDataReceived(object sender, DataReceivedEventArgs e)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#region Methods
|
#region Methods
|
||||||
|
|
||||||
|
|
||||||
@ -63,22 +68,21 @@ namespace OBD.NET.Devices
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual void Initialize()
|
public virtual void Initialize()
|
||||||
{
|
{
|
||||||
|
|
||||||
Connection.Connect();
|
Connection.Connect();
|
||||||
CheckConnection();
|
CheckConnectionAndStartWorker();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes the device async
|
/// Initializes the device asynchronously
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public virtual async Task InitializeAsync()
|
public virtual async Task InitializeAsync()
|
||||||
{
|
{
|
||||||
await Connection.ConnectAsync();
|
await Connection.ConnectAsync();
|
||||||
CheckConnection();
|
CheckConnectionAndStartWorker();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CheckConnection()
|
private void CheckConnectionAndStartWorker()
|
||||||
{
|
{
|
||||||
if (!Connection.IsOpen)
|
if (!Connection.IsOpen)
|
||||||
{
|
{
|
||||||
@ -86,23 +90,37 @@ namespace OBD.NET.Devices
|
|||||||
throw new SerialException("Failed to open Serial-Connection.");
|
throw new SerialException("Failed to open Serial-Connection.");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
Logger?.WriteLine("Opened Serial-Connection!", OBDLogLevel.Debug);
|
Logger?.WriteLine("Opened Serial-Connection!", OBDLogLevel.Debug);
|
||||||
|
}
|
||||||
|
|
||||||
|
commandWorkerTask = Task.Factory.StartNew(CommandWorker);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void CommandWorker()
|
||||||
|
{
|
||||||
|
while (!commandCancellationToken.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
string command = null;
|
||||||
|
commandQueue.TryTake(out command, Timeout.Infinite, commandCancellationToken.Token);
|
||||||
|
Logger?.WriteLine("Writing Command: '" + command.Replace('\r', '\'') + "'", OBDLogLevel.Verbose);
|
||||||
|
Connection.Write(Encoding.ASCII.GetBytes(command));
|
||||||
|
|
||||||
|
//wait for command to finish
|
||||||
|
commandFinishedEvent.WaitOne();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected virtual void SendCommand(string command)
|
protected virtual void SendCommand(string command)
|
||||||
{
|
{
|
||||||
if (!Connection.IsOpen)
|
if (!Connection.IsOpen)
|
||||||
{
|
{
|
||||||
throw new InvalidOperationException("Not connected");
|
throw new InvalidOperationException("Not connected");
|
||||||
}
|
}
|
||||||
|
|
||||||
command = PrepareCommand(command);
|
command = PrepareCommand(command);
|
||||||
Logger?.WriteLine("Queuing Command: '" + command.Replace('\r', '\'') + "'", OBDLogLevel.Verbose);
|
Logger?.WriteLine("Queuing Command: '" + command.Replace('\r', '\'') + "'", OBDLogLevel.Verbose);
|
||||||
commandQueue.Enqueue(command);
|
commandQueue.Add(command);
|
||||||
// Logger?.WriteLine("Writing Command: '" + command.Replace('\r', '\'') + "'", OBDLogLevel.Verbose);
|
|
||||||
// Connection.Write(command);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -120,6 +138,40 @@ namespace OBD.NET.Devices
|
|||||||
return command;
|
return command;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnDataReceived(object sender, DataReceivedEventArgs e)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < e.Count; i++)
|
||||||
|
{
|
||||||
|
char c = (char)e.Data[i];
|
||||||
|
switch (c)
|
||||||
|
{
|
||||||
|
case '\r':
|
||||||
|
FinishLine();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '>':
|
||||||
|
commandFinishedEvent.Set();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '\n':
|
||||||
|
case (char)0x00:
|
||||||
|
break; // ignore
|
||||||
|
|
||||||
|
default:
|
||||||
|
_lineBuffer.Append(c);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void FinishLine()
|
||||||
|
{
|
||||||
|
string line = _lineBuffer.ToString();
|
||||||
|
_lineBuffer.Clear();
|
||||||
|
ProcessMessage(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private void SerialMessageReceived(object sender, string message)
|
private void SerialMessageReceived(object sender, string message)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(message)) return;
|
if (string.IsNullOrWhiteSpace(message)) return;
|
||||||
|
|||||||
20
OBD.NET/OBD.NET.Common/Logging/TraceLogger.cs
Normal file
20
OBD.NET/OBD.NET.Common/Logging/TraceLogger.cs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
using OBD.NET.Logging;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace OBD.NET.Common.Logging
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Simple debug logger
|
||||||
|
/// </summary>
|
||||||
|
/// <seealso cref="OBD.NET.Logging.IOBDLogger" />
|
||||||
|
public class OBDDebugLogger : IOBDLogger
|
||||||
|
{
|
||||||
|
public void WriteLine(string text, OBDLogLevel level)
|
||||||
|
{
|
||||||
|
Debug.WriteLine($"{level}: {text}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -3,6 +3,7 @@ using System.Runtime.InteropServices.WindowsRuntime;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using OBD.NET.Common.Communication.EventArgs;
|
||||||
using Windows.Devices.Bluetooth.Rfcomm;
|
using Windows.Devices.Bluetooth.Rfcomm;
|
||||||
using Windows.Networking.Sockets;
|
using Windows.Networking.Sockets;
|
||||||
using Windows.Storage.Streams;
|
using Windows.Storage.Streams;
|
||||||
@ -16,8 +17,7 @@ namespace OBD.NET.Communication
|
|||||||
private DataWriter _writer;
|
private DataWriter _writer;
|
||||||
|
|
||||||
private readonly byte[] _readBuffer = new byte[1024];
|
private readonly byte[] _readBuffer = new byte[1024];
|
||||||
private readonly StringBuilder _lineBuffer = new StringBuilder();
|
|
||||||
|
|
||||||
private CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource();
|
private CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource();
|
||||||
private Task _readerTask;
|
private Task _readerTask;
|
||||||
|
|
||||||
@ -32,7 +32,7 @@ namespace OBD.NET.Communication
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Occurs when a full line was received
|
/// Occurs when a full line was received
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public event EventHandler<string> MessageReceived;
|
public event EventHandler<DataReceivedEventArgs> DataReceived;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Connects the serial port.
|
/// Connects the serial port.
|
||||||
@ -74,7 +74,7 @@ namespace OBD.NET.Communication
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="text">The text.</param>
|
/// <param name="text">The text.</param>
|
||||||
/// <exception cref="System.NotImplementedException">Synchronous operations not supported</exception>
|
/// <exception cref="System.NotImplementedException">Synchronous operations not supported</exception>
|
||||||
public void Write(string text)
|
public void Write(byte[] data)
|
||||||
{
|
{
|
||||||
throw new NotImplementedException("Synchronous operations not supported");
|
throw new NotImplementedException("Synchronous operations not supported");
|
||||||
}
|
}
|
||||||
@ -84,9 +84,9 @@ namespace OBD.NET.Communication
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="text">The text.</param>
|
/// <param name="text">The text.</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public async Task WriteAsync(string text)
|
public async Task WriteAsync(byte[] data)
|
||||||
{
|
{
|
||||||
_writer.WriteString(text);
|
_writer.WriteBytes(data);
|
||||||
await _writer.StoreAsync();
|
await _writer.StoreAsync();
|
||||||
await _writer.FlushAsync();
|
await _writer.FlushAsync();
|
||||||
}
|
}
|
||||||
@ -107,38 +107,10 @@ namespace OBD.NET.Communication
|
|||||||
|
|
||||||
private void SerialPortOnDataReceived(IBuffer buffer)
|
private void SerialPortOnDataReceived(IBuffer buffer)
|
||||||
{
|
{
|
||||||
|
DataReceived?.Invoke(this, new DataReceivedEventArgs((int)buffer.Length, _readBuffer));
|
||||||
for (uint i = 0; i < buffer.Length; i++)
|
|
||||||
{
|
|
||||||
char c = (char)buffer.GetByte(i);
|
|
||||||
switch (c)
|
|
||||||
{
|
|
||||||
case '\r':
|
|
||||||
FinishLine();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case '>':
|
|
||||||
continue; //ignore
|
|
||||||
|
|
||||||
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()
|
||||||
{
|
{
|
||||||
_cancellationTokenSource?.Cancel();
|
_cancellationTokenSource?.Cancel();
|
||||||
@ -146,6 +118,5 @@ namespace OBD.NET.Communication
|
|||||||
_socket?.Dispose();
|
_socket?.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,6 +3,7 @@ using System.IO.Ports;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using OBD.NET.Common.Communication.EventArgs;
|
||||||
|
|
||||||
namespace OBD.NET.Communication
|
namespace OBD.NET.Communication
|
||||||
{
|
{
|
||||||
@ -24,7 +25,7 @@ namespace OBD.NET.Communication
|
|||||||
|
|
||||||
#region Events
|
#region Events
|
||||||
|
|
||||||
public event EventHandler<string> MessageReceived;
|
public event EventHandler<DataReceivedEventArgs> DataReceived;
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@ -52,53 +53,15 @@ namespace OBD.NET.Communication
|
|||||||
public void Connect()
|
public void Connect()
|
||||||
{
|
{
|
||||||
_serialPort.Open();
|
_serialPort.Open();
|
||||||
Thread.Sleep(5000);
|
|
||||||
Write("\r");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Write(string text)
|
|
||||||
{
|
|
||||||
if (!_hasPrompt.WaitOne(_timeout))
|
|
||||||
throw new TimeoutException("No prompt received");
|
|
||||||
|
|
||||||
_serialPort.Write(text);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SerialPortOnDataReceived(object sender, SerialDataReceivedEventArgs serialDataReceivedEventArgs)
|
private void SerialPortOnDataReceived(object sender, SerialDataReceivedEventArgs serialDataReceivedEventArgs)
|
||||||
{
|
{
|
||||||
int count = _serialPort.Read(_readBuffer, 0, _serialPort.BytesToRead);
|
int count = _serialPort.Read(_readBuffer, 0, _serialPort.BytesToRead);
|
||||||
for (int i = 0; i < count; i++)
|
DataReceived?.Invoke(this,new DataReceivedEventArgs(count, _readBuffer));
|
||||||
{
|
|
||||||
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()
|
||||||
{
|
{
|
||||||
_serialPort?.Dispose();
|
_serialPort?.Dispose();
|
||||||
@ -109,11 +72,19 @@ namespace OBD.NET.Communication
|
|||||||
throw new NotSupportedException("Asynchronous operations not supported");
|
throw new NotSupportedException("Asynchronous operations not supported");
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task WriteAsync(string text)
|
public Task WriteAsync(byte[] data)
|
||||||
{
|
{
|
||||||
throw new NotSupportedException("Asynchronous operations not supported");
|
throw new NotSupportedException("Asynchronous operations not supported");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void Write(byte[] data)
|
||||||
|
{
|
||||||
|
_serialPort.Write(data, 0, data.Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user