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

223 lines
7.3 KiB
C#

using System.Device.Gpio;
using System.Device.Pwm;
using Microsoft.Extensions.Logging;
using GSS2.Core.Abstractions;
namespace GSS2.Core.Hardware;
public class IlluminatorService : IDisposable
{
public record IlluminatorServiceConfiguration : ServiceConfigurationBase
{
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; init; }
public int Uv254PwmPin { get; init; }
public int Uv365PwmPin { get; init; }
public int WhiteRelayPin { get; init; }
public int Uv254RelayPin { get; init; }
public int Uv365RelayPin { get; init; }
public int FanPin { get; init; }
public int PwmFrequency { get; init; }
public double MaxWhitePwmDuty { get; init; }
public double MaxUv254PwmDuty { get; init; }
public double MaxUv365PwmDuty { get; init; }
}
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 event EventHandler<double>? WhiteIntencityChanged;
public event EventHandler<double>? Uv254IntencityChanged;
public event EventHandler<double>? Uv365IntencityChanged;
public IlluminatorService(ILogger<IlluminatorService> logger, IlluminatorServiceConfiguration? configuration = null)
{
_logger = logger;
_logger.LogInformation("Initialization");
try
{
if (configuration is null)
{
configuration = IlluminatorServiceConfiguration.Default;
_logger.LogWarning("Configuration not set. Using default configuration.");
}
_configuration = configuration;
_logger.LogInformation("Using following configuration: \n{}", _configuration.ToString("\n", 4));
CheckPwmPin(_configuration.WhitePwmPin);
CheckPwmPin(_configuration.Uv254PwmPin);
CheckPwmPin(_configuration.Uv365PwmPin);
_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 initialization");
throw;
}
_logger.LogInformation("Initialized");
}
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);
WhiteIntencityChanged?.Invoke(this, white.Value);
}
if (uv365 is not null)
{
_uv365Pwm.DutyCycle = CalculateDuty(uv365.Value, _configuration.MaxUv365PwmDuty);
Uv365IntencityChanged?.Invoke(this, uv365.Value);
}
if (uv254 is not null)
{
_uv254Pwm.DutyCycle = CalculateDuty(uv254.Value, _configuration.MaxUv254PwmDuty);
Uv254IntencityChanged?.Invoke(this, uv254.Value);
}
}
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);
}