This repository has been archived on 2023-12-10. You can view files and clone it, but cannot push or open issues or pull requests.
PainterlyUNO/Matrix App/PortCommandQueue.cs

183 lines
4.5 KiB
C#

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.Ports;
using System.Security.Permissions;
using System.Text;
using System.Threading;
using static MatrixDesigner.Defaults;
namespace Matrix_App
{
public class PortCommandQueue
{
private const string threadDeliverName = "Arduino Port Deliver Thread";
private Queue<byte[]> byteWriteQueue = new Queue<byte[]>();
private Thread portDeliverThread;
private SerialPort port;
private bool running = false;
private volatile bool kill = false;
private volatile bool isPortValid = false;
private byte[] recived = new byte[ARDUINO_RECIVCE_BUFFER_SIZE];
private int mark;
public PortCommandQueue(ref SerialPort port)
{
this.port = port;
portDeliverThread = new Thread(new ThreadStart(ManageQueue));
portDeliverThread.Name = threadDeliverName;
}
private void ManageQueue()
{
try
{
while (!kill)
{
if (byteWriteQueue.Count > 0)
{
byte[] bytes;
lock (byteWriteQueue)
{
bytes = byteWriteQueue.Dequeue();
}
lock (port)
{
if (isPortValid)
{
port.Open();
port.Write(bytes, 0, bytes.Length);
int b;
mark = 0;
while((b = port.ReadByte()) != ARDUINO_SUCCESS_BYTE)
{
recived[mark++] = (byte) b;
}
port.Close();
}
}
}
}
} catch (ThreadInterruptedException)
{
Thread.CurrentThread.Interrupt();
return;
}
catch (Exception)
{
// omit
}
}
[SecurityPermissionAttribute(SecurityAction.Demand, ControlThread = true)]
public void Close()
{
try
{
if (running)
{
kill = true;
portDeliverThread.Interrupt();
portDeliverThread.Join(1000);
}
}
catch (ThreadStartException)
{
// omit
}
catch (ThreadInterruptedException)
{
// omit
}
}
public void EnqueueArduinoCommand(params byte[] bytes)
{
if (!running)
{
running = true;
portDeliverThread.Start();
}
if (byteWriteQueue.Count < ARDUINO_COMMAND_QUEUE_SIZE)
{
lock (byteWriteQueue)
{
byteWriteQueue.Enqueue(bytes);
}
}
}
public void EnqueueArduinoCommand(byte opcode, params byte[] data)
{
byte[] wrapper = new byte[data.Length + 1];
System.Buffer.BlockCopy(data, 0, wrapper, 1, data.Length);
wrapper[0] = opcode;
EnqueueArduinoCommand(wrapper);
}
public void DequeueAll()
{
lock (byteWriteQueue)
{
byteWriteQueue.Clear();
}
}
internal void WaitForLastDequeue()
{
int timeCount = 0;
bool wait = true;
while(wait)
{
lock(byteWriteQueue)
{
wait = byteWriteQueue.Count != 0;
}
timeCount++;
Thread.Sleep(500);
wait = timeCount == DEQUEUE_WAIT_TIMEOUT_COUNTER;
}
}
public byte[] GetLastData()
{
return recived;
}
public void ValidatePort()
{
isPortValid = true;
}
public void InvalidatePort()
{
isPortValid = false;
}
public int GetMark()
{
int tmp = mark;
mark = 0;
return tmp;
}
}
}