未验证 提交 a457e611 编写于 作者: J Jose Perez Rodriguez 提交者: GitHub

Adding implementation for the PwmController (#57)

Adding implementation for the PwmController
上级 15fdf91b
......@@ -3,11 +3,8 @@
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
using System.Device.Gpio.Drivers;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
......@@ -105,6 +102,7 @@ namespace System.Device.Gpio
throw new InvalidOperationException("Can not close a pin that is not yet opened.");
}
_driver.ClosePin(logicalPinNumber);
_openPins.Remove(pinNumber);
}
/// <summary>
......@@ -277,9 +275,11 @@ namespace System.Device.Gpio
private void Dispose(bool disposing)
{
foreach (int pin in _openPins)
while (_openPins.Count > 0)
{
int pin = _openPins.FirstOrDefault();
_driver.ClosePin(pin);
_openPins.Remove(pin);
}
_driver.Dispose();
}
......
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
using System.IO;
namespace System.Device.Pwm.Drivers
{
public class UnixPwmDriver : PwmDriver
{
private const string PwmPath = "/sys/class/pwm";
private Dictionary<(int, int), int> _exportedChannels = new Dictionary<(int, int), int>();
protected internal override void ChangeDutyCycle(int pwmChip, int pwmChannel, double dutyCyclePercentage)
{
if (_exportedChannels[(pwmChip, pwmChannel)] == 1)
{
throw new InvalidOperationException("Can not change the duty cycle if Pwm has not started.");
}
int dutyCycleInNanoSeconds = (int)(_exportedChannels[(pwmChip, pwmChannel)] * dutyCyclePercentage / 100.0);
string dutyCyclePath = Path.Combine(PwmPath, $"pwmchip{pwmChip}", $"pwm{pwmChannel}", "duty_cycle");
File.WriteAllText(dutyCyclePath, Convert.ToString(dutyCycleInNanoSeconds));
}
protected internal override void CloseChannel(int pwmChip, int pwmChannel)
{
ValidatePWMChannel(pwmChip, pwmChannel);
string channelPath = Path.Combine(PwmPath, $"pwmchip{pwmChip}", $"pwm{pwmChannel}");
if (Directory.Exists(channelPath))
{
File.WriteAllText(Path.Combine(PwmPath, $"pwmchip{pwmChip}", "unexport"), Convert.ToString(pwmChannel));
_exportedChannels.Remove((pwmChip, pwmChannel));
}
}
protected internal override void OpenChannel(int pwmChip, int pwmChannel)
{
ValidatePWMChannel(pwmChip, pwmChannel);
string channelPath = Path.Combine(PwmPath, $"pwmchip{pwmChip}", $"pwm{pwmChannel}");
if (!Directory.Exists(channelPath))
{
File.WriteAllText(Path.Combine(PwmPath, $"pwmchip{pwmChip}", "export"), Convert.ToString(pwmChannel));
_exportedChannels.Add((pwmChip, pwmChannel), -1);
}
}
protected internal override void StartWriting(int pwmChip, int pwmChannel, double frequencyInHertz, double dutyCyclePercentage)
{
// In Linux the period needs to be a whole number, and can't have decimal point.
int periodInNanoSeconds = (int)((1.0 / frequencyInHertz) * 1_000_000_000);
// In Linux the dutyCycle needs to be a whole number, and can't have decimal point.
int dutyCycleInNanoSeconds = (int)(periodInNanoSeconds * dutyCyclePercentage / 100.0);
string periodPath = Path.Combine(PwmPath, $"pwmchip{pwmChip}", $"pwm{pwmChannel}", "period");
File.WriteAllText(periodPath, Convert.ToString(periodInNanoSeconds));
_exportedChannels[(pwmChip, pwmChannel)] = periodInNanoSeconds;
string dutyCyclePath = Path.Combine(PwmPath, $"pwmchip{pwmChip}", $"pwm{pwmChannel}", "duty_cycle");
File.WriteAllText(dutyCyclePath, Convert.ToString(dutyCycleInNanoSeconds));
string enablePath = Path.Combine(PwmPath, $"pwmchip{pwmChip}", $"pwm{pwmChannel}", "period");
File.WriteAllText(enablePath, "1"); // Enable PWM
}
protected internal override void StopWriting(int pwmChip, int pwmChannel)
{
string enablePath = Path.Combine(PwmPath, $"pwmchip{pwmChip}", $"pwm{pwmChannel}", "period");
File.WriteAllText(enablePath, "0"); // Disable PWM
}
private void ValidatePWMChannel(int pwmChip, int pwmChannel)
{
string chipPath = Path.Combine(PwmPath, $"pwmchip{pwmChip}");
if (!Directory.Exists(chipPath))
{
throw new ArgumentException($"The chip number {pwmChip} is invalid or is not enabled.");
}
string supportedChannels = File.ReadAllText(Path.Combine(chipPath, "npwm"));
int numSupportedChannels;
if (int.TryParse(supportedChannels, out numSupportedChannels))
{
if (pwmChip < 0 || pwmChip >= numSupportedChannels)
{
throw new ArgumentException($"The pwm chip {pwmChip} does not support the channel {pwmChannel}");
}
}
else
{
throw new IOException($"Unable to parse the number of supported channels at {Path.Combine(chipPath, "npwm")}");
}
}
}
}
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
using System.IO;
namespace System.Device.Pwm.Drivers
{
public class UnixPwmDriver : PwmDriver
{
public UnixPwmDriver() => throw new PlatformNotSupportedException($"The {GetType().Name} class is not available on Windows.");
protected internal override void ChangeDutyCycle(int pwmChip, int pwmChannel, double dutyCycleInNanoSeconds) => throw new PlatformNotSupportedException();
protected internal override void CloseChannel(int pwmChip, int pwmChannel) => throw new PlatformNotSupportedException();
protected internal override void OpenChannel(int pwmChip, int pwmChannel) => throw new PlatformNotSupportedException();
protected internal override void StartWriting(int pwmChip, int pwmChannel, double frequencyInHertz, double dutyCycleInNanoSeconds) => throw new PlatformNotSupportedException();
protected internal override void StopWriting(int pwmChip, int pwmChannel) => throw new PlatformNotSupportedException();
}
}
......@@ -4,24 +4,29 @@
namespace System.Device.Pwm.Drivers
{
internal class UnixPwmDriver : PwmDriver
public class Windows10PwmDriver : PwmDriver
{
protected internal override void CloseChannel(int pwmChannel)
protected internal override void ChangeDutyCycle(int pwmChip, int pwmChannel, double dutyCycleInNanoSeconds)
{
throw new NotImplementedException();
}
protected internal override void OpenChannel(int pwmChannel)
protected internal override void CloseChannel(int pwmChip, int pwmChannel)
{
throw new NotImplementedException();
}
protected internal override void StartWriting(int pwmChannel, double frequency, double dutyCycle)
protected internal override void OpenChannel(int pwmChip, int pwmChannel)
{
throw new NotImplementedException();
}
protected internal override void StopWriting(int pwmChannel)
protected internal override void StartWriting(int pwmChip, int pwmChannel, double frequencyInHertz, double dutyCycleInNanoSeconds)
{
throw new NotImplementedException();
}
protected internal override void StopWriting(int pwmChip, int pwmChannel)
{
throw new NotImplementedException();
}
......
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Device.Pwm.Drivers;
namespace System.Device.Pwm
{
public sealed partial class PwmController : IDisposable
{
public PwmController()
: this(new UnixPwmDriver())
{
}
}
}
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Device.Pwm.Drivers;
namespace System.Device.Pwm
{
public sealed partial class PwmController : IDisposable
{
public PwmController()
: this(new Windows10PwmDriver())
{
}
}
}
......@@ -2,53 +2,93 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
using System.Linq;
namespace System.Device.Pwm
{
public sealed class PwmController : IDisposable
public sealed partial class PwmController : IDisposable
{
public PwmController()
{
throw new NotImplementedException();
}
private PwmDriver _driver;
private HashSet<(int, int)> _openChannels;
public PwmController(PwmDriver driver)
{
throw new NotImplementedException();
_driver = driver;
_openChannels = new HashSet<(int, int)>();
}
public void OpenChannel(int pwmChannel)
public void OpenChannel(int pwmChip, int pwmChannel)
{
throw new NotImplementedException();
if (_openChannels.Contains((pwmChip, pwmChannel)))
{
throw new InvalidOperationException("The selected pwm channel is already open.");
}
_driver.OpenChannel(pwmChip, pwmChannel);
_openChannels.Add((pwmChip, pwmChannel));
}
public void CloseChannel(int pwmChannel)
public void CloseChannel(int pwmChip, int pwmChannel)
{
throw new NotImplementedException();
if (!_openChannels.Contains((pwmChip, pwmChannel)))
{
throw new InvalidOperationException("Can not close a pwm channel that is not yet opened.");
}
_driver.CloseChannel(pwmChip, pwmChannel);
_openChannels.Remove((pwmChip, pwmChannel));
}
public void ChangeDutyCycle(int pwmChannel, double dutyCycle)
public void ChangeDutyCycle(int pwmChip, int pwmChannel, double dutyCyclePercentage)
{
throw new NotImplementedException();
if (!_openChannels.Contains((pwmChip, pwmChannel)))
{
throw new InvalidOperationException("Can not change dutycycle to a pwm channel that is not yet opened.");
}
if (dutyCyclePercentage < 0.0 || dutyCyclePercentage > 100.0)
{
throw new ArgumentException("Duty cycle must be a percentage in the range of 0.0 - 100.0", nameof(dutyCyclePercentage));
}
_driver.ChangeDutyCycle(pwmChip, pwmChannel, dutyCyclePercentage);
}
public void StartWriting(int pwmChannel, double frequency, double dutyCycle)
public void StartWriting(int pwmChip, int pwmChannel, double frequencyInHertz, double dutyCyclePercentage)
{
throw new NotImplementedException();
if (!_openChannels.Contains((pwmChip, pwmChannel)))
{
throw new InvalidOperationException("Can not start writing to a pwm channel that is not yet opened.");
}
if (dutyCyclePercentage < 0.0 || dutyCyclePercentage > 100.0)
{
throw new ArgumentException("Duty cycle must be a percentage in the range of 0.0 - 100.0", nameof(dutyCyclePercentage));
}
_driver.StartWriting(pwmChip, pwmChannel, frequencyInHertz, dutyCyclePercentage);
}
public void StopWriting(int pwmChannel)
public void StopWriting(int pwmChip, int pwmChannel)
{
throw new NotImplementedException();
if (!_openChannels.Contains((pwmChip, pwmChannel)))
{
throw new InvalidOperationException("Can not stop writing to a pwm channel that is not yet opened.");
}
_driver.StopWriting(pwmChip, pwmChannel);
}
public void Dispose()
{
Dispose(true);
}
private void Dispose(bool disposing)
{
while (_openChannels.Count > 0)
{
(int, int) channel = _openChannels.FirstOrDefault();
_driver.CloseChannel(channel.Item1, channel.Item2);
_openChannels.Remove(channel);
}
_driver.Dispose();
}
}
}
......@@ -6,10 +6,11 @@ namespace System.Device.Pwm
{
public abstract class PwmDriver : IDisposable
{
protected internal abstract void OpenChannel(int pwmChannel);
protected internal abstract void CloseChannel(int pwmChannel);
protected internal abstract void StartWriting(int pwmChannel, double frequency, double dutyCycle);
protected internal abstract void StopWriting(int pwmChannel);
protected internal abstract void OpenChannel(int pwmChip, int pwmChannel);
protected internal abstract void CloseChannel(int pwmChip, int pwmChannel);
protected internal abstract void ChangeDutyCycle(int pwmChip, int pwmChannel, double dutyCycleInNanoSeconds);
protected internal abstract void StartWriting(int pwmChip, int pwmChannel, double frequencyInHertz, double dutyCycleInNanoSeconds);
protected internal abstract void StopWriting(int pwmChip, int pwmChannel);
public void Dispose()
{
Dispose(true);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册