diff --git a/OBD.NET/OBD.NET.Common/Devices/Command.cs b/OBD.NET/OBD.NET.Common/Devices/Command.cs
new file mode 100644
index 0000000..c3b306c
--- /dev/null
+++ b/OBD.NET/OBD.NET.Common/Devices/Command.cs
@@ -0,0 +1,27 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace OBD.NET.Common.Devices
+{
+ ///
+ /// Class used for queued command
+ ///
+ public class QueuedCommand
+ {
+
+ ///
+ /// Initializes a new instance
+ ///
+ ///
+ public QueuedCommand(string commandText)
+ {
+ CommandResult = new CommandResult();
+ CommandText = commandText;
+ }
+
+ public string CommandText { get; set; }
+
+ public CommandResult CommandResult { get; }
+ }
+}
diff --git a/OBD.NET/OBD.NET.Common/Devices/CommandResult.cs b/OBD.NET/OBD.NET.Common/Devices/CommandResult.cs
new file mode 100644
index 0000000..7352301
--- /dev/null
+++ b/OBD.NET/OBD.NET.Common/Devices/CommandResult.cs
@@ -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; }
+ }
+}
diff --git a/OBD.NET/OBD.NET.Common/Devices/ELM327.cs b/OBD.NET/OBD.NET.Common/Devices/ELM327.cs
index 6b07d36..170f561 100644
--- a/OBD.NET/OBD.NET.Common/Devices/ELM327.cs
+++ b/OBD.NET/OBD.NET.Common/Devices/ELM327.cs
@@ -89,13 +89,21 @@ namespace OBD.NET.Devices
throw;
}
}
-
+
+ ///
+ /// Sends the AT command.
+ ///
+ /// The command.
public virtual void SendCommand(ATCommand command)
{
SendCommand(command.Command);
}
-
+
+ ///
+ /// Requests the data and calls the handler
+ ///
+ ///
public virtual void RequestData()
where T : class, IOBDData, new()
{
@@ -111,13 +119,33 @@ namespace OBD.NET.Devices
SendCommand(((byte)Mode).ToString("X2") + pid.ToString("X2"));
}
- protected override void ProcessMessage(string message)
+ ///
+ /// Requests the data asynchronous and return the data when available
+ ///
+ ///
+ ///
+ public virtual async Task RequestDataAsync()
+ where T : class, IOBDData, new()
+ {
+ Logger?.WriteLine("Requesting Type " + typeof(T).Name + " ...", OBDLogLevel.Debug);
+ byte pid = ResolvePid();
+ 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;
RawDataReceived?.Invoke(this, new RawDataReceivedEventArgs(message, timestamp));
if (message.Length > 4)
+ {
if (message[0] == '4')
{
byte mode = (byte)message[1].GetHexVal();
@@ -129,13 +157,17 @@ namespace OBD.NET.Devices
{
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);
+
+ return obdData;
}
}
}
+ }
+ return null;
}
protected virtual byte ResolvePid()
diff --git a/OBD.NET/OBD.NET.Common/Devices/SerialDevice.cs b/OBD.NET/OBD.NET.Common/Devices/SerialDevice.cs
index 2ca4954..d9c8dcc 100644
--- a/OBD.NET/OBD.NET.Common/Devices/SerialDevice.cs
+++ b/OBD.NET/OBD.NET.Common/Devices/SerialDevice.cs
@@ -7,6 +7,7 @@ using OBD.NET.Common.Communication.EventArgs;
using System.Text;
using System.Threading;
using System.Collections.Concurrent;
+using OBD.NET.Common.Devices;
namespace OBD.NET.Devices
{
@@ -15,7 +16,7 @@ namespace OBD.NET.Devices
///
public abstract class SerialDevice : IDisposable
{
- private BlockingCollection commandQueue;
+ private BlockingCollection commandQueue;
private readonly StringBuilder _lineBuffer = new StringBuilder();
@@ -24,6 +25,8 @@ namespace OBD.NET.Devices
private Task commandWorkerTask;
private CancellationTokenSource commandCancellationToken;
+
+ protected QueuedCommand currentCommand;
///
/// Logger instance
@@ -48,7 +51,7 @@ namespace OBD.NET.Devices
///
private SerialDevice()
{
- commandQueue = new BlockingCollection();
+ commandQueue = new BlockingCollection();
}
///
@@ -117,16 +120,20 @@ namespace OBD.NET.Devices
///
/// command string
/// Not connected
- protected virtual void SendCommand(string command)
+ protected virtual CommandResult SendCommand(string command)
{
if (!Connection.IsOpen)
{
throw new InvalidOperationException("Not connected");
}
+
command = PrepareCommand(command);
Logger?.WriteLine("Queuing Command: '" + command.Replace('\r', '\'') + "'", OBDLogLevel.Verbose);
- commandQueue.Add(command);
+
+ var cmd = new QueuedCommand(command);
+ commandQueue.Add(cmd);
+ return cmd.CommandResult;
}
///
@@ -161,6 +168,7 @@ namespace OBD.NET.Devices
break;
case '>':
+ currentCommand.CommandResult.WaitHandle.Set();
commandFinishedEvent.Set();
break;
@@ -186,14 +194,25 @@ namespace OBD.NET.Devices
if (string.IsNullOrWhiteSpace(line)) return;
Logger?.WriteLine("Response: '" + line + "'", OBDLogLevel.Verbose);
- ProcessMessage(line);
+ InternalProcessMessage(line);
+ }
+
+ ///
+ /// Process message and sets the result
+ ///
+ /// The message.
+ private void InternalProcessMessage(string message)
+ {
+ var data = ProcessMessage(message);
+ currentCommand.CommandResult.Result = data;
}
///
/// Processes the message.
///
/// message received
- protected abstract void ProcessMessage(string message);
+ /// result data
+ protected abstract object ProcessMessage(string message);
///
/// Worker method for sending commands
@@ -202,18 +221,18 @@ namespace OBD.NET.Devices
{
while (!commandCancellationToken.IsCancellationRequested)
{
- string command = null;
- if(commandQueue.TryTake(out command, Timeout.Infinite, commandCancellationToken.Token))
+ currentCommand = null;
+ 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)
{
- await Connection.WriteAsync(Encoding.ASCII.GetBytes(command));
+ await Connection.WriteAsync(Encoding.ASCII.GetBytes(currentCommand.CommandText));
}
else
{
- Connection.Write(Encoding.ASCII.GetBytes(command));
+ Connection.Write(Encoding.ASCII.GetBytes(currentCommand.CommandText));
}
//wait for command to finish
diff --git a/OBD.NET/OBD.NET.Common/Util/AsyncManulResetEvent.cs b/OBD.NET/OBD.NET.Common/Util/AsyncManulResetEvent.cs
new file mode 100644
index 0000000..4f8f34f
--- /dev/null
+++ b/OBD.NET/OBD.NET.Common/Util/AsyncManulResetEvent.cs
@@ -0,0 +1,48 @@
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace OBD.NET.Util
+{
+ ///
+ /// Notifies one or more waiting awaiters that an event has occurred
+ ///
+ public class AsyncManualResetEvent
+ {
+ private volatile TaskCompletionSource _tcs = new TaskCompletionSource();
+
+ ///
+ /// Waits the async.
+ ///
+ ///
+ public Task WaitAsync()
+ {
+ return _tcs.Task;
+ }
+
+ //public void Set() { m_tcs.TrySetResult(true); }
+ ///
+ /// Sets the state of the event to signaled, allowing one or more waiting awaiters to proceed.
+ ///
+ public void Set()
+ {
+ var tcs = _tcs;
+ Task.Factory.StartNew(s => ((TaskCompletionSource)s).TrySetResult(true),
+ tcs, CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default);
+ tcs.Task.Wait();
+ }
+
+ ///
+ /// Sets the state of the event to nonsignaled, causing awaiters to block.
+ ///
+ public void Reset()
+ {
+ while (true)
+ {
+ var tcs = _tcs;
+ if (!tcs.Task.IsCompleted ||
+ Interlocked.CompareExchange(ref _tcs, new TaskCompletionSource(), tcs) == tcs)
+ return;
+ }
+ }
+ }
+}
\ No newline at end of file