Files
GSS2Rework/GSS2.Core/Hardware/IlluminatorService.cs
T

218 lines
7.3 KiB
C#

using System.Device.Gpio;
using System.Device.Pwm;
using Microsoft.Extensions.Logging;
namespace GSS2.Core.Hardware;
public class IlluminatorService : IDisposable
{
public class IlluminatorServiceConfiguration
{
public static IlluminatorServiceConfiguration Default => new IlluminatorServiceConfiguration
{
WhitePwmPin = 13,
Uv254PwmPin = 18,
Uv365PwmPin = 12,
WhiteRelayPin = 16,
Uv254RelayPin = 15,
Uv365RelayPin = 20,
FanPin = 21,
PwmFrequency = 200,
MaxWhitePwmDuty = 1.0,
MaxUv254PwmDuty = 1.0,
MaxUv365PwmDuty = 1.0
};
public int WhitePwmPin { get; set; }
public int Uv254PwmPin { get; set; }
public int Uv365PwmPin { get; set; }
public int WhiteRelayPin { get; set; }
public int Uv254RelayPin { get; set; }
public int Uv365RelayPin { get; set; }
public int FanPin { get; set; }
public int PwmFrequency { get; set; }
public double MaxWhitePwmDuty { get; set; }
public double MaxUv254PwmDuty { get; set; }
public double MaxUv365PwmDuty { get; set; }
}
private static readonly Dictionary<int, int> PinPwmChips = new()
{
{ 12, 0 },
{ 13, 0 },
{ 14, 0 },
{ 15, 0 },
{ 18, 0 },
{ 19, 0 },
};
private static readonly Dictionary<int, int> PinPwmChannels = new()
{
{ 12, 0 },
{ 13, 1 },
{ 14, 2 },
{ 15, 3 },
{ 18, 2 },
{ 19, 3 }
};
private bool _disposedValue;
private readonly ILogger<IlluminatorService> _logger;
private readonly IlluminatorServiceConfiguration _configuration;
private readonly GpioController _gpio;
private readonly PwmChannel _whitePwm;
private readonly PwmChannel _uv254Pwm;
private readonly PwmChannel _uv365Pwm;
private readonly GpioPin _whiteRelay;
private readonly GpioPin _uv254Relay;
private readonly GpioPin _uv365Relay;
private readonly GpioPin _fanRelay;
public IlluminatorService(ILogger<IlluminatorService> logger, IlluminatorServiceConfiguration? configuration = null)
{
_logger = logger;
_logger.LogInformation("Illuminator initialization");
if (configuration is null)
{
_logger.LogWarning("Illuminator configuration not set. Using default configuration.");
_configuration = IlluminatorServiceConfiguration.Default;
}
else
{
_configuration = configuration;
}
_logger.LogDebug(@$"Illuminator use following configuration:
WhitePwmPin: {_configuration.WhitePwmPin}
Uv254PwmPin: {_configuration.Uv254PwmPin}
Uv365PwmPin: {_configuration.Uv365PwmPin}
WhiteRelayPin: {_configuration.WhiteRelayPin}
Uv254RelayPin: {_configuration.Uv254RelayPin}
Uv365RelayPin: {_configuration.Uv365RelayPin}
FanPin: {_configuration.FanPin}
PwmFrequency: {_configuration.PwmFrequency}
MaxWhitePwmDuty: {_configuration.MaxWhitePwmDuty}
MaxUv254PwmDuty: {_configuration.MaxUv254PwmDuty}
MaxUv365PwmDuty: {_configuration.MaxUv365PwmDuty}
");
CheckPwmPin(_configuration.WhitePwmPin);
CheckPwmPin(_configuration.Uv254PwmPin);
CheckPwmPin(_configuration.Uv365PwmPin);
try
{
_gpio = new GpioController();
_whitePwm = PwmChannel.Create(PinPwmChips[_configuration.WhitePwmPin], PinPwmChannels[_configuration.WhitePwmPin], _configuration.PwmFrequency, CalculateDuty(0, _configuration.MaxWhitePwmDuty));
_uv254Pwm = PwmChannel.Create(PinPwmChips[_configuration.Uv254PwmPin], PinPwmChannels[_configuration.Uv254PwmPin], _configuration.PwmFrequency, CalculateDuty(0, _configuration.MaxUv254PwmDuty));
_uv365Pwm = PwmChannel.Create(PinPwmChips[_configuration.Uv365PwmPin], PinPwmChannels[_configuration.Uv365PwmPin], _configuration.PwmFrequency, CalculateDuty(0, _configuration.MaxUv365PwmDuty));
_whiteRelay = _gpio.OpenPin(_configuration.WhiteRelayPin, PinMode.Output, PinValue.Low);
_uv254Relay = _gpio.OpenPin(_configuration.Uv254RelayPin, PinMode.Output, PinValue.Low);
_uv365Relay = _gpio.OpenPin(_configuration.Uv365RelayPin, PinMode.Output, PinValue.Low);
_fanRelay = _gpio.OpenPin(_configuration.FanPin, PinMode.Output, PinValue.Low);
}
catch (Exception e)
{
_logger.LogCritical(e, "An exception occurred while illuminator initialization");
throw;
}
}
public void SetIntensity(double? white = null, double? uv365 = null, double? uv254 = null)
{
try
{
if (white is not null) _whitePwm.DutyCycle = CalculateDuty(white.Value, _configuration.MaxWhitePwmDuty);
if (uv365 is not null) _uv365Pwm.DutyCycle = CalculateDuty(uv365.Value, _configuration.MaxUv365PwmDuty);
if (uv254 is not null) _uv254Pwm.DutyCycle = CalculateDuty(uv254.Value, _configuration.MaxUv254PwmDuty);
}
catch (Exception e)
{
_logger.LogError(e, "An exception occurred while setting illuminator intensity");
}
}
public void TurnOn()
{
try
{
_fanRelay.Write(PinValue.High);
_whitePwm.Start();
_uv254Pwm.Start();
_uv365Pwm.Start();
_whiteRelay.Write(PinValue.High);
_uv254Relay.Write(PinValue.High);
_uv365Relay.Write(PinValue.High);
}
catch (Exception e)
{
_logger.LogError(e, "An exception occurred while turning on illuminator");
}
}
public void TurnOff()
{
try
{
_whitePwm.Stop();
_uv254Pwm.Stop();
_uv365Pwm.Stop();
_whiteRelay.Write(PinValue.Low);
_uv254Relay.Write(PinValue.Low);
_uv365Relay.Write(PinValue.Low);
_fanRelay.Write(PinValue.Low);
}
catch (Exception e)
{
_logger.LogError(e, "An exception occurred while turning off illuminator");
}
}
protected virtual void Dispose(bool disposing)
{
if (!_disposedValue)
{
if (disposing)
{
try
{
TurnOff();
}
catch { }
_whiteRelay?.Dispose();
_uv254Relay?.Dispose();
_uv365Relay?.Dispose();
_fanRelay?.Dispose();
_whitePwm?.Dispose();
_uv254Pwm?.Dispose();
_uv365Pwm?.Dispose();
_gpio?.Dispose();
}
_disposedValue = true;
}
}
void IDisposable.Dispose()
{
Dispose(disposing: true);
GC.SuppressFinalize(this);
}
private static void CheckPwmPin(int pin)
{
if (!PinPwmChips.TryGetValue(pin, out var _) || !PinPwmChannels.TryGetValue(pin, out var _))
throw new ArgumentException($"Unsupported PWM pin {pin}");
}
private static double CalculateDuty(double intensity, double maxDuty) => Math.Clamp(intensity, 0.0, 1.0) * Math.Clamp(maxDuty, 0.0, 1.0);
}