mirror of
https://github.com/DarthAffe/OBD.NET.git
synced 2025-12-13 09:18:31 +00:00
Implemented RequestDataAsync
This commit is contained in:
parent
f38a867a99
commit
fa3fb7b756
27
OBD.NET/OBD.NET.Common/Devices/Command.cs
Normal file
27
OBD.NET/OBD.NET.Common/Devices/Command.cs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace OBD.NET.Common.Devices
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Class used for queued command
|
||||||
|
/// </summary>
|
||||||
|
public class QueuedCommand
|
||||||
|
{
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="commandText"></param>
|
||||||
|
public QueuedCommand(string commandText)
|
||||||
|
{
|
||||||
|
CommandResult = new CommandResult();
|
||||||
|
CommandText = commandText;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string CommandText { get; set; }
|
||||||
|
|
||||||
|
public CommandResult CommandResult { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
18
OBD.NET/OBD.NET.Common/Devices/CommandResult.cs
Normal file
18
OBD.NET/OBD.NET.Common/Devices/CommandResult.cs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
using OBD.NET.Util;
|
||||||
|
|
||||||
|
namespace OBD.NET.Common.Devices
|
||||||
|
{
|
||||||
|
public class CommandResult
|
||||||
|
{
|
||||||
|
public CommandResult()
|
||||||
|
{
|
||||||
|
WaitHandle = new AsyncManualResetEvent();
|
||||||
|
}
|
||||||
|
|
||||||
|
public object Result { get; set; }
|
||||||
|
public AsyncManualResetEvent WaitHandle { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -89,13 +89,21 @@ namespace OBD.NET.Devices
|
|||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sends the AT command.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="command">The command.</param>
|
||||||
public virtual void SendCommand(ATCommand command)
|
public virtual void SendCommand(ATCommand command)
|
||||||
{
|
{
|
||||||
SendCommand(command.Command);
|
SendCommand(command.Command);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Requests the data and calls the handler
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T"></typeparam>
|
||||||
public virtual void RequestData<T>()
|
public virtual void RequestData<T>()
|
||||||
where T : class, IOBDData, new()
|
where T : class, IOBDData, new()
|
||||||
{
|
{
|
||||||
@ -111,13 +119,33 @@ namespace OBD.NET.Devices
|
|||||||
SendCommand(((byte)Mode).ToString("X2") + pid.ToString("X2"));
|
SendCommand(((byte)Mode).ToString("X2") + pid.ToString("X2"));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void ProcessMessage(string message)
|
/// <summary>
|
||||||
|
/// Requests the data asynchronous and return the data when available
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T"></typeparam>
|
||||||
|
/// <returns></returns>
|
||||||
|
public virtual async Task<T> RequestDataAsync<T>()
|
||||||
|
where T : class, IOBDData, new()
|
||||||
|
{
|
||||||
|
Logger?.WriteLine("Requesting Type " + typeof(T).Name + " ...", OBDLogLevel.Debug);
|
||||||
|
byte pid = ResolvePid<T>();
|
||||||
|
Logger?.WriteLine("Requesting PID " + pid.ToString("X2") + " ...", OBDLogLevel.Debug);
|
||||||
|
var result = SendCommand(((byte)Mode).ToString("X2") + pid.ToString("X2"));
|
||||||
|
|
||||||
|
await result.WaitHandle.WaitAsync();
|
||||||
|
return result.Result as T;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
protected override object ProcessMessage(string message)
|
||||||
{
|
{
|
||||||
DateTime timestamp = DateTime.Now;
|
DateTime timestamp = DateTime.Now;
|
||||||
|
|
||||||
RawDataReceived?.Invoke(this, new RawDataReceivedEventArgs(message, timestamp));
|
RawDataReceived?.Invoke(this, new RawDataReceivedEventArgs(message, timestamp));
|
||||||
|
|
||||||
if (message.Length > 4)
|
if (message.Length > 4)
|
||||||
|
{
|
||||||
if (message[0] == '4')
|
if (message[0] == '4')
|
||||||
{
|
{
|
||||||
byte mode = (byte)message[1].GetHexVal();
|
byte mode = (byte)message[1].GetHexVal();
|
||||||
@ -129,13 +157,17 @@ namespace OBD.NET.Devices
|
|||||||
{
|
{
|
||||||
IOBDData obdData = (IOBDData)Activator.CreateInstance(dataType);
|
IOBDData obdData = (IOBDData)Activator.CreateInstance(dataType);
|
||||||
obdData.Load(message.Substring(4, message.Length - 4));
|
obdData.Load(message.Substring(4, message.Length - 4));
|
||||||
|
|
||||||
IDataEventManager dataEventManager;
|
IDataEventManager dataEventManager;
|
||||||
if (_dataReceivedEventHandlers.TryGetValue(dataType, out dataEventManager))
|
if (_dataReceivedEventHandlers.TryGetValue(dataType, out dataEventManager))
|
||||||
dataEventManager.RaiseEvent(this, obdData, timestamp);
|
dataEventManager.RaiseEvent(this, obdData, timestamp);
|
||||||
|
|
||||||
|
return obdData;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual byte ResolvePid<T>()
|
protected virtual byte ResolvePid<T>()
|
||||||
|
|||||||
@ -7,6 +7,7 @@ using OBD.NET.Common.Communication.EventArgs;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
|
using OBD.NET.Common.Devices;
|
||||||
|
|
||||||
namespace OBD.NET.Devices
|
namespace OBD.NET.Devices
|
||||||
{
|
{
|
||||||
@ -15,7 +16,7 @@ namespace OBD.NET.Devices
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class SerialDevice : IDisposable
|
public abstract class SerialDevice : IDisposable
|
||||||
{
|
{
|
||||||
private BlockingCollection<string> commandQueue;
|
private BlockingCollection<QueuedCommand> commandQueue;
|
||||||
|
|
||||||
private readonly StringBuilder _lineBuffer = new StringBuilder();
|
private readonly StringBuilder _lineBuffer = new StringBuilder();
|
||||||
|
|
||||||
@ -24,6 +25,8 @@ namespace OBD.NET.Devices
|
|||||||
private Task commandWorkerTask;
|
private Task commandWorkerTask;
|
||||||
|
|
||||||
private CancellationTokenSource commandCancellationToken;
|
private CancellationTokenSource commandCancellationToken;
|
||||||
|
|
||||||
|
protected QueuedCommand currentCommand;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Logger instance
|
/// Logger instance
|
||||||
@ -48,7 +51,7 @@ namespace OBD.NET.Devices
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
private SerialDevice()
|
private SerialDevice()
|
||||||
{
|
{
|
||||||
commandQueue = new BlockingCollection<string>();
|
commandQueue = new BlockingCollection<QueuedCommand>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -117,16 +120,20 @@ namespace OBD.NET.Devices
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="command">command string</param>
|
/// <param name="command">command string</param>
|
||||||
/// <exception cref="System.InvalidOperationException">Not connected</exception>
|
/// <exception cref="System.InvalidOperationException">Not connected</exception>
|
||||||
protected virtual void SendCommand(string command)
|
protected virtual CommandResult 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.Add(command);
|
|
||||||
|
var cmd = new QueuedCommand(command);
|
||||||
|
commandQueue.Add(cmd);
|
||||||
|
return cmd.CommandResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -161,6 +168,7 @@ namespace OBD.NET.Devices
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case '>':
|
case '>':
|
||||||
|
currentCommand.CommandResult.WaitHandle.Set();
|
||||||
commandFinishedEvent.Set();
|
commandFinishedEvent.Set();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -186,14 +194,25 @@ namespace OBD.NET.Devices
|
|||||||
if (string.IsNullOrWhiteSpace(line)) return;
|
if (string.IsNullOrWhiteSpace(line)) return;
|
||||||
Logger?.WriteLine("Response: '" + line + "'", OBDLogLevel.Verbose);
|
Logger?.WriteLine("Response: '" + line + "'", OBDLogLevel.Verbose);
|
||||||
|
|
||||||
ProcessMessage(line);
|
InternalProcessMessage(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Process message and sets the result
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message.</param>
|
||||||
|
private void InternalProcessMessage(string message)
|
||||||
|
{
|
||||||
|
var data = ProcessMessage(message);
|
||||||
|
currentCommand.CommandResult.Result = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Processes the message.
|
/// Processes the message.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="message">message received</param>
|
/// <param name="message">message received</param>
|
||||||
protected abstract void ProcessMessage(string message);
|
/// <returns>result data</returns>
|
||||||
|
protected abstract object ProcessMessage(string message);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Worker method for sending commands
|
/// Worker method for sending commands
|
||||||
@ -202,18 +221,18 @@ namespace OBD.NET.Devices
|
|||||||
{
|
{
|
||||||
while (!commandCancellationToken.IsCancellationRequested)
|
while (!commandCancellationToken.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
string command = null;
|
currentCommand = null;
|
||||||
if(commandQueue.TryTake(out command, Timeout.Infinite, commandCancellationToken.Token))
|
if(commandQueue.TryTake(out currentCommand, Timeout.Infinite, commandCancellationToken.Token))
|
||||||
{
|
{
|
||||||
Logger?.WriteLine("Writing Command: '" + command.Replace('\r', '\'') + "'", OBDLogLevel.Verbose);
|
Logger?.WriteLine("Writing Command: '" + currentCommand.CommandText.Replace('\r', '\'') + "'", OBDLogLevel.Verbose);
|
||||||
|
|
||||||
if (Connection.IsAsync)
|
if (Connection.IsAsync)
|
||||||
{
|
{
|
||||||
await Connection.WriteAsync(Encoding.ASCII.GetBytes(command));
|
await Connection.WriteAsync(Encoding.ASCII.GetBytes(currentCommand.CommandText));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Connection.Write(Encoding.ASCII.GetBytes(command));
|
Connection.Write(Encoding.ASCII.GetBytes(currentCommand.CommandText));
|
||||||
|
|
||||||
}
|
}
|
||||||
//wait for command to finish
|
//wait for command to finish
|
||||||
|
|||||||
48
OBD.NET/OBD.NET.Common/Util/AsyncManulResetEvent.cs
Normal file
48
OBD.NET/OBD.NET.Common/Util/AsyncManulResetEvent.cs
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace OBD.NET.Util
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Notifies one or more waiting awaiters that an event has occurred
|
||||||
|
/// </summary>
|
||||||
|
public class AsyncManualResetEvent
|
||||||
|
{
|
||||||
|
private volatile TaskCompletionSource<bool> _tcs = new TaskCompletionSource<bool>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Waits the async.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public Task WaitAsync()
|
||||||
|
{
|
||||||
|
return _tcs.Task;
|
||||||
|
}
|
||||||
|
|
||||||
|
//public void Set() { m_tcs.TrySetResult(true); }
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the state of the event to signaled, allowing one or more waiting awaiters to proceed.
|
||||||
|
/// </summary>
|
||||||
|
public void Set()
|
||||||
|
{
|
||||||
|
var tcs = _tcs;
|
||||||
|
Task.Factory.StartNew(s => ((TaskCompletionSource<bool>)s).TrySetResult(true),
|
||||||
|
tcs, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default);
|
||||||
|
tcs.Task.Wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the state of the event to nonsignaled, causing awaiters to block.
|
||||||
|
/// </summary>
|
||||||
|
public void Reset()
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
var tcs = _tcs;
|
||||||
|
if (!tcs.Task.IsCompleted ||
|
||||||
|
Interlocked.CompareExchange(ref _tcs, new TaskCompletionSource<bool>(), tcs) == tcs)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user