using Sick.Tim781s.Colab.Commands;
using Sick.Tim781s.Colab.Helpers;
using Sick.Tim781s.Colab.Interfaces;
namespace Sick.Tim781s.Colab;
///
/// ColaB session manager for handling send, receive and process telegrams
///
public sealed class ColaBSession : IDisposable
{
private readonly ITcpClient _tcpClient;
private readonly object _lock = new();
private bool _disposed;
public bool IsOpen
{
get
{
lock (_lock)
{
return _tcpClient.IsConnected;
}
}
}
public ColaBSession(ITcpClient tcpClient)
{
_tcpClient = tcpClient ?? throw new ArgumentNullException(nameof(tcpClient));
}
///
/// Opens the session (connects to scanner)
///
public void Open(int timeoutMs = 5000)
{
if (_disposed)
throw new ObjectDisposedException(nameof(ColaBSession));
if (IsOpen)
return;
_tcpClient.Connect(timeoutMs);
}
///
/// Closes the session (disconnects from scanner)
///
public void Close()
{
if (_disposed)
return;
_tcpClient.Disconnect();
}
///
/// Executes a command and waits for reply
///
public void ExecuteCommand(IColaBCommand command, int timeoutMs = 5000)
{
if (_disposed)
throw new ObjectDisposedException(nameof(ColaBSession));
if (!IsOpen)
throw new InvalidOperationException("Session is not open");
// Create ColaB frame from command
var commandData = command.GetCommandData();
var frame = ColaBHelper.CreateFrame(commandData.Span);
// Send frame
_tcpClient.Send(frame);
// Receive reply with retry logic
byte[]? replyFrame = null;
int retries = 3;
for (int i = 0; i < retries; i++)
{
try
{
replyFrame = _tcpClient.Receive(timeoutMs);
break;
}
catch (TimeoutException) when (i < retries - 1)
{
// Retry on timeout
System.Threading.Thread.Sleep(100);
continue;
}
}
if (replyFrame == null || replyFrame.Length == 0)
{
throw new TimeoutException($"No reply received after {retries} attempts");
}
// Parse frame and extract command data
if (ColaBHelper.TryParseFrame(replyFrame, out var replyData, out _))
{
// Process reply
command.ProcessReply(replyData.ToArray());
}
else
{
throw new InvalidOperationException($"Failed to parse reply frame. Raw reply: {BitConverter.ToString(replyFrame.Take(64).ToArray())}");
}
}
public void Dispose()
{
if (_disposed)
return;
Close();
_disposed = true;
}
}