common/Hardware/Common.Hardware.SIRT/SIRTBroadcaster.cs
2026-04-23 17:50:07 +02:00

230 lines
6.8 KiB
C#

namespace Common.Hardware.SIRT
{
using Common.Hardware.SIRT.Tasks;
using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;
public class SIRTBroadcaster
{
private readonly SIRTChanel[] chanels;
private readonly ConcurrentDictionary<uint, SIRTChanel> chanelsMap;
private readonly ConcurrentDictionary<uint, SIRTTask> tasks;
private readonly SIRTStream sirtStream;
private readonly bool log_RX_TX;
private CancellationTokenSource cancellationTokenSource;
private CancellationToken cancellationToken;
public SIRTBroadcaster(string portName, bool log_RX_TX = true)
{
this.chanels = new SIRTChanel[]
{
new SIRTChanel(),
new SIRTChanel(),
new SIRTChanel(),
new SIRTChanel(),
new SIRTChanel(),
};
this.tasks = new ConcurrentDictionary<uint, SIRTTask>();
this.sirtStream = new SIRTStream(portName, false);
this.log_RX_TX = log_RX_TX;
this.Id = "00-00-00-00-00-00-00-00";
}
public event Action<SIRTBroadcaster> Connected;
public event Action<SIRTBroadcaster> Disconnected;
public event Action<SIRTMessage> MessageReceived;
public string Id { get; private set; }
public int Frequency { get; private set; }
public bool IsOpen => this.sirtStream.IsOpen;
public string PortName => this.sirtStream.PortName;
public void Close()
{
this.sirtStream.Close();
try
{
this.tasks.Clear();
}
catch (Exception e)
{
this.LogMessage(e);
}
try
{
this.cancellationTokenSource.Cancel();
}
catch (Exception e)
{
this.LogMessage(e);
}
foreach (var chanel in this.chanels)
{
chanel.Captured -= this.Chanel_Captured;
chanel.Released -= this.Chanel_Released;
}
this.Disconnected?.Invoke(this);
}
public void Open()
{
this.sirtStream.Open();
if (this.sirtStream.IsOpen)
{
this.cancellationTokenSource = new CancellationTokenSource();
this.cancellationToken = this.cancellationTokenSource.Token;
_ = Task.Factory
.StartNew(this.ReceiveAsync, this.cancellationToken)
.ContinueWith(this.LogContinuationError);
this.LogMessage("Activating SIRT ...");
if (this.TryActivate(out var id, out var frequency))
{
this.Id = id;
this.Frequency = frequency;
this.Connected?.Invoke(this);
this.LogMessage("Activated");
foreach (var chanel in this.chanels)
{
chanel.Captured += this.Chanel_Captured;
chanel.Released += this.Chanel_Released;
}
}
else
{
this.Close();
this.LogMessage("Activation failed!");
}
}
}
/// <summary>
/// Checks if the given task can be sent then replaces existing SIRTTask (if any) and starts the new one.
/// </summary>
public bool Start(SIRTTask task)
{
if (task.Frequency == this.Frequency)
{
task.SirtId = this.Id;
task = this.tasks.AddOrUpdate(task.RequestAddress, addr => task, (addr, oldTask) => task);
task = this.tasks.AddOrUpdate(task.ResponseAddress, addr => task, (addr, oldTask) => task);
var bytes = task.Start();
this.sirtStream.Write(bytes);
if (this.log_RX_TX)
{
this.LogMessage(task);
}
return true;
}
return false;
}
private void Chanel_Released(SIRTChanel chanel)
=> this.chanelsMap.TryRemove(chanel.Address, out var _);
private void Chanel_Captured(SIRTChanel chanel)
{
this.chanelsMap.TryRemove(chanel.Address, out var _);
this.chanelsMap.TryAdd(chanel.Address, chanel);
}
private void LogContinuationError(Task task)
{
if (task?.Exception != null)
{
this.LogMessage(task.Exception);
}
}
private void ReceiveAsync()
{
this.LogMessage($"Message receiving started!");
var cancellationToken = this.cancellationToken;
foreach (SIRTMessage message in this.sirtStream.ReadMessages())
{
message.Timestamp = DateTimeOffset.UtcNow;
message.Frequency = this.Frequency;
message.SirtId = this.Id;
//if (this.chanelsMap.TryGetValue(message.Address, out var chanel))
//{
// chanel.Receive(message);
//}
this.MessageReceived?.Invoke(message);
if (this.tasks.TryGetValue(message.Address, out var task))
{
task.Receive(message);
if (task.State == SIRTTaskState.Completed || task.State == SIRTTaskState.Cancelled)
{
this.tasks.TryRemove(task.RequestAddress, out _);
this.tasks.TryRemove(task.ResponseAddress, out _);
}
}
if (this.log_RX_TX)
{
this.LogMessage(message);
}
cancellationToken.ThrowIfCancellationRequested();
}
this.LogMessage($"Message receiving stopped!");
}
private void LogMessage(object message)
=> SIRTLogger.LogMessage($"{this.PortName}|{nameof(SIRTBroadcaster)}|{message}");
public bool TryCaptureChanel(uint address, out SIRTChanel chanel)
{
chanel = null;
if (this.chanelsMap.TryGetValue(address, out chanel))
{
return true;
}
foreach (var _chanel in this.chanels)
{
if (_chanel.IsFree)
{
_chanel.Capture(address);
this.chanelsMap.AddOrUpdate(address, _chanel, (_1, _2) => _chanel);
chanel = _chanel;
break;
}
}
return chanel != null;
}
}
}