using Microsoft.Extensions.Logging;
using RobotNet10.CANOpen.Enums;
using RobotNet10.CANOpen.Interfaces;
namespace RobotNet10.CANOpen.Services;
///
/// SYNC Producer - phát tin nhắn SYNC định kỳ cho synchronous PDOs
///
public class SyncProducer : IDisposable
{
private readonly ICanBus _canBus;
private readonly uint _cobId;
private readonly ILogger? _logger;
private Timer? _timer;
private byte _counter;
private bool _useCounter;
private bool _isRunning;
public bool IsRunning => _isRunning;
public int IntervalMs { get; private set; }
public SyncProducer(ICanBus canBus, uint cobId = (uint)CanMessageType.Sync, ILogger? logger = null)
{
_canBus = canBus ?? throw new ArgumentNullException(nameof(canBus));
_cobId = cobId;
_logger = logger;
_counter = 0;
_useCounter = false;
_isRunning = false;
}
///
/// Start SYNC producer với interval tính bằng milliseconds
///
/// SYNC interval in milliseconds (thường 1-100ms)
/// Nếu true, SYNC message sẽ có counter byte (1-240)
public void Start(int intervalMs, bool useCounter = false)
{
if (_isRunning)
Stop();
IntervalMs = intervalMs;
_useCounter = useCounter;
_counter = 0;
_isRunning = true;
_timer = new Timer(SendSyncCallback, null, 0, intervalMs);
}
///
/// Stop SYNC producer
///
public void Stop()
{
_timer?.Dispose();
_timer = null;
_isRunning = false;
_counter = 0;
}
///
/// Gửi một SYNC message thủ công (không dùng timer)
///
public async Task SendSyncAsync(CancellationToken ct = default)
{
byte[] data = Array.Empty();
if (_useCounter)
{
_counter++;
if (_counter > 240)
_counter = 1;
data = new byte[] { _counter };
}
await _canBus.SendFrameAsync(_cobId, data, ct);
}
private async void SendSyncCallback(object? state)
{
try
{
await SendSyncAsync(CancellationToken.None);
}
catch (Exception ex)
{
// Log error nhưng không dừng timer
_logger?.LogError(ex, "Failed to send SYNC message with COB-ID 0x{CobId:X3}", _cobId);
}
}
public void Dispose()
{
Stop();
}
}