diff --git a/OBD.NET/OBD.NET.Common/Communication/SerialConnection.cs b/OBD.NET/OBD.NET.Common/Communication/SerialConnection.cs index c25571f..d5934cf 100644 --- a/OBD.NET/OBD.NET.Common/Communication/SerialConnection.cs +++ b/OBD.NET/OBD.NET.Common/Communication/SerialConnection.cs @@ -29,13 +29,13 @@ namespace OBD.NET.Communication /// /// Connects the serial port. /// - bool Connect(); + void Connect(); /// /// Connects the serial port async /// /// - Task ConnectAsync(); + Task ConnectAsync(); /// diff --git a/OBD.NET/OBD.NET.Common/Devices/ELM327.cs b/OBD.NET/OBD.NET.Common/Devices/ELM327.cs index 4921712..2fe0f18 100644 --- a/OBD.NET/OBD.NET.Common/Devices/ELM327.cs +++ b/OBD.NET/OBD.NET.Common/Devices/ELM327.cs @@ -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) { SendCommand(command.Command); } - - public virtual async Task SendCommandAsync(ATCommand command) - { - await SendCommandAsync(command.Command); - } - + public virtual void RequestData() where T : class, IOBDData, new() { @@ -134,27 +94,12 @@ namespace OBD.NET.Devices RequestData(pid); } - public virtual async Task RequestDataAsync() - where T : class, IOBDData, new() - { - Logger?.WriteLine("Requesting Type " + typeof(T).Name + " ...", OBDLogLevel.Debug); - - byte pid = ResolvePid(); - await RequestDataAsync(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 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) { DateTime timestamp = DateTime.Now; diff --git a/OBD.NET/OBD.NET.Common/Devices/SerialDevice.cs b/OBD.NET/OBD.NET.Common/Devices/SerialDevice.cs index eb1c656..efeffc5 100644 --- a/OBD.NET/OBD.NET.Common/Devices/SerialDevice.cs +++ b/OBD.NET/OBD.NET.Common/Devices/SerialDevice.cs @@ -4,6 +4,9 @@ using OBD.NET.Exceptions; using OBD.NET.Logging; using System.Threading.Tasks; using OBD.NET.Common.Communication.EventArgs; +using System.Text; +using System.Threading; +using System.Collections.Concurrent; namespace OBD.NET.Devices { @@ -12,8 +15,15 @@ namespace OBD.NET.Devices /// public abstract class SerialDevice : IDisposable { - private System.Collections.Generic.Queue commandQueue; + private BlockingCollection commandQueue; + private readonly StringBuilder _lineBuffer = new StringBuilder(); + + private readonly AutoResetEvent commandFinishedEvent = new AutoResetEvent(true); + + private Task commandWorkerTask; + private CancellationTokenSource commandCancellationToken; + /// /// Logger instance /// @@ -34,7 +44,7 @@ namespace OBD.NET.Devices private SerialDevice() { - commandQueue = new System.Collections.Generic.Queue(); + commandQueue = new BlockingCollection(); } protected SerialDevice(ISerialConnection connection, char terminator = '\r', IOBDLogger logger = null) @@ -49,12 +59,7 @@ namespace OBD.NET.Devices #endregion - - private void OnDataReceived(object sender, DataReceivedEventArgs e) - { - - } - + #region Methods @@ -63,22 +68,21 @@ namespace OBD.NET.Devices /// public virtual void Initialize() { - Connection.Connect(); - CheckConnection(); + CheckConnectionAndStartWorker(); } /// - /// Initializes the device async + /// Initializes the device asynchronously /// /// public virtual async Task InitializeAsync() { await Connection.ConnectAsync(); - CheckConnection(); + CheckConnectionAndStartWorker(); } - private void CheckConnection() + private void CheckConnectionAndStartWorker() { if (!Connection.IsOpen) { @@ -86,23 +90,37 @@ namespace OBD.NET.Devices throw new SerialException("Failed to open Serial-Connection."); } else + { 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) { if (!Connection.IsOpen) { throw new InvalidOperationException("Not connected"); - } + } command = PrepareCommand(command); Logger?.WriteLine("Queuing Command: '" + command.Replace('\r', '\'') + "'", OBDLogLevel.Verbose); - commandQueue.Enqueue(command); -// Logger?.WriteLine("Writing Command: '" + command.Replace('\r', '\'') + "'", OBDLogLevel.Verbose); - // Connection.Write(command); + commandQueue.Add(command); } /// @@ -120,6 +138,40 @@ namespace OBD.NET.Devices 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) { if (string.IsNullOrWhiteSpace(message)) return; diff --git a/OBD.NET/OBD.NET.Common/Logging/TraceLogger.cs b/OBD.NET/OBD.NET.Common/Logging/TraceLogger.cs new file mode 100644 index 0000000..7ee9adf --- /dev/null +++ b/OBD.NET/OBD.NET.Common/Logging/TraceLogger.cs @@ -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 +{ + /// + /// Simple debug logger + /// + /// + public class OBDDebugLogger : IOBDLogger + { + public void WriteLine(string text, OBDLogLevel level) + { + Debug.WriteLine($"{level}: {text}"); + } + } +} diff --git a/OBD.NET/OBD.NET.Universal/Communication/BluetoothSerialConnection.cs b/OBD.NET/OBD.NET.Universal/Communication/BluetoothSerialConnection.cs index cd48f14..72b826d 100644 --- a/OBD.NET/OBD.NET.Universal/Communication/BluetoothSerialConnection.cs +++ b/OBD.NET/OBD.NET.Universal/Communication/BluetoothSerialConnection.cs @@ -3,6 +3,7 @@ using System.Runtime.InteropServices.WindowsRuntime; using System.Text; using System.Threading; using System.Threading.Tasks; +using OBD.NET.Common.Communication.EventArgs; using Windows.Devices.Bluetooth.Rfcomm; using Windows.Networking.Sockets; using Windows.Storage.Streams; @@ -16,8 +17,7 @@ namespace OBD.NET.Communication private DataWriter _writer; private readonly byte[] _readBuffer = new byte[1024]; - private readonly StringBuilder _lineBuffer = new StringBuilder(); - + private CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource(); private Task _readerTask; @@ -32,7 +32,7 @@ namespace OBD.NET.Communication /// /// Occurs when a full line was received /// - public event EventHandler MessageReceived; + public event EventHandler DataReceived; /// /// Connects the serial port. @@ -74,7 +74,7 @@ namespace OBD.NET.Communication /// /// The text. /// Synchronous operations not supported - public void Write(string text) + public void Write(byte[] data) { throw new NotImplementedException("Synchronous operations not supported"); } @@ -84,9 +84,9 @@ namespace OBD.NET.Communication /// /// The text. /// - public async Task WriteAsync(string text) + public async Task WriteAsync(byte[] data) { - _writer.WriteString(text); + _writer.WriteBytes(data); await _writer.StoreAsync(); await _writer.FlushAsync(); } @@ -107,38 +107,10 @@ namespace OBD.NET.Communication private void SerialPortOnDataReceived(IBuffer buffer) { - - 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); + DataReceived?.Invoke(this, new DataReceivedEventArgs((int)buffer.Length, _readBuffer)); } + public void Dispose() { _cancellationTokenSource?.Cancel(); @@ -146,6 +118,5 @@ namespace OBD.NET.Communication _socket?.Dispose(); } - } } diff --git a/OBD.NET/ODB.NET.Desktop/Communication/SerialConnection.cs b/OBD.NET/ODB.NET.Desktop/Communication/SerialConnection.cs index 23ad33d..76941f1 100644 --- a/OBD.NET/ODB.NET.Desktop/Communication/SerialConnection.cs +++ b/OBD.NET/ODB.NET.Desktop/Communication/SerialConnection.cs @@ -3,6 +3,7 @@ using System.IO.Ports; using System.Text; using System.Threading; using System.Threading.Tasks; +using OBD.NET.Common.Communication.EventArgs; namespace OBD.NET.Communication { @@ -24,7 +25,7 @@ namespace OBD.NET.Communication #region Events - public event EventHandler MessageReceived; + public event EventHandler DataReceived; #endregion @@ -52,53 +53,15 @@ namespace OBD.NET.Communication public void Connect() { _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) { 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); + DataReceived?.Invoke(this,new DataReceivedEventArgs(count, _readBuffer)); } + public void Dispose() { _serialPort?.Dispose(); @@ -109,11 +72,19 @@ namespace OBD.NET.Communication throw new NotSupportedException("Asynchronous operations not supported"); } - public Task WriteAsync(string text) + public Task WriteAsync(byte[] data) { throw new NotSupportedException("Asynchronous operations not supported"); } + + public void Write(byte[] data) + { + _serialPort.Write(data, 0, data.Length); + } + + + #endregion } }