From b8b94ae5549484425cd9ff307833d2e609cbcddb Mon Sep 17 00:00:00 2001 From: Darth Affe Date: Sat, 26 Aug 2017 17:42:45 +0200 Subject: [PATCH] Added method to wait till all queued commands are processed; Added method to request data by pid --- OBD.NET/OBD.NET.Common/Devices/ELM327.cs | 58 ++++++++++++++++--- .../OBD.NET.Common/Devices/SerialDevice.cs | 19 +++++- .../OBD.NET.Common/Logging/OBDDebugLogger.cs | 27 ++++++++- OBD.NET/ODB.NET.ConsoleClient/Program.cs | 8 ++- .../Logging/ODBConsoleLogger.cs | 2 +- 5 files changed, 99 insertions(+), 15 deletions(-) diff --git a/OBD.NET/OBD.NET.Common/Devices/ELM327.cs b/OBD.NET/OBD.NET.Common/Devices/ELM327.cs index 85594ad..372d5ca 100644 --- a/OBD.NET/OBD.NET.Common/Devices/ELM327.cs +++ b/OBD.NET/OBD.NET.Common/Devices/ELM327.cs @@ -1,5 +1,7 @@ using System; using System.Collections.Generic; +using System.Linq; +using System.Reflection; using System.Threading.Tasks; using OBD.NET.Common.Commands; using OBD.NET.Common.Communication; @@ -80,6 +82,7 @@ namespace OBD.NET.Common.Devices Logger?.WriteLine("Setting the Protocol to 'Auto' ...", OBDLogLevel.Debug); SendCommand(ATCommand.SetProtocolAuto); + WaitQueue(); } // DarthAffe 21.02.2017: This seems to happen sometimes, i don't know why - just retry. catch @@ -108,7 +111,11 @@ namespace OBD.NET.Common.Devices RequestData(pid); } - protected virtual void RequestData(byte pid) + /// + /// Request data based on a pid + /// + /// The pid of the requested data + public virtual void RequestData(byte pid) { Logger?.WriteLine("Requesting PID " + pid.ToString("X2") + " ...", OBDLogLevel.Debug); SendCommand(((byte)Mode).ToString("X2") + pid.ToString("X2")); @@ -124,11 +131,20 @@ namespace OBD.NET.Common.Devices { Logger?.WriteLine("Requesting Type " + typeof(T).Name + " ...", OBDLogLevel.Debug); byte pid = ResolvePid(); + return await RequestDataAsync(pid) as T; + } + + /// + /// Request data based on a pid + /// + /// The pid of the requested data + public virtual async Task RequestDataAsync(byte pid) + { Logger?.WriteLine("Requesting PID " + pid.ToString("X2") + " ...", OBDLogLevel.Debug); CommandResult result = SendCommand(((byte)Mode).ToString("X2") + pid.ToString("X2")); await result.WaitHandle.WaitAsync(); - return result.Result as T; + return result.Result; } protected override object ProcessMessage(string message) @@ -168,16 +184,42 @@ namespace OBD.NET.Common.Devices where T : class, IOBDData, new() { if (!PidCache.TryGetValue(typeof(T), out byte pid)) - { - T data = Activator.CreateInstance(); - pid = data.PID; - PidCache.Add(typeof(T), pid); - DataTypeCache.Add(pid, typeof(T)); - } + pid = AddToPidCache(); return pid; } + public virtual byte AddToPidCache() + where T : class, IOBDData, new() => AddToPidCache(typeof(T)); + + protected virtual byte AddToPidCache(Type obdDataType) + { + IOBDData data = (IOBDData)Activator.CreateInstance(obdDataType); + if (data == null) throw new ArgumentException("Has to implement IOBDData", nameof(obdDataType)); + + byte pid = data.PID; + + PidCache.Add(obdDataType, pid); + DataTypeCache.Add(pid, obdDataType); + + return pid; + } + + /// + /// YOU SHOULDN'T NEED THIS METHOD! + /// + /// You should only use this method if you're requesting data by pid instead of the -method. + /// + /// Initializes the PID-Cache with all IOBDData-Types contained in OBD.NET. + /// You can add additional ones with . + /// + public virtual void InitializePidCache() + { + TypeInfo iobdDataInfo = typeof(IOBDData).GetTypeInfo(); + foreach (TypeInfo obdDataType in iobdDataInfo.Assembly.DefinedTypes.Where(t => t.IsClass && !t.IsAbstract && iobdDataInfo.IsAssignableFrom(t))) + AddToPidCache(obdDataType.AsType()); + } + public override void Dispose() => Dispose(true); public void Dispose(bool sendCloseProtocol) diff --git a/OBD.NET/OBD.NET.Common/Devices/SerialDevice.cs b/OBD.NET/OBD.NET.Common/Devices/SerialDevice.cs index ee05218..ec446c8 100644 --- a/OBD.NET/OBD.NET.Common/Devices/SerialDevice.cs +++ b/OBD.NET/OBD.NET.Common/Devices/SerialDevice.cs @@ -23,6 +23,11 @@ namespace OBD.NET.Common.Devices private Task _commandWorkerTask; private CancellationTokenSource _commandCancellationToken; + private volatile int _queueSize = 0; + private readonly ManualResetEvent _queueEmptyEvent = new ManualResetEvent(true); + + public int QueueSize => _queueSize; + protected QueuedCommand CurrentCommand; protected IOBDLogger Logger { get; } protected ISerialConnection Connection { get; } @@ -102,6 +107,8 @@ namespace OBD.NET.Common.Devices Logger?.WriteLine("Queuing Command: '" + command.Replace('\r', '\'') + "'", OBDLogLevel.Verbose); QueuedCommand cmd = new QueuedCommand(command); + _queueEmptyEvent.Reset(); + _queueSize++; _commandQueue.Add(cmd); return cmd.CommandResult; @@ -193,8 +200,14 @@ namespace OBD.NET.Common.Devices while (!_commandCancellationToken.IsCancellationRequested) { CurrentCommand = null; - if (_commandQueue.TryTake(out CurrentCommand, Timeout.Infinite, _commandCancellationToken.Token)) + + if (_queueSize == 0) + _queueEmptyEvent.Set(); + + if (_commandQueue.TryTake(out CurrentCommand, 10, _commandCancellationToken.Token)) { + _queueSize--; + Logger?.WriteLine("Writing Command: '" + CurrentCommand.CommandText.Replace('\r', '\'') + "'", OBDLogLevel.Verbose); if (Connection.IsAsync) @@ -208,6 +221,10 @@ namespace OBD.NET.Common.Devices } } + public void WaitQueue() => _queueEmptyEvent.WaitOne(); + + public async Task WaitQueueAsync() => await Task.Run(() => WaitQueue()); + /// /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// diff --git a/OBD.NET/OBD.NET.Common/Logging/OBDDebugLogger.cs b/OBD.NET/OBD.NET.Common/Logging/OBDDebugLogger.cs index 17bf914..14cc316 100644 --- a/OBD.NET/OBD.NET.Common/Logging/OBDDebugLogger.cs +++ b/OBD.NET/OBD.NET.Common/Logging/OBDDebugLogger.cs @@ -1,4 +1,5 @@ -using System.Diagnostics; +using System; +using System.Diagnostics; namespace OBD.NET.Common.Logging { @@ -8,9 +9,31 @@ namespace OBD.NET.Common.Logging /// public class OBDDebugLogger : IOBDLogger { + + #region Properties & Fields + + public OBDLogLevel LogLevel { get; set; } + + #endregion + + #region Constructors + + public OBDDebugLogger(OBDLogLevel level = OBDLogLevel.None) + { + this.LogLevel = level; + } + + #endregion + #region Methods - public void WriteLine(string text, OBDLogLevel level) => Debug.WriteLine($"{level}: {text}"); + public void WriteLine(string text, OBDLogLevel level) + { + if (LogLevel == OBDLogLevel.None) return; + + if ((int)level <= (int)LogLevel) + Debug.WriteLine($"{DateTime.Now:G} - {level} - {text}"); + } #endregion } diff --git a/OBD.NET/ODB.NET.ConsoleClient/Program.cs b/OBD.NET/ODB.NET.ConsoleClient/Program.cs index 1dbed58..366027a 100644 --- a/OBD.NET/ODB.NET.ConsoleClient/Program.cs +++ b/OBD.NET/ODB.NET.ConsoleClient/Program.cs @@ -2,6 +2,7 @@ using System.Threading; using System.Threading.Tasks; using OBD.NET.Common.Devices; +using OBD.NET.Common.Extensions; using OBD.NET.Common.Logging; using OBD.NET.Common.OBDData; using ODB.NET.Desktop.Communication; @@ -25,9 +26,10 @@ namespace ODB.NET.ConsoleClient using (ELM327 dev = new ELM327(connection, new OBDConsoleLogger(OBDLogLevel.Debug))) { dev.SubscribeDataReceived((sender, data) => Console.WriteLine("EngineRPM: " + data.Data.Rpm)); - dev.SubscribeDataReceived((sender, data) => Console.WriteLine("VehicleSpeed: " + data.Data.Speed)); + dev.SubscribeDataReceived((sender, data) => Console.WriteLine($"PID {data.Data.PID.ToHexString()}: {data.Data}")); + dev.Initialize(); dev.RequestData(); for (int i = 0; i < 5; i++) @@ -40,9 +42,9 @@ namespace ODB.NET.ConsoleClient Console.ReadLine(); //Async example - MainAsync(comPort).Wait(); + //MainAsync(comPort).Wait(); - Console.ReadLine(); + //Console.ReadLine(); } /// diff --git a/OBD.NET/ODB.NET.Desktop/Logging/ODBConsoleLogger.cs b/OBD.NET/ODB.NET.Desktop/Logging/ODBConsoleLogger.cs index 6f88164..9e5522b 100644 --- a/OBD.NET/ODB.NET.Desktop/Logging/ODBConsoleLogger.cs +++ b/OBD.NET/ODB.NET.Desktop/Logging/ODBConsoleLogger.cs @@ -30,7 +30,7 @@ namespace ODB.NET.Desktop.Logging { if (LogLevel == OBDLogLevel.None) return; - if ((int)level >= (int)LogLevel) + if ((int)level <= (int)LogLevel) Console.WriteLine($"{DateTime.Now:G} - {level} - {text}"); }