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; } }