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

Adding implementation for the PwmController (#57)

Adding implementation for the PwmController
上级 15fdf91b
...@@ -3,11 +3,8 @@ ...@@ -3,11 +3,8 @@
// See the LICENSE file in the project root for more information. // See the LICENSE file in the project root for more information.
using System.Collections.Generic; using System.Collections.Generic;
using System.Device.Gpio.Drivers; using System.Linq;
using System.IO;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
...@@ -105,6 +102,7 @@ namespace System.Device.Gpio ...@@ -105,6 +102,7 @@ namespace System.Device.Gpio
throw new InvalidOperationException("Can not close a pin that is not yet opened."); throw new InvalidOperationException("Can not close a pin that is not yet opened.");
} }
_driver.ClosePin(logicalPinNumber); _driver.ClosePin(logicalPinNumber);
_openPins.Remove(pinNumber);
} }
/// <summary> /// <summary>
...@@ -277,9 +275,11 @@ namespace System.Device.Gpio ...@@ -277,9 +275,11 @@ namespace System.Device.Gpio
private void Dispose(bool disposing) private void Dispose(bool disposing)
{ {
foreach (int pin in _openPins) while (_openPins.Count > 0)
{ {
int pin = _openPins.FirstOrDefault();
_driver.ClosePin(pin); _driver.ClosePin(pin);
_openPins.Remove(pin);
} }
_driver.Dispose(); _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 @@ ...@@ -4,24 +4,29 @@
namespace System.Device.Pwm.Drivers 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(); throw new NotImplementedException();
} }
protected internal override void OpenChannel(int pwmChannel) protected internal override void CloseChannel(int pwmChip, int pwmChannel)
{ {
throw new NotImplementedException(); 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(); 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(); 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 @@ ...@@ -2,53 +2,93 @@
// The .NET Foundation licenses this file to you under the MIT license. // The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information. // See the LICENSE file in the project root for more information.
using System.Collections.Generic;
using System.Linq;
namespace System.Device.Pwm namespace System.Device.Pwm
{ {
public sealed class PwmController : IDisposable public sealed partial class PwmController : IDisposable
{ {
public PwmController() private PwmDriver _driver;
{ private HashSet<(int, int)> _openChannels;
throw new NotImplementedException();
}
public PwmController(PwmDriver driver) 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() public void Dispose()
{ {
Dispose(true);
} }
private void Dispose(bool disposing) 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 ...@@ -6,10 +6,11 @@ namespace System.Device.Pwm
{ {
public abstract class PwmDriver : IDisposable public abstract class PwmDriver : IDisposable
{ {
protected internal abstract void OpenChannel(int pwmChannel); protected internal abstract void OpenChannel(int pwmChip, int pwmChannel);
protected internal abstract void CloseChannel(int pwmChannel); protected internal abstract void CloseChannel(int pwmChip, int pwmChannel);
protected internal abstract void StartWriting(int pwmChannel, double frequency, double dutyCycle); protected internal abstract void ChangeDutyCycle(int pwmChip, int pwmChannel, double dutyCycleInNanoSeconds);
protected internal abstract void StopWriting(int pwmChannel); 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() public void Dispose()
{ {
Dispose(true); Dispose(true);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册