Skip to content

Commit

Permalink
Now reading data in more "proper" way.
Browse files Browse the repository at this point in the history
Changed default baud rate for quicker local testing. Default value shouldn't matter anyway.
  • Loading branch information
Glenn Thomas Hvidsten committed May 15, 2016
1 parent 0f5bf32 commit 3cac161
Show file tree
Hide file tree
Showing 2 changed files with 152 additions and 156 deletions.
246 changes: 123 additions & 123 deletions src/OpenSerialPortMonitor/ViewModels/SerialConnectorViewModel.cs
Original file line number Diff line number Diff line change
@@ -1,123 +1,123 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Caliburn.Micro;
using Whitestone.OpenSerialPortMonitor.SerialCommunication;
using Whitestone.OpenSerialPortMonitor.Main.Messages;
using System.IO.Ports;
using System.Windows;

namespace Whitestone.OpenSerialPortMonitor.Main.ViewModels
{
public class SerialConnectorViewModel : PropertyChangedBase, IHandle<ConnectionError>
{
private readonly IEventAggregator _eventAggregator;

public BindableCollection<string> ComPorts { get; set; }
public BindableCollection<int> BaudRates { get; set; }
public BindableCollection<Parity> Parities { get; set; }
public BindableCollection<int> DataBits { get; set; }
public BindableCollection<StopBits> StopBits { get; set; }

public string SelectedComPort { get; set; }
public int SelectedBaudRate { get; set; }
public int SelectedDataBits { get; set; }
public Parity SelectedParity { get; set; }
public StopBits SelectedStopBits { get; set; }

private bool _isConnected = false;
public bool IsConnected
{
get { return _isConnected; }
set
{
_isConnected = value;
NotifyOfPropertyChange(() => IsConnected);
NotifyOfPropertyChange(() => IsDisconnected);
}
}
public bool IsDisconnected
{
get { return !_isConnected; }
set
{
_isConnected = !value;
NotifyOfPropertyChange(() => IsConnected);
NotifyOfPropertyChange(() => IsDisconnected);
}
}

public SerialConnectorViewModel(IEventAggregator eventAggregator)
{
_eventAggregator = eventAggregator;
_eventAggregator.Subscribe(this);

BindValues();
}

private void BindValues()
{
BaudRates = new BindableCollection<int>() { 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200 };
SelectedBaudRate = 4800;

DataBits = new BindableCollection<int>() { 5, 6, 7, 8, 9 };
SelectedDataBits = 8;

Parities = new BindableCollection<Parity>();
foreach (Parity p in Enum.GetValues(typeof(Parity)))
{
Parities.Add(p);
}
SelectedParity = Parity.None;

StopBits = new BindableCollection<StopBits>();
foreach (StopBits s in Enum.GetValues(typeof(StopBits)))
{
StopBits.Add(s);
}
SelectedStopBits = System.IO.Ports.StopBits.One;


IEnumerable<string> ports = SerialReader.GetAvailablePorts();
ComPorts = new BindableCollection<string>();
ComPorts.AddRange(ports);

SelectedComPort = ports.FirstOrDefault();
}

public void Connect()
{
IsConnected = true;

_eventAggregator.PublishOnUIThread(new SerialPortConnect
{
PortName = SelectedComPort,
BaudRate = SelectedBaudRate,
DataBits = SelectedDataBits,
Parity = SelectedParity,
StopBits = SelectedStopBits
});
}

public void Disconnect()
{
IsConnected = false;

_eventAggregator.PublishOnUIThread(new SerialPortDisconnect());
}

public void Handle(ConnectionError message)
{
IsConnected = false;

string errorMessage = message.Exception.Message;
if (message.Exception.InnerException != null)
{
errorMessage = message.Exception.InnerException.Message;
}
MessageBox.Show(errorMessage, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Caliburn.Micro;
using Whitestone.OpenSerialPortMonitor.SerialCommunication;
using Whitestone.OpenSerialPortMonitor.Main.Messages;
using System.IO.Ports;
using System.Windows;

namespace Whitestone.OpenSerialPortMonitor.Main.ViewModels
{
public class SerialConnectorViewModel : PropertyChangedBase, IHandle<ConnectionError>
{
private readonly IEventAggregator _eventAggregator;

public BindableCollection<string> ComPorts { get; set; }
public BindableCollection<int> BaudRates { get; set; }
public BindableCollection<Parity> Parities { get; set; }
public BindableCollection<int> DataBits { get; set; }
public BindableCollection<StopBits> StopBits { get; set; }

public string SelectedComPort { get; set; }
public int SelectedBaudRate { get; set; }
public int SelectedDataBits { get; set; }
public Parity SelectedParity { get; set; }
public StopBits SelectedStopBits { get; set; }

private bool _isConnected = false;
public bool IsConnected
{
get { return _isConnected; }
set
{
_isConnected = value;
NotifyOfPropertyChange(() => IsConnected);
NotifyOfPropertyChange(() => IsDisconnected);
}
}
public bool IsDisconnected
{
get { return !_isConnected; }
set
{
_isConnected = !value;
NotifyOfPropertyChange(() => IsConnected);
NotifyOfPropertyChange(() => IsDisconnected);
}
}

public SerialConnectorViewModel(IEventAggregator eventAggregator)
{
_eventAggregator = eventAggregator;
_eventAggregator.Subscribe(this);

BindValues();
}

private void BindValues()
{
BaudRates = new BindableCollection<int>() { 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200 };
SelectedBaudRate = 115200;

DataBits = new BindableCollection<int>() { 5, 6, 7, 8, 9 };
SelectedDataBits = 8;

Parities = new BindableCollection<Parity>();
foreach (Parity p in Enum.GetValues(typeof(Parity)))
{
Parities.Add(p);
}
SelectedParity = Parity.None;

StopBits = new BindableCollection<StopBits>();
foreach (StopBits s in Enum.GetValues(typeof(StopBits)))
{
StopBits.Add(s);
}
SelectedStopBits = System.IO.Ports.StopBits.One;


IEnumerable<string> ports = SerialReader.GetAvailablePorts();
ComPorts = new BindableCollection<string>();
ComPorts.AddRange(ports);

SelectedComPort = ports.FirstOrDefault();
}

public void Connect()
{
IsConnected = true;

_eventAggregator.PublishOnUIThread(new SerialPortConnect
{
PortName = SelectedComPort,
BaudRate = SelectedBaudRate,
DataBits = SelectedDataBits,
Parity = SelectedParity,
StopBits = SelectedStopBits
});
}

public void Disconnect()
{
IsConnected = false;

_eventAggregator.PublishOnUIThread(new SerialPortDisconnect());
}

public void Handle(ConnectionError message)
{
IsConnected = false;

string errorMessage = message.Exception.Message;
if (message.Exception.InnerException != null)
{
errorMessage = message.Exception.InnerException.Message;
}
MessageBox.Show(errorMessage, "Error", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
}
62 changes: 29 additions & 33 deletions src/SerialCommunication/SerialReader.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Timers;

namespace Whitestone.OpenSerialPortMonitor.SerialCommunication
Expand All @@ -23,6 +22,8 @@ public class SerialReader : IDisposable
private Timer _bufferTimer = null;
private DateTime _lastReceivedData = DateTime.Now;
private bool _disposed = false;
private System.Threading.Thread _readThread = null;
private bool _readThreadRunning = false;

public SerialReader()
{
Expand Down Expand Up @@ -68,7 +69,28 @@ public void Start(string portName, int baudRate, Parity parity, int dataBits, St
}

_serialPort.ReadTimeout = 100; // Milliseconds
_serialPort.DataReceived += SerialPortDataReceived;

_readThread = new System.Threading.Thread(ReadThread);
_readThreadRunning = true;
_readThread.Start();
}

private async void ReadThread()
{
while (_readThreadRunning)
{
// This is the proper way to read data, according to http://www.sparxeng.com/blog/software/must-use-net-system-io-ports-serialport
// Though he uses BeginRead/EndRead, ReadAsync is the preferred way in .NET 4.5
byte[] buffer = new byte[MAX_RECEIVE_BUFFER * 3];
int bytesRead = await _serialPort.BaseStream.ReadAsync(buffer, 0, buffer.Length);

byte[] received = new byte[bytesRead];
Buffer.BlockCopy(buffer, 0, received, 0, bytesRead);
lock (_receiveBuffer)
{
_receiveBuffer.AddRange(received);
}
}
}

public void Send(byte[] data)
Expand All @@ -81,10 +103,11 @@ public void Send(byte[] data)

public void Stop()
{
_readThreadRunning = false;

// Disconnect from the serial port
if (_serialPort != null)
{
_serialPort.DataReceived -= SerialPortDataReceived;
_serialPort.Close();
_serialPort.Dispose();
_serialPort = null;
Expand All @@ -104,35 +127,13 @@ public void Stop()
}
}

private void SerialPortDataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
// Read the data from COM and empty the COM buffer
SerialPort serialPort = (SerialPort)sender;
byte[] buffer = new byte[serialPort.BytesToRead];
serialPort.Read(buffer, 0, buffer.Length);

serialPort.DiscardInBuffer();

lock (_receiveBuffer)
{
_lastReceivedData = DateTime.Now;

_receiveBuffer.AddRange(buffer);

if (_receiveBuffer.Count >= MAX_RECEIVE_BUFFER)
{
SendBuffer(ref _receiveBuffer);
}
}
}

private void _bufferTimer_Elapsed(object sender, ElapsedEventArgs e)
{
lock (_receiveBuffer)
{
// Only send data if the last data received was more than BUFFER_TIMER_INTERVAL milliseconds ago
// This is to ensure it only empties the buffer when not a lot of data has been received lately
if ((DateTime.Now - _lastReceivedData).TotalMilliseconds > BUFFER_TIMER_INTERVAL)
if ((DateTime.Now - _lastReceivedData).TotalMilliseconds > BUFFER_TIMER_INTERVAL && _receiveBuffer.Count > 0)
{
SendBuffer(ref _receiveBuffer);
}
Expand All @@ -144,15 +145,10 @@ private void SendBuffer(ref List<byte> buffer)
byte[] byteBuffer = buffer.ToArray();
buffer.Clear();

OnDataReceived(this, new SerialDataReceivedEventArgs() { Data = byteBuffer });
}

private void OnDataReceived(object sender, SerialDataReceivedEventArgs e)
{
EventHandler<SerialDataReceivedEventArgs> handler = SerialDataReceived;
if (handler != null)
{
handler(this, e);
handler(this, new SerialDataReceivedEventArgs() { Data = byteBuffer });
}
}

Expand Down

0 comments on commit 3cac161

Please sign in to comment.