Files
BQP/srcs/RobotNet10/RobotApp/RobotNet10.RobotApp/Drivers/Varta/Vartaservice/VartaChargerSimulatorService.cs
2026-07-13 09:25:40 +07:00

166 lines
4.7 KiB
C#

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using RobotNet10.CANOpen;
namespace RobotNet10.RobotApp.Drivers.Battery.Varta;
public sealed class VartaChargerSimulatorService : IHostedService, IDisposable
{
private readonly ILogger<VartaChargerSimulatorService> _logger;
private readonly ICanOpenManager _canOpenManager;
private readonly VartaChargerSimulatorOptions _options;
private readonly SemaphoreSlim _controlLock = new(1, 1);
private Task? _runTask;
private CancellationTokenSource? _runCts;
private string _currentInterface = "can0";
private bool _disposed;
public bool IsRunning => _runTask is { IsCompleted: false };
public string CurrentInterface => _currentInterface;
public VartaChargerSimulatorService(
IConfiguration configuration,
ILogger<VartaChargerSimulatorService> logger,
ICanOpenManager canOpenManager)
{
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_canOpenManager = canOpenManager ?? throw new ArgumentNullException(nameof(canOpenManager));
_options = new VartaChargerSimulatorOptions();
configuration.GetSection("Varta:Charger59VSimulator").Bind(_options);
}
public async Task StartAsync(CancellationToken cancellationToken)
{
if (_options.Enabled)
{
await StartSimulatorAsync(_options.CanInterface, cancellationToken);
return;
}
_logger.LogInformation("Varta Charger59V simulator is disabled at startup.");
}
public async Task StopAsync(CancellationToken cancellationToken)
{
await StopSimulatorAsync(cancellationToken);
}
public async Task<bool> StartSimulatorAsync(string? canInterface = null, CancellationToken cancellationToken = default)
{
ThrowIfDisposed();
await _controlLock.WaitAsync(cancellationToken);
try
{
if (_runTask is { IsCompleted: false })
{
return false;
}
_currentInterface = string.IsNullOrWhiteSpace(canInterface) ? "can0" : canInterface;
_runCts = new CancellationTokenSource();
_runTask = RunSimulatorAsync(_currentInterface, _runCts.Token);
return true;
}
finally
{
_controlLock.Release();
}
}
public async Task<bool> StopSimulatorAsync(CancellationToken cancellationToken = default)
{
ThrowIfDisposed();
Task? runTask;
CancellationTokenSource? runCts;
await _controlLock.WaitAsync(cancellationToken);
try
{
if (_runTask is not { IsCompleted: false } || _runCts is null)
{
return false;
}
runTask = _runTask;
runCts = _runCts;
_runTask = null;
_runCts = null;
}
finally
{
_controlLock.Release();
}
runCts.Cancel();
try
{
await runTask.WaitAsync(cancellationToken);
}
catch (OperationCanceledException)
{
}
finally
{
runCts.Dispose();
}
return true;
}
private async Task RunSimulatorAsync(string canInterface, CancellationToken token)
{
_logger.LogInformation("Starting Varta Charger59V simulator on CAN interface {CanInterface}", canInterface);
try
{
var simulator = new Charger59V(_canOpenManager, canInterface, token);
await simulator.RunAsync();
}
catch (OperationCanceledException) when (token.IsCancellationRequested)
{
_logger.LogInformation("Varta Charger59V simulator stopped.");
}
catch (Exception ex)
{
_logger.LogError(ex, "Varta Charger59V simulator crashed.");
}
}
public void Dispose()
{
if (_disposed)
{
return;
}
_disposed = true;
_runCts?.Cancel();
_runCts?.Dispose();
_controlLock.Dispose();
}
private void ThrowIfDisposed()
{
if (_disposed)
{
throw new ObjectDisposedException(nameof(VartaChargerSimulatorService));
}
}
}
public sealed class VartaChargerSimulatorOptions
{
public bool Enabled { get; set; }
public string CanInterface { get; set; } = "can0";
}
public sealed class VartaChargerSimulatorStartRequest
{
public string? CanInterface { get; set; }
}