1
0
mirror of synced 2024-10-05 23:06:08 +00:00
MassiveKnob/Windows/Hardware/SerialMassiveKnobHardware.cs

181 lines
5.3 KiB
C#
Raw Normal View History

using System.Diagnostics;
using System.IO.Ports;
using System.Threading;
using System.Threading.Tasks;
namespace MassiveKnob.Hardware
{
public class SerialMassiveKnobHardware : AbstractMassiveKnobHardware
{
private readonly string portName;
private Thread workerThread;
private readonly CancellationTokenSource workerThreadCancellation = new CancellationTokenSource();
private readonly TaskCompletionSource<bool> workerThreadCompleted = new TaskCompletionSource<bool>();
public SerialMassiveKnobHardware(string portName)
{
this.portName = portName;
}
public override async Task TryConnect()
{
if (workerThread != null)
await Disconnect();
workerThread = new Thread(RunWorker)
{
Name = "SerialMassiveKnobHardware Worker"
};
workerThread.Start();
}
public override async Task Disconnect()
{
workerThreadCancellation.Cancel();
await workerThreadCompleted.Task;
workerThread = null;
}
private void RunWorker()
{
Observers.Connecting();
while (!workerThreadCancellation.IsCancellationRequested)
{
SerialPort serialPort = null;
void SafeCloseSerialPort()
{
try
{
serialPort?.Dispose();
}
catch
{
// ignroed
}
serialPort = null;
Observers.Disconnected();
Observers.Connecting();
}
var knobCount = 0;
while (serialPort == null && !workerThreadCancellation.IsCancellationRequested)
{
try
{
serialPort = new SerialPort(portName, 115200);
serialPort.Open();
// Send handshake
serialPort.Write(new[] { 'H', 'M', 'K', 'B' }, 0, 4);
// Wait for reply
serialPort.ReadTimeout = 1000;
var response = serialPort.ReadByte();
if ((char) response == 'H')
{
knobCount = serialPort.ReadByte();
if (knobCount > -1)
break;
}
SafeCloseSerialPort();
Thread.Sleep(500);
}
catch
{
SafeCloseSerialPort();
Thread.Sleep(500);
}
}
if (workerThreadCancellation.IsCancellationRequested)
{
SafeCloseSerialPort();
break;
}
var processingMessage = false;
Debug.Assert(serialPort != null, nameof(serialPort) + " != null");
serialPort.DataReceived += (sender, args) =>
{
if (args.EventType != SerialData.Chars || processingMessage)
return;
var senderPort = (SerialPort) sender;
processingMessage = true;
try
{
var message = (char) senderPort.ReadByte();
ProcessMessage(senderPort, message);
}
finally
{
processingMessage = false;
}
};
Observers.Connected(knobCount);
try
{
// This is where sending data to the hardware would be implemented
while (serialPort.IsOpen && !workerThreadCancellation.IsCancellationRequested)
{
Thread.Sleep(10);
}
}
catch
{
// ignored
}
Observers.Disconnected();
SafeCloseSerialPort();
if (!workerThreadCancellation.IsCancellationRequested)
Thread.Sleep(500);
}
workerThreadCompleted.TrySetResult(true);
}
private void ProcessMessage(SerialPort serialPort, char message)
{
switch (message)
{
case 'V':
var knobIndex = (byte)serialPort.ReadByte();
var volume = (byte)serialPort.ReadByte();
if (knobIndex < 255 && volume <= 100)
Observers.VolumeChanged(knobIndex, volume);
break;
}
}
}
public class SerialMassiveKnobHardwareFactory : IMassiveKnobHardwareFactory
{
public IMassiveKnobHardware Create(string portName)
{
return new SerialMassiveKnobHardware(portName);
}
}
}