Skip to content

Commit

Permalink
Improve and harden data read from serial
Browse files Browse the repository at this point in the history
  • Loading branch information
adrianstevens committed Dec 4, 2023
1 parent a95c9d9 commit 24bd7d7
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 28 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,20 @@ public class A02yyuw : PollingSensorBase<Length>, IRangeFinder, ISleepAwarePerip
/// </summary>
public Length OutOfRangeValue { get; } = new Length(25, Length.UnitType.Centimeters);

/// <summary>
/// The maximum time to wait for a sensor reading
/// </summary>
public TimeSpan SensorReadTimeOut { get; set; } = TimeSpan.FromSeconds(1000);

//The baud rate is 9600, 8 bits, no parity, with one stop bit
private readonly ISerialPort serialPort;

private static readonly int portSpeed = 9600;

private readonly byte[] readBuffer = new byte[16];
//Serial read variables
readonly byte[] readBuffer = new byte[16];
int serialDataBytesRead = 0;
byte serialDataFirstByte;

private TaskCompletionSource<Length>? dataReceivedTaskCompletionSource;

Expand All @@ -58,6 +66,7 @@ public A02yyuw(IMeadowDevice device, SerialPortName serialPortName)
public A02yyuw(ISerialPort serialMessage)
{
serialPort = serialMessage;
serialPort.ReadTimeout = TimeSpan.FromSeconds(5);
serialPort.DataReceived += SerialPortDataReceived;
}

Expand Down Expand Up @@ -125,36 +134,59 @@ public override void StopUpdating()
//when 3 bytes are available we know we have a distance reading ready
private async Task<Length> ReadSingleValue()
{
dataReceivedTaskCompletionSource = new TaskCompletionSource<Length>();

if (serialPort.IsOpen == false)
{
serialPort.Open();
}

dataReceivedTaskCompletionSource = new TaskCompletionSource<Length>();
var timeOutTask = Task.Delay(SensorReadTimeOut);

await Task.WhenAny(dataReceivedTaskCompletionSource.Task, timeOutTask);

var result = await dataReceivedTaskCompletionSource.Task;
serialPort.Close();

return result;
if (dataReceivedTaskCompletionSource.Task.IsCompletedSuccessfully == true)
{
return dataReceivedTaskCompletionSource.Task.Result;
}
return Length.Zero;
}

private void SerialPortDataReceived(object sender, SerialDataReceivedEventArgs e)
{
var len = serialPort.BytesToRead;

if (len > 3)
if (serialPort.IsOpen == false || serialPort.BytesToRead == 0 || dataReceivedTaskCompletionSource?.Task.IsCompletedSuccessfully == true)
{
serialPort.Read(readBuffer, 0, Math.Min(len, readBuffer.Length));
return;
}

if (len == 3)
{
var mm = readBuffer[0] << 8 | readBuffer[1];
var len = serialPort.BytesToRead;

serialPort.Read(readBuffer, 0, Math.Min(len, readBuffer.Length));

if (mm != 0)
for (int i = 0; i < len; i++)
{
if (readBuffer[i] == 0xFF)
{
serialDataBytesRead = 0;
}
else if (serialDataBytesRead == 0)
{
var length = new Length(mm, Length.UnitType.Millimeters);
dataReceivedTaskCompletionSource?.SetResult(length);
serialDataFirstByte = readBuffer[i];
serialDataBytesRead++;
}
else if (serialDataBytesRead == 1)
{
serialDataBytesRead = 2;
var lengthInMillimeters = serialDataFirstByte << 8 | readBuffer[i];

if (lengthInMillimeters != 0) //device should never return 0
{
var length = new Length(lengthInMillimeters, Length.UnitType.Millimeters);
dataReceivedTaskCompletionSource?.SetResult(length);
return;
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,20 @@ public class Me007ys : PollingSensorBase<Length>, IRangeFinder, ISleepAwarePerip
/// </summary>
public Length OutOfRangeValue { get; } = new Length(25, Length.UnitType.Centimeters);

/// <summary>
/// The maximum time to wait for a sensor reading
/// </summary>
public TimeSpan SensorReadTimeOut { get; set; } = TimeSpan.FromSeconds(1000);

//The baud rate is 9600, 8 bits, no parity, with one stop bit
private readonly ISerialPort serialPort;

private static readonly int portSpeed = 9600;

private readonly byte[] readBuffer = new byte[16];
//Serial read variables
readonly byte[] readBuffer = new byte[16];
int serialDataBytesRead = 0;
byte serialDataFirstByte;

private TaskCompletionSource<Length>? dataReceivedTaskCompletionSource;

Expand All @@ -58,6 +66,7 @@ public Me007ys(IMeadowDevice device, SerialPortName serialPortName)
public Me007ys(ISerialPort serialMessage)
{
serialPort = serialMessage;
serialPort.ReadTimeout = TimeSpan.FromSeconds(5);
serialPort.DataReceived += SerialPortDataReceived;
}

Expand Down Expand Up @@ -125,36 +134,59 @@ public override void StopUpdating()
//when 3 bytes are available we know we have a distance reading ready
private async Task<Length> ReadSingleValue()
{
dataReceivedTaskCompletionSource = new TaskCompletionSource<Length>();

if (serialPort.IsOpen == false)
{
serialPort.Open();
}

dataReceivedTaskCompletionSource = new TaskCompletionSource<Length>();
var timeOutTask = Task.Delay(SensorReadTimeOut);

await Task.WhenAny(dataReceivedTaskCompletionSource.Task, timeOutTask);

var result = await dataReceivedTaskCompletionSource.Task;
serialPort.Close();

return result;
if (dataReceivedTaskCompletionSource.Task.IsCompletedSuccessfully == true)
{
return dataReceivedTaskCompletionSource.Task.Result;
}
return Length.Zero;
}

private void SerialPortDataReceived(object sender, SerialDataReceivedEventArgs e)
{
var len = serialPort.BytesToRead;

if (len > 3)
if (serialPort.IsOpen == false || serialPort.BytesToRead == 0 || dataReceivedTaskCompletionSource?.Task.IsCompletedSuccessfully == true)
{
serialPort.Read(readBuffer, 0, Math.Min(len, readBuffer.Length));
return;
}

if (len == 3)
{
var mm = readBuffer[0] << 8 | readBuffer[1];
var len = serialPort.BytesToRead;

serialPort.Read(readBuffer, 0, Math.Min(len, readBuffer.Length));

if (mm != 0)
for (int i = 0; i < len; i++)
{
if (readBuffer[i] == 0xFF)
{
serialDataBytesRead = 0;
}
else if (serialDataBytesRead == 0)
{
var length = new Length(mm, Length.UnitType.Millimeters);
dataReceivedTaskCompletionSource?.SetResult(length);
serialDataFirstByte = readBuffer[i];
serialDataBytesRead++;
}
else if (serialDataBytesRead == 1)
{
serialDataBytesRead = 2;
var lengthInMillimeters = serialDataFirstByte << 8 | readBuffer[i];

if (lengthInMillimeters != 0) //device should never return 0
{
var length = new Length(lengthInMillimeters, Length.UnitType.Millimeters);
dataReceivedTaskCompletionSource?.SetResult(length);
return;
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ public override Task Initialize()

public override async Task Run()
{
Resolver.Log.Info("Run...");

var distance = await me007ys.Read();
Resolver.Log.Info($"Initial distance is: {distance.Centimeters:N1}cm / {distance.Inches:N1}in");

Expand Down

0 comments on commit 24bd7d7

Please sign in to comment.