2021-06-09 16:43:27 +00:00
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Diagnostics;
|
|
|
|
|
using System.IO.Ports;
|
|
|
|
|
using System.Security.Permissions;
|
|
|
|
|
using System.Threading;
|
2021-06-09 17:53:36 +00:00
|
|
|
|
using static Matrix_App.Defaults;
|
2021-06-09 16:43:27 +00:00
|
|
|
|
|
2021-08-08 12:50:24 +00:00
|
|
|
|
namespace Matrix_App.adds
|
2021-06-09 16:43:27 +00:00
|
|
|
|
{
|
|
|
|
|
public class PortCommandQueue
|
|
|
|
|
{
|
2021-07-04 12:56:52 +00:00
|
|
|
|
private const string ThreadDeliverName = "Arduino Port Deliver Thread";
|
2021-06-09 16:43:27 +00:00
|
|
|
|
|
2021-08-08 12:50:24 +00:00
|
|
|
|
private readonly Queue<byte[]> byteWriteQueue = new();
|
|
|
|
|
private readonly Queue<byte> statusByteQueue = new();
|
2021-06-09 16:43:27 +00:00
|
|
|
|
|
2021-08-08 12:50:24 +00:00
|
|
|
|
private readonly Thread portDeliverThread;
|
2021-06-09 16:43:27 +00:00
|
|
|
|
|
2021-08-08 12:50:24 +00:00
|
|
|
|
private readonly SerialPort tx;
|
2021-06-09 16:43:27 +00:00
|
|
|
|
|
2021-07-04 12:56:52 +00:00
|
|
|
|
private bool running;
|
2021-06-09 16:43:27 +00:00
|
|
|
|
|
2021-07-04 12:56:52 +00:00
|
|
|
|
private volatile bool kill;
|
2021-06-09 16:43:27 +00:00
|
|
|
|
|
2021-07-04 12:56:52 +00:00
|
|
|
|
private volatile bool isPortValid;
|
2021-06-09 16:43:27 +00:00
|
|
|
|
|
2021-08-08 12:50:24 +00:00
|
|
|
|
private readonly byte[] received = new byte[ArduinoReceiveBufferSize];
|
2021-06-09 16:43:27 +00:00
|
|
|
|
private int mark;
|
2021-08-08 12:50:24 +00:00
|
|
|
|
|
|
|
|
|
private volatile bool synchronized;
|
|
|
|
|
private bool updateRealtime;
|
|
|
|
|
|
|
|
|
|
public PortCommandQueue(ref SerialPort tx)
|
2021-06-09 16:43:27 +00:00
|
|
|
|
{
|
2021-08-08 12:50:24 +00:00
|
|
|
|
this.tx = tx;
|
2021-06-09 16:43:27 +00:00
|
|
|
|
|
2021-07-04 12:56:52 +00:00
|
|
|
|
portDeliverThread = new Thread(ManageQueue) { Name = ThreadDeliverName };
|
2021-06-09 16:43:27 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void ManageQueue()
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
while (!kill)
|
|
|
|
|
{
|
2021-08-08 12:50:24 +00:00
|
|
|
|
if (!isPortValid) continue;
|
|
|
|
|
if (byteWriteQueue.Count <= 0)
|
|
|
|
|
{
|
|
|
|
|
lock (byteWriteQueue)
|
|
|
|
|
{
|
|
|
|
|
Monitor.Wait(byteWriteQueue);
|
|
|
|
|
}
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2021-07-04 12:56:52 +00:00
|
|
|
|
byte[] bytes;
|
2021-08-08 12:50:24 +00:00
|
|
|
|
int statusByte;
|
2021-07-04 12:56:52 +00:00
|
|
|
|
lock (byteWriteQueue)
|
2021-06-09 16:43:27 +00:00
|
|
|
|
{
|
2021-07-04 12:56:52 +00:00
|
|
|
|
bytes = byteWriteQueue.Dequeue();
|
2021-08-08 12:50:24 +00:00
|
|
|
|
statusByte = statusByteQueue.Dequeue();
|
2021-07-04 12:56:52 +00:00
|
|
|
|
}
|
2021-06-09 16:43:27 +00:00
|
|
|
|
|
2021-08-08 12:50:24 +00:00
|
|
|
|
lock (tx)
|
2021-07-04 12:56:52 +00:00
|
|
|
|
{
|
2021-08-08 12:50:24 +00:00
|
|
|
|
var success = false;
|
|
|
|
|
var tryCounter = 0;
|
2021-07-04 12:56:52 +00:00
|
|
|
|
|
2021-08-08 12:50:24 +00:00
|
|
|
|
do
|
2021-06-09 16:43:27 +00:00
|
|
|
|
{
|
2021-08-08 12:50:24 +00:00
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
tx.Write(bytes, 0, bytes.Length);
|
|
|
|
|
|
|
|
|
|
var b = ArduinoErrorByte;
|
|
|
|
|
var errorFlag = false;
|
|
|
|
|
mark = 0;
|
|
|
|
|
while (!errorFlag && (b = tx.ReadByte()) != statusByte)
|
|
|
|
|
{
|
|
|
|
|
received[mark++] = (byte) b;
|
|
|
|
|
|
|
|
|
|
errorFlag = b == ArduinoErrorByte;
|
|
|
|
|
}
|
|
|
|
|
synchronized = b == ArduinoSynchronizationByte;
|
|
|
|
|
success = !errorFlag;
|
|
|
|
|
Debug.WriteLine("===================> Com Success !");
|
|
|
|
|
}
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
{
|
|
|
|
|
Debug.WriteLine("=============================> ERROR <=================================");
|
|
|
|
|
Debug.WriteLine(e.Message);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tryCounter++;
|
|
|
|
|
} while (!success && tryCounter < 3);
|
2021-06-09 16:43:27 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2021-08-08 12:50:24 +00:00
|
|
|
|
}
|
|
|
|
|
catch (ThreadInterruptedException)
|
2021-06-09 16:43:27 +00:00
|
|
|
|
{
|
|
|
|
|
Thread.CurrentThread.Interrupt();
|
2021-08-08 12:50:24 +00:00
|
|
|
|
}
|
2021-06-09 16:43:27 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-08-08 12:50:24 +00:00
|
|
|
|
[SecurityPermission(SecurityAction.Demand, ControlThread = true)]
|
2021-06-09 16:43:27 +00:00
|
|
|
|
public void Close()
|
|
|
|
|
{
|
|
|
|
|
try
|
|
|
|
|
{
|
2021-07-04 12:56:52 +00:00
|
|
|
|
if (!running) return;
|
|
|
|
|
kill = true;
|
|
|
|
|
portDeliverThread.Interrupt();
|
|
|
|
|
portDeliverThread.Join(1000);
|
2021-06-09 16:43:27 +00:00
|
|
|
|
}
|
|
|
|
|
catch (ThreadStartException)
|
|
|
|
|
{
|
|
|
|
|
// omit
|
|
|
|
|
}
|
|
|
|
|
catch (ThreadInterruptedException)
|
|
|
|
|
{
|
|
|
|
|
// omit
|
|
|
|
|
}
|
2021-08-08 12:50:24 +00:00
|
|
|
|
finally
|
|
|
|
|
{
|
|
|
|
|
if (tx.IsOpen)
|
|
|
|
|
{
|
|
|
|
|
tx.Close();
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-06-09 16:43:27 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-08-08 12:50:24 +00:00
|
|
|
|
private void EnqueueArduinoCommand(params byte[] bytes)
|
2021-06-09 16:43:27 +00:00
|
|
|
|
{
|
2021-08-08 12:50:24 +00:00
|
|
|
|
if (!updateRealtime && bytes[0] != ArduinoInstruction.OpcodeScale &&
|
|
|
|
|
bytes[0] != ArduinoInstruction.OpcodePush)
|
|
|
|
|
return;
|
|
|
|
|
|
2021-06-09 16:43:27 +00:00
|
|
|
|
if (!running)
|
|
|
|
|
{
|
|
|
|
|
running = true;
|
|
|
|
|
portDeliverThread.Start();
|
|
|
|
|
}
|
2021-08-08 12:50:24 +00:00
|
|
|
|
|
2021-07-04 12:56:52 +00:00
|
|
|
|
lock (byteWriteQueue)
|
2021-06-09 16:43:27 +00:00
|
|
|
|
{
|
2021-08-08 12:50:24 +00:00
|
|
|
|
Monitor.Pulse(byteWriteQueue);
|
|
|
|
|
if (byteWriteQueue.Count >= ArduinoCommandQueueSize) return;
|
|
|
|
|
lock (byteWriteQueue)
|
2021-06-09 16:43:27 +00:00
|
|
|
|
{
|
2021-08-08 12:50:24 +00:00
|
|
|
|
byteWriteQueue.Enqueue(bytes);
|
2021-06-09 16:43:27 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void EnqueueArduinoCommand(byte opcode, params byte[] data)
|
|
|
|
|
{
|
|
|
|
|
byte[] wrapper = new byte[data.Length + 1];
|
2021-07-04 12:56:52 +00:00
|
|
|
|
Buffer.BlockCopy(data, 0, wrapper, 1, data.Length);
|
2021-06-09 16:43:27 +00:00
|
|
|
|
wrapper[0] = opcode;
|
|
|
|
|
|
2021-08-08 12:50:24 +00:00
|
|
|
|
statusByteQueue.Enqueue(ArduinoSuccessByte);
|
2021-06-09 16:43:27 +00:00
|
|
|
|
EnqueueArduinoCommand(wrapper);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void DequeueAll()
|
|
|
|
|
{
|
|
|
|
|
lock (byteWriteQueue)
|
|
|
|
|
{
|
|
|
|
|
byteWriteQueue.Clear();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-08-08 12:50:24 +00:00
|
|
|
|
public static void WaitForLastDequeue()
|
2021-06-09 16:43:27 +00:00
|
|
|
|
{
|
2021-08-08 12:50:24 +00:00
|
|
|
|
var timeCount = 0;
|
|
|
|
|
var wait = true;
|
2021-07-04 12:56:52 +00:00
|
|
|
|
|
2021-06-09 16:43:27 +00:00
|
|
|
|
while(wait)
|
|
|
|
|
{
|
|
|
|
|
timeCount++;
|
|
|
|
|
Thread.Sleep(500);
|
|
|
|
|
|
2021-06-09 17:53:36 +00:00
|
|
|
|
wait = timeCount == DequeueWaitTimeoutCounter;
|
2021-06-09 16:43:27 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public byte[] GetLastData()
|
|
|
|
|
{
|
2021-08-08 12:50:24 +00:00
|
|
|
|
return received;
|
2021-06-09 16:43:27 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void ValidatePort()
|
|
|
|
|
{
|
2021-08-08 12:50:24 +00:00
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
if (!tx.IsOpen)
|
|
|
|
|
{
|
|
|
|
|
tx.Open();
|
|
|
|
|
isPortValid = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
{
|
|
|
|
|
isPortValid = false;
|
|
|
|
|
|
|
|
|
|
Debug.WriteLine("Failed opening port: " + e.Message);
|
|
|
|
|
}
|
2021-06-09 16:43:27 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void InvalidatePort()
|
|
|
|
|
{
|
|
|
|
|
isPortValid = false;
|
2021-08-08 12:50:24 +00:00
|
|
|
|
tx.Close();
|
2021-06-09 16:43:27 +00:00
|
|
|
|
}
|
|
|
|
|
|
2021-08-08 12:50:24 +00:00
|
|
|
|
/// <summary>
|
|
|
|
|
/// Returns last location of written byte in the received buffer.
|
|
|
|
|
/// Call clears the mark. Any other call will return 0, unless the mark has been
|
|
|
|
|
/// altered by reading new data from the serial port.
|
|
|
|
|
/// </summary>
|
|
|
|
|
/// <returns></returns>
|
2021-06-09 16:43:27 +00:00
|
|
|
|
public int GetMark()
|
|
|
|
|
{
|
2021-08-08 12:50:24 +00:00
|
|
|
|
var tmp = mark;
|
2021-06-09 16:43:27 +00:00
|
|
|
|
mark = 0;
|
|
|
|
|
return tmp;
|
|
|
|
|
}
|
2021-08-08 12:50:24 +00:00
|
|
|
|
|
|
|
|
|
public void EnqueueArduinoCommandSynchronized(byte[] bytes)
|
|
|
|
|
{
|
|
|
|
|
statusByteQueue.Enqueue(ArduinoSynchronizationByte);
|
|
|
|
|
EnqueueArduinoCommand(bytes);
|
|
|
|
|
|
|
|
|
|
while (!synchronized)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
Debug.WriteLine("======================> Synchronized!");
|
|
|
|
|
synchronized = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void SetRealtimeUpdates(bool @checked)
|
|
|
|
|
{
|
|
|
|
|
updateRealtime = @checked;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public bool GetRealtimeUpdates()
|
|
|
|
|
{
|
|
|
|
|
return updateRealtime;
|
|
|
|
|
}
|
2021-06-09 16:43:27 +00:00
|
|
|
|
}
|
|
|
|
|
}
|