Coding styles
This commit is contained in:
parent
d75c3bc73f
commit
186792fde8
@ -1,23 +1,20 @@
|
||||
namespace Unosquare.RaspberryIO.Camera
|
||||
{
|
||||
using Swan;
|
||||
using Unosquare.Swan;
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace Unosquare.RaspberryIO.Camera {
|
||||
/// <summary>
|
||||
/// A simple RGB color class to represent colors in RGB and YUV colorspaces.
|
||||
/// </summary>
|
||||
public class CameraColor
|
||||
{
|
||||
public class CameraColor {
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="CameraColor"/> class.
|
||||
/// </summary>
|
||||
/// <param name="r">The red.</param>
|
||||
/// <param name="g">The green.</param>
|
||||
/// <param name="b">The blue.</param>
|
||||
public CameraColor(int r, int g, int b)
|
||||
: this(r, g, b, string.Empty)
|
||||
{
|
||||
public CameraColor(Int32 r, Int32 g, Int32 b)
|
||||
: this(r, g, b, String.Empty) {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -27,16 +24,15 @@
|
||||
/// <param name="g">The green.</param>
|
||||
/// <param name="b">The blue.</param>
|
||||
/// <param name="name">The well-known color name.</param>
|
||||
public CameraColor(int r, int g, int b, string name)
|
||||
{
|
||||
RGB = new[] { Convert.ToByte(r.Clamp(0, 255)), Convert.ToByte(g.Clamp(0, 255)), Convert.ToByte(b.Clamp(0, 255)) };
|
||||
public CameraColor(Int32 r, Int32 g, Int32 b, String name) {
|
||||
this.RGB = new[] { Convert.ToByte(r.Clamp(0, 255)), Convert.ToByte(g.Clamp(0, 255)), Convert.ToByte(b.Clamp(0, 255)) };
|
||||
|
||||
var y = (R * .299000f) + (G * .587000f) + (B * .114000f);
|
||||
var u = (R * -.168736f) + (G * -.331264f) + (B * .500000f) + 128f;
|
||||
var v = (R * .500000f) + (G * -.418688f) + (B * -.081312f) + 128f;
|
||||
Single y = this.R * .299000f + this.G * .587000f + this.B * .114000f;
|
||||
Single u = this.R * -.168736f + this.G * -.331264f + this.B * .500000f + 128f;
|
||||
Single v = this.R * .500000f + this.G * -.418688f + this.B * -.081312f + 128f;
|
||||
|
||||
YUV = new byte[] { (byte)y.Clamp(0, 255), (byte)u.Clamp(0, 255), (byte)v.Clamp(0, 255) };
|
||||
Name = name;
|
||||
this.YUV = new Byte[] { (Byte)y.Clamp(0, 255), (Byte)u.Clamp(0, 255), (Byte)v.Clamp(0, 255) };
|
||||
this.Name = name;
|
||||
}
|
||||
|
||||
#region Static Definitions
|
||||
@ -71,32 +67,38 @@
|
||||
/// <summary>
|
||||
/// Gets the well-known color name.
|
||||
/// </summary>
|
||||
public string Name { get; }
|
||||
public String Name {
|
||||
get;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the red byte.
|
||||
/// </summary>
|
||||
public byte R => RGB[0];
|
||||
public Byte R => this.RGB[0];
|
||||
|
||||
/// <summary>
|
||||
/// Gets the green byte.
|
||||
/// </summary>
|
||||
public byte G => RGB[1];
|
||||
public Byte G => this.RGB[1];
|
||||
|
||||
/// <summary>
|
||||
/// Gets the blue byte.
|
||||
/// </summary>
|
||||
public byte B => RGB[2];
|
||||
public Byte B => this.RGB[2];
|
||||
|
||||
/// <summary>
|
||||
/// Gets the RGB byte array (3 bytes).
|
||||
/// </summary>
|
||||
public byte[] RGB { get; }
|
||||
public Byte[] RGB {
|
||||
get;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the YUV byte array (3 bytes).
|
||||
/// </summary>
|
||||
public byte[] YUV { get; }
|
||||
public Byte[] YUV {
|
||||
get;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a hexadecimal representation of the RGB byte array.
|
||||
@ -104,10 +106,12 @@
|
||||
/// </summary>
|
||||
/// <param name="reverse">if set to <c>true</c> [reverse].</param>
|
||||
/// <returns>A string</returns>
|
||||
public string ToRgbHex(bool reverse)
|
||||
{
|
||||
var data = RGB.ToArray();
|
||||
if (reverse) Array.Reverse(data);
|
||||
public String ToRgbHex(Boolean reverse) {
|
||||
Byte[] data = this.RGB.ToArray();
|
||||
if(reverse) {
|
||||
Array.Reverse(data);
|
||||
}
|
||||
|
||||
return ToHex(data);
|
||||
}
|
||||
|
||||
@ -117,10 +121,12 @@
|
||||
/// </summary>
|
||||
/// <param name="reverse">if set to <c>true</c> [reverse].</param>
|
||||
/// <returns>A string</returns>
|
||||
public string ToYuvHex(bool reverse)
|
||||
{
|
||||
var data = YUV.ToArray();
|
||||
if (reverse) Array.Reverse(data);
|
||||
public String ToYuvHex(Boolean reverse) {
|
||||
Byte[] data = this.YUV.ToArray();
|
||||
if(reverse) {
|
||||
Array.Reverse(data);
|
||||
}
|
||||
|
||||
return ToHex(data);
|
||||
}
|
||||
|
||||
@ -129,6 +135,6 @@
|
||||
/// </summary>
|
||||
/// <param name="data">The data.</param>
|
||||
/// <returns>A string</returns>
|
||||
private static string ToHex(byte[] data) => $"0x{BitConverter.ToString(data).Replace("-", string.Empty).ToLowerInvariant()}";
|
||||
private static String ToHex(Byte[] data) => $"0x{BitConverter.ToString(data).Replace("-", String.Empty).ToLowerInvariant()}";
|
||||
}
|
||||
}
|
@ -1,22 +1,20 @@
|
||||
namespace Unosquare.RaspberryIO.Camera
|
||||
{
|
||||
using Swan.Abstractions;
|
||||
using Unosquare.Swan.Abstractions;
|
||||
using System;
|
||||
using Swan.Components;
|
||||
using Unosquare.Swan.Components;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Unosquare.RaspberryIO.Camera {
|
||||
/// <summary>
|
||||
/// The Raspberry Pi's camera controller wrapping raspistill and raspivid programs.
|
||||
/// This class is a singleton
|
||||
/// </summary>
|
||||
public class CameraController : SingletonBase<CameraController>
|
||||
{
|
||||
public class CameraController : SingletonBase<CameraController> {
|
||||
#region Private Declarations
|
||||
|
||||
private static readonly ManualResetEventSlim OperationDone = new ManualResetEventSlim(true);
|
||||
private static readonly object SyncRoot = new object();
|
||||
private static readonly Object SyncRoot = new Object();
|
||||
private static CancellationTokenSource _videoTokenSource = new CancellationTokenSource();
|
||||
private static Task<Task> _videoStreamTask;
|
||||
|
||||
@ -30,7 +28,7 @@
|
||||
/// <value>
|
||||
/// <c>true</c> if this instance is busy; otherwise, <c>false</c>.
|
||||
/// </value>
|
||||
public bool IsBusy => OperationDone.IsSet == false;
|
||||
public Boolean IsBusy => OperationDone.IsSet == false;
|
||||
|
||||
#endregion
|
||||
|
||||
@ -43,34 +41,30 @@
|
||||
/// <param name="ct">The ct.</param>
|
||||
/// <returns>The image bytes</returns>
|
||||
/// <exception cref="InvalidOperationException">Cannot use camera module because it is currently busy.</exception>
|
||||
public async Task<byte[]> CaptureImageAsync(CameraStillSettings settings, CancellationToken ct = default)
|
||||
{
|
||||
if (Instance.IsBusy)
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Codequalität", "IDE0067:Objekte verwerfen, bevor Bereich verloren geht", Justification = "<Ausstehend>")]
|
||||
public async Task<Byte[]> CaptureImageAsync(CameraStillSettings settings, CancellationToken ct = default) {
|
||||
if(Instance.IsBusy) {
|
||||
throw new InvalidOperationException("Cannot use camera module because it is currently busy.");
|
||||
}
|
||||
|
||||
if (settings.CaptureTimeoutMilliseconds <= 0)
|
||||
if(settings.CaptureTimeoutMilliseconds <= 0) {
|
||||
throw new ArgumentException($"{nameof(settings.CaptureTimeoutMilliseconds)} needs to be greater than 0");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
try {
|
||||
OperationDone.Reset();
|
||||
|
||||
var output = new MemoryStream();
|
||||
var exitCode = await ProcessRunner.RunProcessAsync(
|
||||
MemoryStream output = new MemoryStream();
|
||||
Int32 exitCode = await ProcessRunner.RunProcessAsync(
|
||||
settings.CommandName,
|
||||
settings.CreateProcessArguments(),
|
||||
(data, proc) =>
|
||||
{
|
||||
output.Write(data, 0, data.Length);
|
||||
},
|
||||
(data, proc) => output.Write(data, 0, data.Length),
|
||||
null,
|
||||
true,
|
||||
ct);
|
||||
|
||||
return exitCode != 0 ? new byte[] { } : output.ToArray();
|
||||
}
|
||||
finally
|
||||
{
|
||||
return exitCode != 0 ? new Byte[] { } : output.ToArray();
|
||||
} finally {
|
||||
OperationDone.Set();
|
||||
}
|
||||
}
|
||||
@ -80,10 +74,7 @@
|
||||
/// </summary>
|
||||
/// <param name="settings">The settings.</param>
|
||||
/// <returns>The image bytes</returns>
|
||||
public byte[] CaptureImage(CameraStillSettings settings)
|
||||
{
|
||||
return CaptureImageAsync(settings).GetAwaiter().GetResult();
|
||||
}
|
||||
public Byte[] CaptureImage(CameraStillSettings settings) => this.CaptureImageAsync(settings).GetAwaiter().GetResult();
|
||||
|
||||
/// <summary>
|
||||
/// Captures a JPEG encoded image asynchronously at 90% quality.
|
||||
@ -92,17 +83,15 @@
|
||||
/// <param name="height">The height.</param>
|
||||
/// <param name="ct">The ct.</param>
|
||||
/// <returns>The image bytes</returns>
|
||||
public Task<byte[]> CaptureImageJpegAsync(int width, int height, CancellationToken ct = default)
|
||||
{
|
||||
var settings = new CameraStillSettings
|
||||
{
|
||||
public Task<Byte[]> CaptureImageJpegAsync(Int32 width, Int32 height, CancellationToken ct = default) {
|
||||
CameraStillSettings settings = new CameraStillSettings {
|
||||
CaptureWidth = width,
|
||||
CaptureHeight = height,
|
||||
CaptureJpegQuality = 90,
|
||||
CaptureTimeoutMilliseconds = 300,
|
||||
};
|
||||
|
||||
return CaptureImageAsync(settings, ct);
|
||||
return this.CaptureImageAsync(settings, ct);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -111,7 +100,7 @@
|
||||
/// <param name="width">The width.</param>
|
||||
/// <param name="height">The height.</param>
|
||||
/// <returns>The image bytes</returns>
|
||||
public byte[] CaptureImageJpeg(int width, int height) => CaptureImageJpegAsync(width, height).GetAwaiter().GetResult();
|
||||
public Byte[] CaptureImageJpeg(Int32 width, Int32 height) => this.CaptureImageJpegAsync(width, height).GetAwaiter().GetResult();
|
||||
|
||||
#endregion
|
||||
|
||||
@ -123,17 +112,15 @@
|
||||
/// </summary>
|
||||
/// <param name="onDataCallback">The on data callback.</param>
|
||||
/// <param name="onExitCallback">The on exit callback.</param>
|
||||
public void OpenVideoStream(Action<byte[]> onDataCallback, Action onExitCallback = null)
|
||||
{
|
||||
var settings = new CameraVideoSettings
|
||||
{
|
||||
public void OpenVideoStream(Action<Byte[]> onDataCallback, Action onExitCallback = null) {
|
||||
CameraVideoSettings settings = new CameraVideoSettings {
|
||||
CaptureTimeoutMilliseconds = 0,
|
||||
CaptureDisplayPreview = false,
|
||||
CaptureWidth = 1920,
|
||||
CaptureHeight = 1080
|
||||
};
|
||||
|
||||
OpenVideoStream(settings, onDataCallback, onExitCallback);
|
||||
this.OpenVideoStream(settings, onDataCallback, onExitCallback);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -144,21 +131,19 @@
|
||||
/// <param name="onExitCallback">The on exit callback.</param>
|
||||
/// <exception cref="InvalidOperationException">Cannot use camera module because it is currently busy.</exception>
|
||||
/// <exception cref="ArgumentException">CaptureTimeoutMilliseconds</exception>
|
||||
public void OpenVideoStream(CameraVideoSettings settings, Action<byte[]> onDataCallback, Action onExitCallback)
|
||||
{
|
||||
if (Instance.IsBusy)
|
||||
public void OpenVideoStream(CameraVideoSettings settings, Action<Byte[]> onDataCallback, Action onExitCallback) {
|
||||
if(Instance.IsBusy) {
|
||||
throw new InvalidOperationException("Cannot use camera module because it is currently busy.");
|
||||
}
|
||||
|
||||
if (settings.CaptureTimeoutMilliseconds < 0)
|
||||
if(settings.CaptureTimeoutMilliseconds < 0) {
|
||||
throw new ArgumentException($"{nameof(settings.CaptureTimeoutMilliseconds)} needs to be greater than or equal to 0");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
try {
|
||||
OperationDone.Reset();
|
||||
_videoStreamTask = Task.Factory.StartNew(() => VideoWorkerDoWork(settings, onDataCallback, onExitCallback), _videoTokenSource.Token);
|
||||
}
|
||||
catch
|
||||
{
|
||||
} catch {
|
||||
OperationDone.Set();
|
||||
throw;
|
||||
}
|
||||
@ -167,16 +152,14 @@
|
||||
/// <summary>
|
||||
/// Closes the video stream of a video stream is open.
|
||||
/// </summary>
|
||||
public void CloseVideoStream()
|
||||
{
|
||||
lock (SyncRoot)
|
||||
{
|
||||
if (IsBusy == false)
|
||||
public void CloseVideoStream() {
|
||||
lock(SyncRoot) {
|
||||
if(this.IsBusy == false) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (_videoTokenSource.IsCancellationRequested == false)
|
||||
{
|
||||
if(_videoTokenSource.IsCancellationRequested == false) {
|
||||
_videoTokenSource.Cancel();
|
||||
_videoStreamTask.Wait();
|
||||
}
|
||||
@ -184,13 +167,8 @@
|
||||
_videoTokenSource = new CancellationTokenSource();
|
||||
}
|
||||
|
||||
private static async Task VideoWorkerDoWork(
|
||||
CameraVideoSettings settings,
|
||||
Action<byte[]> onDataCallback,
|
||||
Action onExitCallback)
|
||||
{
|
||||
try
|
||||
{
|
||||
private static async Task VideoWorkerDoWork(CameraVideoSettings settings, Action<Byte[]> onDataCallback, Action onExitCallback) {
|
||||
try {
|
||||
await ProcessRunner.RunProcessAsync(
|
||||
settings.CommandName,
|
||||
settings.CreateProcessArguments(),
|
||||
@ -200,13 +178,9 @@
|
||||
_videoTokenSource.Token);
|
||||
|
||||
onExitCallback?.Invoke();
|
||||
}
|
||||
catch
|
||||
{
|
||||
} catch {
|
||||
// swallow
|
||||
}
|
||||
finally
|
||||
{
|
||||
} finally {
|
||||
Instance.CloseVideoStream();
|
||||
OperationDone.Set();
|
||||
}
|
||||
|
@ -1,13 +1,12 @@
|
||||
namespace Unosquare.RaspberryIO.Camera
|
||||
{
|
||||
using Swan;
|
||||
using Unosquare.Swan;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
|
||||
namespace Unosquare.RaspberryIO.Camera {
|
||||
/// <summary>
|
||||
/// Defines the Raspberry Pi camera's sensor ROI (Region of Interest)
|
||||
/// </summary>
|
||||
public struct CameraRect
|
||||
{
|
||||
public struct CameraRect {
|
||||
/// <summary>
|
||||
/// The default ROI which is the entire area.
|
||||
/// </summary>
|
||||
@ -19,7 +18,9 @@
|
||||
/// <value>
|
||||
/// The x.
|
||||
/// </value>
|
||||
public decimal X { get; set; }
|
||||
public Decimal X {
|
||||
get; set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the y location in relative coordinates. (0.0 to 1.0)
|
||||
@ -27,7 +28,9 @@
|
||||
/// <value>
|
||||
/// The y.
|
||||
/// </value>
|
||||
public decimal Y { get; set; }
|
||||
public Decimal Y {
|
||||
get; set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the width in relative coordinates. (0.0 to 1.0)
|
||||
@ -35,7 +38,9 @@
|
||||
/// <value>
|
||||
/// The w.
|
||||
/// </value>
|
||||
public decimal W { get; set; }
|
||||
public Decimal W {
|
||||
get; set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the height in relative coordinates. (0.0 to 1.0)
|
||||
@ -43,7 +48,9 @@
|
||||
/// <value>
|
||||
/// The h.
|
||||
/// </value>
|
||||
public decimal H { get; set; }
|
||||
public Decimal H {
|
||||
get; set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this instance is equal to the default (The entire area).
|
||||
@ -51,32 +58,29 @@
|
||||
/// <value>
|
||||
/// <c>true</c> if this instance is default; otherwise, <c>false</c>.
|
||||
/// </value>
|
||||
public bool IsDefault
|
||||
{
|
||||
get
|
||||
{
|
||||
Clamp();
|
||||
return X == Default.X && Y == Default.Y && W == Default.W && H == Default.H;
|
||||
public Boolean IsDefault {
|
||||
get {
|
||||
this.Clamp();
|
||||
return this.X == Default.X && this.Y == Default.Y && this.W == Default.W && this.H == Default.H;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clamps the members of this ROI to their minimum and maximum values
|
||||
/// </summary>
|
||||
public void Clamp()
|
||||
{
|
||||
X = X.Clamp(0M, 1M);
|
||||
Y = Y.Clamp(0M, 1M);
|
||||
W = W.Clamp(0M, 1M - X);
|
||||
H = H.Clamp(0M, 1M - Y);
|
||||
public void Clamp() {
|
||||
this.X = this.X.Clamp(0M, 1M);
|
||||
this.Y = this.Y.Clamp(0M, 1M);
|
||||
this.W = this.W.Clamp(0M, 1M - this.X);
|
||||
this.H = this.H.Clamp(0M, 1M - this.Y);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a <see cref="string" /> that represents this instance.
|
||||
/// Returns a <see cref="String" /> that represents this instance.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="string" /> that represents this instance.
|
||||
/// A <see cref="String" /> that represents this instance.
|
||||
/// </returns>
|
||||
public override string ToString() => $"{X.ToString(CultureInfo.InvariantCulture)},{Y.ToString(CultureInfo.InvariantCulture)},{W.ToString(CultureInfo.InvariantCulture)},{H.ToString(CultureInfo.InvariantCulture)}";
|
||||
public override String ToString() => $"{this.X.ToString(CultureInfo.InvariantCulture)},{this.Y.ToString(CultureInfo.InvariantCulture)},{this.W.ToString(CultureInfo.InvariantCulture)},{this.H.ToString(CultureInfo.InvariantCulture)}";
|
||||
}
|
||||
}
|
||||
|
@ -1,16 +1,15 @@
|
||||
namespace Unosquare.RaspberryIO.Camera
|
||||
{
|
||||
using Swan;
|
||||
using Unosquare.Swan;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
using System;
|
||||
|
||||
namespace Unosquare.RaspberryIO.Camera {
|
||||
/// <summary>
|
||||
/// A base class to implement raspistill and raspivid wrappers
|
||||
/// Full documentation available at
|
||||
/// https://www.raspberrypi.org/documentation/raspbian/applications/camera.md
|
||||
/// </summary>
|
||||
public abstract class CameraSettingsBase
|
||||
{
|
||||
public abstract class CameraSettingsBase {
|
||||
/// <summary>
|
||||
/// The Invariant Culture shorthand
|
||||
/// </summary>
|
||||
@ -23,27 +22,27 @@
|
||||
/// Default value is 5000
|
||||
/// Recommended value is at least 300 in order to let the light collectors open
|
||||
/// </summary>
|
||||
public int CaptureTimeoutMilliseconds { get; set; } = 5000;
|
||||
public Int32 CaptureTimeoutMilliseconds { get; set; } = 5000;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether or not to show a preview window on the screen
|
||||
/// </summary>
|
||||
public bool CaptureDisplayPreview { get; set; } = false;
|
||||
public Boolean CaptureDisplayPreview { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether a preview window is shown in full screen mode if enabled
|
||||
/// </summary>
|
||||
public bool CaptureDisplayPreviewInFullScreen { get; set; } = true;
|
||||
public Boolean CaptureDisplayPreviewInFullScreen { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether video stabilization should be enabled.
|
||||
/// </summary>
|
||||
public bool CaptureVideoStabilizationEnabled { get; set; } = false;
|
||||
public Boolean CaptureVideoStabilizationEnabled { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the display preview opacity only if the display preview property is enabled.
|
||||
/// </summary>
|
||||
public byte CaptureDisplayPreviewOpacity { get; set; } = 255;
|
||||
public Byte CaptureDisplayPreviewOpacity { get; set; } = 255;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the capture sensor region of interest in relative coordinates.
|
||||
@ -54,7 +53,7 @@
|
||||
/// Gets or sets the capture shutter speed in microseconds.
|
||||
/// Default -1, Range 0 to 6000000 (equivalent to 6 seconds)
|
||||
/// </summary>
|
||||
public int CaptureShutterSpeedMicroseconds { get; set; } = -1;
|
||||
public Int32 CaptureShutterSpeedMicroseconds { get; set; } = -1;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the exposure mode.
|
||||
@ -68,7 +67,7 @@
|
||||
/// Exposure can be adjusted by changing either the lens f-number or the exposure time;
|
||||
/// which one is changed usually depends on the camera's exposure mode.
|
||||
/// </summary>
|
||||
public int CaptureExposureCompensation { get; set; } = 0;
|
||||
public Int32 CaptureExposureCompensation { get; set; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the capture metering mode.
|
||||
@ -85,20 +84,22 @@
|
||||
/// Only takes effect if White balance control is set to off.
|
||||
/// Default is 0
|
||||
/// </summary>
|
||||
public decimal CaptureWhiteBalanceGainBlue { get; set; } = 0M;
|
||||
public Decimal CaptureWhiteBalanceGainBlue { get; set; } = 0M;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the capture white balance gain on the red channel. Example: 1.75
|
||||
/// Only takes effect if White balance control is set to off.
|
||||
/// Default is 0
|
||||
/// </summary>
|
||||
public decimal CaptureWhiteBalanceGainRed { get; set; } = 0M;
|
||||
public Decimal CaptureWhiteBalanceGainRed { get; set; } = 0M;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the dynamic range compensation.
|
||||
/// DRC changes the images by increasing the range of dark areas, and decreasing the brighter areas. This can improve the image in low light areas.
|
||||
/// </summary>
|
||||
public CameraDynamicRangeCompensation CaptureDynamicRangeCompensation { get; set; } =
|
||||
public CameraDynamicRangeCompensation CaptureDynamicRangeCompensation {
|
||||
get; set;
|
||||
} =
|
||||
CameraDynamicRangeCompensation.Off;
|
||||
|
||||
#endregion
|
||||
@ -109,39 +110,39 @@
|
||||
/// Gets or sets the width of the picture to take.
|
||||
/// Less than or equal to 0 in either width or height means maximum resolution available.
|
||||
/// </summary>
|
||||
public int CaptureWidth { get; set; } = 640;
|
||||
public Int32 CaptureWidth { get; set; } = 640;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the height of the picture to take.
|
||||
/// Less than or equal to 0 in either width or height means maximum resolution available.
|
||||
/// </summary>
|
||||
public int CaptureHeight { get; set; } = 480;
|
||||
public Int32 CaptureHeight { get; set; } = 480;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the picture sharpness. Default is 0, Range form -100 to 100
|
||||
/// </summary>
|
||||
public int ImageSharpness { get; set; } = 0;
|
||||
public Int32 ImageSharpness { get; set; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the picture contrast. Default is 0, Range form -100 to 100
|
||||
/// </summary>
|
||||
public int ImageContrast { get; set; } = 0;
|
||||
public Int32 ImageContrast { get; set; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the picture brightness. Default is 50, Range form 0 to 100
|
||||
/// </summary>
|
||||
public int ImageBrightness { get; set; } = 50; // from 0 to 100
|
||||
public Int32 ImageBrightness { get; set; } = 50; // from 0 to 100
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the picture saturation. Default is 0, Range form -100 to 100
|
||||
/// </summary>
|
||||
public int ImageSaturation { get; set; } = 0;
|
||||
public Int32 ImageSaturation { get; set; } = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the picture ISO. Default is -1 Range is 100 to 800
|
||||
/// The higher the value, the more light the sensor absorbs
|
||||
/// </summary>
|
||||
public int ImageIso { get; set; } = -1;
|
||||
public Int32 ImageIso { get; set; } = -1;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the image capture effect to be applied.
|
||||
@ -153,14 +154,14 @@
|
||||
/// Default is -1, Range is 0 to 255
|
||||
/// 128:128 should be effectively a monochrome image.
|
||||
/// </summary>
|
||||
public int ImageColorEffectU { get; set; } = -1; // 0 to 255
|
||||
public Int32 ImageColorEffectU { get; set; } = -1; // 0 to 255
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the color effect V coordinates.
|
||||
/// Default is -1, Range is 0 to 255
|
||||
/// 128:128 should be effectively a monochrome image.
|
||||
/// </summary>
|
||||
public int ImageColorEffectV { get; set; } = -1; // 0 to 255
|
||||
public Int32 ImageColorEffectV { get; set; } = -1; // 0 to 255
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the image rotation. Default is no rotation
|
||||
@ -170,12 +171,16 @@
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the image should be flipped horizontally.
|
||||
/// </summary>
|
||||
public bool ImageFlipHorizontally { get; set; }
|
||||
public Boolean ImageFlipHorizontally {
|
||||
get; set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the image should be flipped vertically.
|
||||
/// </summary>
|
||||
public bool ImageFlipVertically { get; set; }
|
||||
public Boolean ImageFlipVertically {
|
||||
get; set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the image annotations using a bitmask (or flags) notation.
|
||||
@ -188,13 +193,13 @@
|
||||
/// Text may include date/time placeholders by using the '%' character, as used by strftime.
|
||||
/// Example: ABC %Y-%m-%d %X will output ABC 2015-10-28 20:09:33
|
||||
/// </summary>
|
||||
public string ImageAnnotationsText { get; set; } = string.Empty;
|
||||
public String ImageAnnotationsText { get; set; } = String.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the font size of the text annotations
|
||||
/// Default is -1, range is 6 to 160
|
||||
/// </summary>
|
||||
public int ImageAnnotationFontSize { get; set; } = -1;
|
||||
public Int32 ImageAnnotationFontSize { get; set; } = -1;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the color of the text annotations.
|
||||
@ -219,118 +224,134 @@
|
||||
/// <summary>
|
||||
/// Gets the command file executable.
|
||||
/// </summary>
|
||||
public abstract string CommandName { get; }
|
||||
public abstract String CommandName {
|
||||
get;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the process arguments.
|
||||
/// </summary>
|
||||
/// <returns>The string that represents the process arguments</returns>
|
||||
public virtual string CreateProcessArguments()
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
sb.Append("-o -"); // output to standard output as opposed to a file.
|
||||
sb.Append($" -t {(CaptureTimeoutMilliseconds < 0 ? "0" : CaptureTimeoutMilliseconds.ToString(Ci))}");
|
||||
public virtual String CreateProcessArguments() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
_ = sb.Append("-o -"); // output to standard output as opposed to a file.
|
||||
_ = sb.Append($" -t {(this.CaptureTimeoutMilliseconds < 0 ? "0" : this.CaptureTimeoutMilliseconds.ToString(Ci))}");
|
||||
|
||||
// Basic Width and height
|
||||
if (CaptureWidth > 0 && CaptureHeight > 0)
|
||||
{
|
||||
sb.Append($" -w {CaptureWidth.ToString(Ci)}");
|
||||
sb.Append($" -h {CaptureHeight.ToString(Ci)}");
|
||||
if(this.CaptureWidth > 0 && this.CaptureHeight > 0) {
|
||||
_ = sb.Append($" -w {this.CaptureWidth.ToString(Ci)}");
|
||||
_ = sb.Append($" -h {this.CaptureHeight.ToString(Ci)}");
|
||||
}
|
||||
|
||||
// Display Preview
|
||||
if (CaptureDisplayPreview)
|
||||
{
|
||||
if (CaptureDisplayPreviewInFullScreen)
|
||||
sb.Append(" -f");
|
||||
|
||||
if (CaptureDisplayPreviewOpacity != byte.MaxValue)
|
||||
sb.Append($" -op {CaptureDisplayPreviewOpacity.ToString(Ci)}");
|
||||
if(this.CaptureDisplayPreview) {
|
||||
if(this.CaptureDisplayPreviewInFullScreen) {
|
||||
_ = sb.Append(" -f");
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.Append(" -n"); // no preview
|
||||
|
||||
if(this.CaptureDisplayPreviewOpacity != Byte.MaxValue) {
|
||||
_ = sb.Append($" -op {this.CaptureDisplayPreviewOpacity.ToString(Ci)}");
|
||||
}
|
||||
} else {
|
||||
_ = sb.Append(" -n"); // no preview
|
||||
}
|
||||
|
||||
// Picture Settings
|
||||
if (ImageSharpness != 0)
|
||||
sb.Append($" -sh {ImageSharpness.Clamp(-100, 100).ToString(Ci)}");
|
||||
|
||||
if (ImageContrast != 0)
|
||||
sb.Append($" -co {ImageContrast.Clamp(-100, 100).ToString(Ci)}");
|
||||
|
||||
if (ImageBrightness != 50)
|
||||
sb.Append($" -br {ImageBrightness.Clamp(0, 100).ToString(Ci)}");
|
||||
|
||||
if (ImageSaturation != 0)
|
||||
sb.Append($" -sa {ImageSaturation.Clamp(-100, 100).ToString(Ci)}");
|
||||
|
||||
if (ImageIso >= 100)
|
||||
sb.Append($" -ISO {ImageIso.Clamp(100, 800).ToString(Ci)}");
|
||||
|
||||
if (CaptureVideoStabilizationEnabled)
|
||||
sb.Append(" -vs");
|
||||
|
||||
if (CaptureExposureCompensation != 0)
|
||||
sb.Append($" -ev {CaptureExposureCompensation.Clamp(-10, 10).ToString(Ci)}");
|
||||
|
||||
if (CaptureExposure != CameraExposureMode.Auto)
|
||||
sb.Append($" -ex {CaptureExposure.ToString().ToLowerInvariant()}");
|
||||
|
||||
if (CaptureWhiteBalanceControl != CameraWhiteBalanceMode.Auto)
|
||||
sb.Append($" -awb {CaptureWhiteBalanceControl.ToString().ToLowerInvariant()}");
|
||||
|
||||
if (ImageEffect != CameraImageEffect.None)
|
||||
sb.Append($" -ifx {ImageEffect.ToString().ToLowerInvariant()}");
|
||||
|
||||
if (ImageColorEffectU >= 0 && ImageColorEffectV >= 0)
|
||||
{
|
||||
sb.Append(
|
||||
$" -cfx {ImageColorEffectU.Clamp(0, 255).ToString(Ci)}:{ImageColorEffectV.Clamp(0, 255).ToString(Ci)}");
|
||||
if(this.ImageSharpness != 0) {
|
||||
_ = sb.Append($" -sh {this.ImageSharpness.Clamp(-100, 100).ToString(Ci)}");
|
||||
}
|
||||
|
||||
if (CaptureMeteringMode != CameraMeteringMode.Average)
|
||||
sb.Append($" -mm {CaptureMeteringMode.ToString().ToLowerInvariant()}");
|
||||
if(this.ImageContrast != 0) {
|
||||
_ = sb.Append($" -co {this.ImageContrast.Clamp(-100, 100).ToString(Ci)}");
|
||||
}
|
||||
|
||||
if (ImageRotation != CameraImageRotation.None)
|
||||
sb.Append($" -rot {((int)ImageRotation).ToString(Ci)}");
|
||||
if(this.ImageBrightness != 50) {
|
||||
_ = sb.Append($" -br {this.ImageBrightness.Clamp(0, 100).ToString(Ci)}");
|
||||
}
|
||||
|
||||
if (ImageFlipHorizontally)
|
||||
sb.Append(" -hf");
|
||||
if(this.ImageSaturation != 0) {
|
||||
_ = sb.Append($" -sa {this.ImageSaturation.Clamp(-100, 100).ToString(Ci)}");
|
||||
}
|
||||
|
||||
if (ImageFlipVertically)
|
||||
sb.Append(" -vf");
|
||||
if(this.ImageIso >= 100) {
|
||||
_ = sb.Append($" -ISO {this.ImageIso.Clamp(100, 800).ToString(Ci)}");
|
||||
}
|
||||
|
||||
if (CaptureSensorRoi.IsDefault == false)
|
||||
sb.Append($" -roi {CaptureSensorRoi}");
|
||||
if(this.CaptureVideoStabilizationEnabled) {
|
||||
_ = sb.Append(" -vs");
|
||||
}
|
||||
|
||||
if (CaptureShutterSpeedMicroseconds > 0)
|
||||
sb.Append($" -ss {CaptureShutterSpeedMicroseconds.Clamp(0, 6000000).ToString(Ci)}");
|
||||
if(this.CaptureExposureCompensation != 0) {
|
||||
_ = sb.Append($" -ev {this.CaptureExposureCompensation.Clamp(-10, 10).ToString(Ci)}");
|
||||
}
|
||||
|
||||
if (CaptureDynamicRangeCompensation != CameraDynamicRangeCompensation.Off)
|
||||
sb.Append($" -drc {CaptureDynamicRangeCompensation.ToString().ToLowerInvariant()}");
|
||||
if(this.CaptureExposure != CameraExposureMode.Auto) {
|
||||
_ = sb.Append($" -ex {this.CaptureExposure.ToString().ToLowerInvariant()}");
|
||||
}
|
||||
|
||||
if (CaptureWhiteBalanceControl == CameraWhiteBalanceMode.Off &&
|
||||
(CaptureWhiteBalanceGainBlue != 0M || CaptureWhiteBalanceGainRed != 0M))
|
||||
sb.Append($" -awbg {CaptureWhiteBalanceGainBlue.ToString(Ci)},{CaptureWhiteBalanceGainRed.ToString(Ci)}");
|
||||
if(this.CaptureWhiteBalanceControl != CameraWhiteBalanceMode.Auto) {
|
||||
_ = sb.Append($" -awb {this.CaptureWhiteBalanceControl.ToString().ToLowerInvariant()}");
|
||||
}
|
||||
|
||||
if (ImageAnnotationFontSize > 0)
|
||||
{
|
||||
sb.Append($" -ae {ImageAnnotationFontSize.Clamp(6, 160).ToString(Ci)}");
|
||||
sb.Append($",{(ImageAnnotationFontColor == null ? "0xff" : ImageAnnotationFontColor.ToYuvHex(true))}");
|
||||
if(this.ImageEffect != CameraImageEffect.None) {
|
||||
_ = sb.Append($" -ifx {this.ImageEffect.ToString().ToLowerInvariant()}");
|
||||
}
|
||||
|
||||
if (ImageAnnotationBackground != null)
|
||||
{
|
||||
ImageAnnotations |= CameraAnnotation.SolidBackground;
|
||||
sb.Append($",{ImageAnnotationBackground.ToYuvHex(true)}");
|
||||
if(this.ImageColorEffectU >= 0 && this.ImageColorEffectV >= 0) {
|
||||
_ = sb.Append(
|
||||
$" -cfx {this.ImageColorEffectU.Clamp(0, 255).ToString(Ci)}:{this.ImageColorEffectV.Clamp(0, 255).ToString(Ci)}");
|
||||
}
|
||||
|
||||
if(this.CaptureMeteringMode != CameraMeteringMode.Average) {
|
||||
_ = sb.Append($" -mm {this.CaptureMeteringMode.ToString().ToLowerInvariant()}");
|
||||
}
|
||||
|
||||
if(this.ImageRotation != CameraImageRotation.None) {
|
||||
_ = sb.Append($" -rot {((Int32)this.ImageRotation).ToString(Ci)}");
|
||||
}
|
||||
|
||||
if(this.ImageFlipHorizontally) {
|
||||
_ = sb.Append(" -hf");
|
||||
}
|
||||
|
||||
if(this.ImageFlipVertically) {
|
||||
_ = sb.Append(" -vf");
|
||||
}
|
||||
|
||||
if(this.CaptureSensorRoi.IsDefault == false) {
|
||||
_ = sb.Append($" -roi {this.CaptureSensorRoi}");
|
||||
}
|
||||
|
||||
if(this.CaptureShutterSpeedMicroseconds > 0) {
|
||||
_ = sb.Append($" -ss {this.CaptureShutterSpeedMicroseconds.Clamp(0, 6000000).ToString(Ci)}");
|
||||
}
|
||||
|
||||
if(this.CaptureDynamicRangeCompensation != CameraDynamicRangeCompensation.Off) {
|
||||
_ = sb.Append($" -drc {this.CaptureDynamicRangeCompensation.ToString().ToLowerInvariant()}");
|
||||
}
|
||||
|
||||
if(this.CaptureWhiteBalanceControl == CameraWhiteBalanceMode.Off &&
|
||||
(this.CaptureWhiteBalanceGainBlue != 0M || this.CaptureWhiteBalanceGainRed != 0M)) {
|
||||
_ = sb.Append($" -awbg {this.CaptureWhiteBalanceGainBlue.ToString(Ci)},{this.CaptureWhiteBalanceGainRed.ToString(Ci)}");
|
||||
}
|
||||
|
||||
if(this.ImageAnnotationFontSize > 0) {
|
||||
_ = sb.Append($" -ae {this.ImageAnnotationFontSize.Clamp(6, 160).ToString(Ci)}");
|
||||
_ = sb.Append($",{(this.ImageAnnotationFontColor == null ? "0xff" : this.ImageAnnotationFontColor.ToYuvHex(true))}");
|
||||
|
||||
if(this.ImageAnnotationBackground != null) {
|
||||
this.ImageAnnotations |= CameraAnnotation.SolidBackground;
|
||||
_ = sb.Append($",{this.ImageAnnotationBackground.ToYuvHex(true)}");
|
||||
}
|
||||
}
|
||||
|
||||
if (ImageAnnotations != CameraAnnotation.None)
|
||||
sb.Append($" -a {((int)ImageAnnotations).ToString(Ci)}");
|
||||
if(this.ImageAnnotations != CameraAnnotation.None) {
|
||||
_ = sb.Append($" -a {((Int32)this.ImageAnnotations).ToString(Ci)}");
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(ImageAnnotationsText) == false)
|
||||
sb.Append($" -a \"{ImageAnnotationsText.Replace("\"", "'")}\"");
|
||||
if(String.IsNullOrWhiteSpace(this.ImageAnnotationsText) == false) {
|
||||
_ = sb.Append($" -a \"{this.ImageAnnotationsText.Replace("\"", "'")}\"");
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
@ -1,26 +1,24 @@
|
||||
namespace Unosquare.RaspberryIO.Camera
|
||||
{
|
||||
using Swan;
|
||||
using Unosquare.Swan;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Unosquare.RaspberryIO.Camera {
|
||||
/// <summary>
|
||||
/// Defines a wrapper for the raspistill program and its settings (command-line arguments)
|
||||
/// </summary>
|
||||
/// <seealso cref="CameraSettingsBase" />
|
||||
public class CameraStillSettings : CameraSettingsBase
|
||||
{
|
||||
private int _rotate;
|
||||
public class CameraStillSettings : CameraSettingsBase {
|
||||
private Int32 _rotate;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string CommandName => "raspistill";
|
||||
public override String CommandName => "raspistill";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the preview window (if enabled) uses native capture resolution
|
||||
/// This may slow down preview FPS
|
||||
/// </summary>
|
||||
public bool CaptureDisplayPreviewAtResolution { get; set; } = false;
|
||||
public Boolean CaptureDisplayPreviewAtResolution { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the encoding format the hardware will use for the output.
|
||||
@ -31,18 +29,18 @@
|
||||
/// Gets or sets the quality for JPEG only encoding mode.
|
||||
/// Value ranges from 0 to 100
|
||||
/// </summary>
|
||||
public int CaptureJpegQuality { get; set; } = 90;
|
||||
public Int32 CaptureJpegQuality { get; set; } = 90;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the JPEG encoder should add raw bayer metadata.
|
||||
/// </summary>
|
||||
public bool CaptureJpegIncludeRawBayerMetadata { get; set; } = false;
|
||||
public Boolean CaptureJpegIncludeRawBayerMetadata { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// JPEG EXIF data
|
||||
/// Keys and values must be already properly escaped. Otherwise the command will fail.
|
||||
/// </summary>
|
||||
public Dictionary<string, string> CaptureJpegExtendedInfo { get; } = new Dictionary<string, string>();
|
||||
public Dictionary<String, String> CaptureJpegExtendedInfo { get; } = new Dictionary<String, String>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether [horizontal flip].
|
||||
@ -50,7 +48,7 @@
|
||||
/// <value>
|
||||
/// <c>true</c> if [horizontal flip]; otherwise, <c>false</c>.
|
||||
/// </value>
|
||||
public bool HorizontalFlip { get; set; } = false;
|
||||
public Boolean HorizontalFlip { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether [vertical flip].
|
||||
@ -58,61 +56,64 @@
|
||||
/// <value>
|
||||
/// <c>true</c> if [vertical flip]; otherwise, <c>false</c>.
|
||||
/// </value>
|
||||
public bool VerticalFlip { get; set; } = false;
|
||||
public Boolean VerticalFlip { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the rotation.
|
||||
/// </summary>
|
||||
/// <exception cref="ArgumentOutOfRangeException">Valid range 0-359</exception>
|
||||
public int Rotation
|
||||
{
|
||||
get => _rotate;
|
||||
set
|
||||
{
|
||||
if (value < 0 || value > 359)
|
||||
{
|
||||
public Int32 Rotation {
|
||||
get => this._rotate;
|
||||
set {
|
||||
if(value < 0 || value > 359) {
|
||||
throw new ArgumentOutOfRangeException(nameof(value), "Valid range 0-359");
|
||||
}
|
||||
|
||||
_rotate = value;
|
||||
this._rotate = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string CreateProcessArguments()
|
||||
{
|
||||
var sb = new StringBuilder(base.CreateProcessArguments());
|
||||
sb.Append($" -e {CaptureEncoding.ToString().ToLowerInvariant()}");
|
||||
public override String CreateProcessArguments() {
|
||||
StringBuilder sb = new StringBuilder(base.CreateProcessArguments());
|
||||
_ = sb.Append($" -e {this.CaptureEncoding.ToString().ToLowerInvariant()}");
|
||||
|
||||
// JPEG Encoder specific arguments
|
||||
if (CaptureEncoding == CameraImageEncodingFormat.Jpg)
|
||||
{
|
||||
sb.Append($" -q {CaptureJpegQuality.Clamp(0, 100).ToString(Ci)}");
|
||||
if(this.CaptureEncoding == CameraImageEncodingFormat.Jpg) {
|
||||
_ = sb.Append($" -q {this.CaptureJpegQuality.Clamp(0, 100).ToString(Ci)}");
|
||||
|
||||
if (CaptureJpegIncludeRawBayerMetadata)
|
||||
sb.Append(" -r");
|
||||
if(this.CaptureJpegIncludeRawBayerMetadata) {
|
||||
_ = sb.Append(" -r");
|
||||
}
|
||||
|
||||
// JPEG EXIF data
|
||||
if (CaptureJpegExtendedInfo.Count > 0)
|
||||
{
|
||||
foreach (var kvp in CaptureJpegExtendedInfo)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(kvp.Key) || string.IsNullOrWhiteSpace(kvp.Value))
|
||||
if(this.CaptureJpegExtendedInfo.Count > 0) {
|
||||
foreach(KeyValuePair<String, String> kvp in this.CaptureJpegExtendedInfo) {
|
||||
if(String.IsNullOrWhiteSpace(kvp.Key) || String.IsNullOrWhiteSpace(kvp.Value)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
sb.Append($" -x \"{kvp.Key.Replace("\"", "'")}={kvp.Value.Replace("\"", "'")}\"");
|
||||
_ = sb.Append($" -x \"{kvp.Key.Replace("\"", "'")}={kvp.Value.Replace("\"", "'")}\"");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Display preview settings
|
||||
if (CaptureDisplayPreview && CaptureDisplayPreviewAtResolution) sb.Append(" -fp");
|
||||
if(this.CaptureDisplayPreview && this.CaptureDisplayPreviewAtResolution) {
|
||||
_ = sb.Append(" -fp");
|
||||
}
|
||||
|
||||
if (Rotation != 0) sb.Append($" -rot {Rotation}");
|
||||
if(this.Rotation != 0) {
|
||||
_ = sb.Append($" -rot {this.Rotation}");
|
||||
}
|
||||
|
||||
if (HorizontalFlip) sb.Append(" -hf");
|
||||
if(this.HorizontalFlip) {
|
||||
_ = sb.Append(" -hf");
|
||||
}
|
||||
|
||||
if (VerticalFlip) sb.Append(" -vf");
|
||||
if(this.VerticalFlip) {
|
||||
_ = sb.Append(" -vf");
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
@ -1,43 +1,42 @@
|
||||
namespace Unosquare.RaspberryIO.Camera
|
||||
{
|
||||
using Swan;
|
||||
using Unosquare.Swan;
|
||||
using System;
|
||||
using System.Text;
|
||||
|
||||
namespace Unosquare.RaspberryIO.Camera {
|
||||
/// <summary>
|
||||
/// Represents the raspivid camera settings for video capture functionality
|
||||
/// </summary>
|
||||
/// <seealso cref="CameraSettingsBase" />
|
||||
public class CameraVideoSettings : CameraSettingsBase
|
||||
{
|
||||
public class CameraVideoSettings : CameraSettingsBase {
|
||||
/// <inheritdoc />
|
||||
public override string CommandName => "raspivid";
|
||||
public override String CommandName => "raspivid";
|
||||
|
||||
/// <summary>
|
||||
/// Use bits per second, so 10Mbits/s would be -b 10000000. For H264, 1080p30 a high quality bitrate would be 15Mbits/s or more.
|
||||
/// Maximum bitrate is 25Mbits/s (-b 25000000), but much over 17Mbits/s won't show noticeable improvement at 1080p30.
|
||||
/// Default -1
|
||||
/// </summary>
|
||||
public int CaptureBitrate { get; set; } = -1;
|
||||
public Int32 CaptureBitrate { get; set; } = -1;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the framerate.
|
||||
/// Default 25, range 2 to 30
|
||||
/// </summary>
|
||||
public int CaptureFramerate { get; set; } = 25;
|
||||
public Int32 CaptureFramerate { get; set; } = 25;
|
||||
|
||||
/// <summary>
|
||||
/// Sets the intra refresh period (GoP) rate for the recorded video. H264 video uses a complete frame (I-frame) every intra
|
||||
/// refresh period, from which subsequent frames are based. This option specifies the number of frames between each I-frame.
|
||||
/// Larger numbers here will reduce the size of the resulting video, and smaller numbers make the stream less error-prone.
|
||||
/// </summary>
|
||||
public int CaptureKeyframeRate { get; set; } = 25;
|
||||
public Int32 CaptureKeyframeRate { get; set; } = 25;
|
||||
|
||||
/// <summary>
|
||||
/// Sets the initial quantisation parameter for the stream. Varies from approximately 10 to 40, and will greatly affect
|
||||
/// the quality of the recording. Higher values reduce quality and decrease file size. Combine this setting with a
|
||||
/// bitrate of 0 to set a completely variable bitrate.
|
||||
/// </summary>
|
||||
public int CaptureQuantisation { get; set; } = 23;
|
||||
public Int32 CaptureQuantisation { get; set; } = 23;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the profile.
|
||||
@ -53,7 +52,7 @@
|
||||
/// <value>
|
||||
/// <c>true</c> if [interleave headers]; otherwise, <c>false</c>.
|
||||
/// </value>
|
||||
public bool CaptureInterleaveHeaders { get; set; } = true;
|
||||
public Boolean CaptureInterleaveHeaders { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Switch on an option to display the preview after compression. This will show any compression artefacts in the preview window. In normal operation,
|
||||
@ -62,31 +61,36 @@
|
||||
/// <value>
|
||||
/// <c>true</c> if [capture display preview encoded]; otherwise, <c>false</c>.
|
||||
/// </value>
|
||||
public bool CaptureDisplayPreviewEncoded { get; set; } = false;
|
||||
public Boolean CaptureDisplayPreviewEncoded { get; set; } = false;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string CreateProcessArguments()
|
||||
{
|
||||
var sb = new StringBuilder(base.CreateProcessArguments());
|
||||
public override String CreateProcessArguments() {
|
||||
StringBuilder sb = new StringBuilder(base.CreateProcessArguments());
|
||||
|
||||
sb.Append($" -pf {CaptureProfile.ToString().ToLowerInvariant()}");
|
||||
if (CaptureBitrate < 0)
|
||||
sb.Append($" -b {CaptureBitrate.Clamp(0, 25000000).ToString(Ci)}");
|
||||
_ = sb.Append($" -pf {this.CaptureProfile.ToString().ToLowerInvariant()}");
|
||||
if(this.CaptureBitrate < 0) {
|
||||
_ = sb.Append($" -b {this.CaptureBitrate.Clamp(0, 25000000).ToString(Ci)}");
|
||||
}
|
||||
|
||||
if (CaptureFramerate >= 2)
|
||||
sb.Append($" -fps {CaptureFramerate.Clamp(2, 30).ToString(Ci)}");
|
||||
if(this.CaptureFramerate >= 2) {
|
||||
_ = sb.Append($" -fps {this.CaptureFramerate.Clamp(2, 30).ToString(Ci)}");
|
||||
}
|
||||
|
||||
if (CaptureDisplayPreview && CaptureDisplayPreviewEncoded)
|
||||
sb.Append(" -e");
|
||||
if(this.CaptureDisplayPreview && this.CaptureDisplayPreviewEncoded) {
|
||||
_ = sb.Append(" -e");
|
||||
}
|
||||
|
||||
if (CaptureKeyframeRate > 0)
|
||||
sb.Append($" -g {CaptureKeyframeRate.ToString(Ci)}");
|
||||
if(this.CaptureKeyframeRate > 0) {
|
||||
_ = sb.Append($" -g {this.CaptureKeyframeRate.ToString(Ci)}");
|
||||
}
|
||||
|
||||
if (CaptureQuantisation >= 0)
|
||||
sb.Append($" -qp {CaptureQuantisation.Clamp(0, 40).ToString(Ci)}");
|
||||
if(this.CaptureQuantisation >= 0) {
|
||||
_ = sb.Append($" -qp {this.CaptureQuantisation.Clamp(0, 40).ToString(Ci)}");
|
||||
}
|
||||
|
||||
if (CaptureInterleaveHeaders)
|
||||
sb.Append(" -ih");
|
||||
if(this.CaptureInterleaveHeaders) {
|
||||
_ = sb.Append(" -ih");
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
@ -1,12 +1,10 @@
|
||||
namespace Unosquare.RaspberryIO.Camera
|
||||
{
|
||||
using System;
|
||||
using System;
|
||||
|
||||
namespace Unosquare.RaspberryIO.Camera {
|
||||
/// <summary>
|
||||
/// Defines the available encoding formats for the Raspberry Pi camera module
|
||||
/// </summary>
|
||||
public enum CameraImageEncodingFormat
|
||||
{
|
||||
public enum CameraImageEncodingFormat {
|
||||
/// <summary>
|
||||
/// The JPG
|
||||
/// </summary>
|
||||
@ -31,8 +29,7 @@
|
||||
/// <summary>
|
||||
/// Defines the different exposure modes for the Raspberry Pi's camera module
|
||||
/// </summary>
|
||||
public enum CameraExposureMode
|
||||
{
|
||||
public enum CameraExposureMode {
|
||||
/// <summary>
|
||||
/// The automatic
|
||||
/// </summary>
|
||||
@ -97,8 +94,7 @@
|
||||
/// <summary>
|
||||
/// Defines the different AWB (Auto White Balance) modes for the Raspberry Pi's camera module
|
||||
/// </summary>
|
||||
public enum CameraWhiteBalanceMode
|
||||
{
|
||||
public enum CameraWhiteBalanceMode {
|
||||
/// <summary>
|
||||
/// No white balance
|
||||
/// </summary>
|
||||
@ -153,8 +149,7 @@
|
||||
/// <summary>
|
||||
/// Defines the available image effects for the Raspberry Pi's camera module
|
||||
/// </summary>
|
||||
public enum CameraImageEffect
|
||||
{
|
||||
public enum CameraImageEffect {
|
||||
/// <summary>
|
||||
/// No effect
|
||||
/// </summary>
|
||||
@ -264,8 +259,7 @@
|
||||
/// <summary>
|
||||
/// Defines the different metering modes for the Raspberry Pi's camera module
|
||||
/// </summary>
|
||||
public enum CameraMeteringMode
|
||||
{
|
||||
public enum CameraMeteringMode {
|
||||
/// <summary>
|
||||
/// The average
|
||||
/// </summary>
|
||||
@ -290,8 +284,7 @@
|
||||
/// <summary>
|
||||
/// Defines the different image rotation modes for the Raspberry Pi's camera module
|
||||
/// </summary>
|
||||
public enum CameraImageRotation
|
||||
{
|
||||
public enum CameraImageRotation {
|
||||
/// <summary>
|
||||
/// No rerotation
|
||||
/// </summary>
|
||||
@ -317,8 +310,7 @@
|
||||
/// Defines the different DRC (Dynamic Range Compensation) modes for the Raspberry Pi's camera module
|
||||
/// Helpful for low light photos
|
||||
/// </summary>
|
||||
public enum CameraDynamicRangeCompensation
|
||||
{
|
||||
public enum CameraDynamicRangeCompensation {
|
||||
/// <summary>
|
||||
/// The off setting
|
||||
/// </summary>
|
||||
@ -344,8 +336,7 @@
|
||||
/// Defines the bit-wise mask flags for the available annotation elements for the Raspberry Pi's camera module
|
||||
/// </summary>
|
||||
[Flags]
|
||||
public enum CameraAnnotation
|
||||
{
|
||||
public enum CameraAnnotation {
|
||||
/// <summary>
|
||||
/// The none
|
||||
/// </summary>
|
||||
@ -400,8 +391,7 @@
|
||||
/// <summary>
|
||||
/// Defines the different H.264 encoding profiles to be used when capturing video.
|
||||
/// </summary>
|
||||
public enum CameraH264Profile
|
||||
{
|
||||
public enum CameraH264Profile {
|
||||
/// <summary>
|
||||
/// BP: Primarily for lower-cost applications with limited computing resources,
|
||||
/// this profile is used widely in videoconferencing and mobile applications.
|
||||
|
@ -1,24 +1,22 @@
|
||||
namespace Unosquare.RaspberryIO.Computer
|
||||
{
|
||||
using Swan.Abstractions;
|
||||
using Unosquare.Swan.Abstractions;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System;
|
||||
|
||||
namespace Unosquare.RaspberryIO.Computer {
|
||||
/// <summary>
|
||||
/// The Official Raspberry Pi 7-inch touch display from the foundation
|
||||
/// Some docs available here:
|
||||
/// http://forums.pimoroni.com/t/official-7-raspberry-pi-touch-screen-faq/959
|
||||
/// </summary>
|
||||
public class DsiDisplay : SingletonBase<DsiDisplay>
|
||||
{
|
||||
private const string BacklightFilename = "/sys/class/backlight/rpi_backlight/bl_power";
|
||||
private const string BrightnessFilename = "/sys/class/backlight/rpi_backlight/brightness";
|
||||
public class DsiDisplay : SingletonBase<DsiDisplay> {
|
||||
private const String BacklightFilename = "/sys/class/backlight/rpi_backlight/bl_power";
|
||||
private const String BrightnessFilename = "/sys/class/backlight/rpi_backlight/brightness";
|
||||
|
||||
/// <summary>
|
||||
/// Prevents a default instance of the <see cref="DsiDisplay"/> class from being created.
|
||||
/// </summary>
|
||||
private DsiDisplay()
|
||||
{
|
||||
private DsiDisplay() {
|
||||
// placeholder
|
||||
}
|
||||
|
||||
@ -28,7 +26,7 @@
|
||||
/// <value>
|
||||
/// <c>true</c> if this instance is present; otherwise, <c>false</c>.
|
||||
/// </value>
|
||||
public bool IsPresent => File.Exists(BrightnessFilename);
|
||||
public Boolean IsPresent => File.Exists(BrightnessFilename);
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the brightness of the DSI display via filesystem.
|
||||
@ -36,17 +34,13 @@
|
||||
/// <value>
|
||||
/// The brightness.
|
||||
/// </value>
|
||||
public byte Brightness
|
||||
{
|
||||
get
|
||||
{
|
||||
if (IsPresent == false) return 0;
|
||||
|
||||
return byte.TryParse(File.ReadAllText(BrightnessFilename).Trim(), out var brightness) ? brightness : (byte)0;
|
||||
public Byte Brightness {
|
||||
get => this.IsPresent == false ? (Byte)0 : Byte.TryParse(File.ReadAllText(BrightnessFilename).Trim(), out Byte brightness) ? brightness : (Byte)0;
|
||||
set {
|
||||
if(this.IsPresent == false) {
|
||||
return;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (IsPresent == false) return;
|
||||
|
||||
File.WriteAllText(BrightnessFilename, value.ToString(CultureInfo.InvariantCulture));
|
||||
}
|
||||
}
|
||||
@ -58,20 +52,12 @@
|
||||
/// <value>
|
||||
/// <c>true</c> if this instance is backlight on; otherwise, <c>false</c>.
|
||||
/// </value>
|
||||
public bool IsBacklightOn
|
||||
{
|
||||
get
|
||||
{
|
||||
if (IsPresent == false) return false;
|
||||
|
||||
if (int.TryParse(File.ReadAllText(BacklightFilename).Trim(), out var backlight))
|
||||
return backlight == 0;
|
||||
|
||||
return false;
|
||||
public Boolean IsBacklightOn {
|
||||
get => this.IsPresent == false ? false : Int32.TryParse(File.ReadAllText(BacklightFilename).Trim(), out Int32 backlight) ? backlight == 0 : false;
|
||||
set {
|
||||
if(this.IsPresent == false) {
|
||||
return;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (IsPresent == false) return;
|
||||
|
||||
File.WriteAllText(BacklightFilename, value ? "0" : "1");
|
||||
}
|
||||
|
@ -1,40 +1,51 @@
|
||||
namespace Unosquare.RaspberryIO.Computer
|
||||
{
|
||||
using System;
|
||||
using System.Net;
|
||||
|
||||
namespace Unosquare.RaspberryIO.Computer {
|
||||
/// <summary>
|
||||
/// Represents a Network Adapter
|
||||
/// </summary>
|
||||
public class NetworkAdapterInfo
|
||||
{
|
||||
public class NetworkAdapterInfo {
|
||||
/// <summary>
|
||||
/// Gets the name.
|
||||
/// </summary>
|
||||
public string Name { get; internal set; }
|
||||
public String Name {
|
||||
get; internal set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the IP V4 address.
|
||||
/// </summary>
|
||||
public IPAddress IPv4 { get; internal set; }
|
||||
public IPAddress IPv4 {
|
||||
get; internal set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the IP V6 address.
|
||||
/// </summary>
|
||||
public IPAddress IPv6 { get; internal set; }
|
||||
public IPAddress IPv6 {
|
||||
get; internal set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of the access point.
|
||||
/// </summary>
|
||||
public string AccessPointName { get; internal set; }
|
||||
public String AccessPointName {
|
||||
get; internal set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the MAC (Physical) address.
|
||||
/// </summary>
|
||||
public string MacAddress { get; internal set; }
|
||||
public String MacAddress {
|
||||
get; internal set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this instance is wireless.
|
||||
/// </summary>
|
||||
public bool IsWireless { get; internal set; }
|
||||
public Boolean IsWireless {
|
||||
get; internal set;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,6 @@
|
||||
namespace Unosquare.RaspberryIO.Computer
|
||||
{
|
||||
using Swan;
|
||||
using Swan.Abstractions;
|
||||
using Swan.Components;
|
||||
using Unosquare.Swan;
|
||||
using Unosquare.Swan.Abstractions;
|
||||
using Unosquare.Swan.Components;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
@ -10,86 +8,85 @@
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
|
||||
namespace Unosquare.RaspberryIO.Computer {
|
||||
/// <summary>
|
||||
/// Represents the network information
|
||||
/// </summary>
|
||||
public class NetworkSettings : SingletonBase<NetworkSettings>
|
||||
{
|
||||
private const string EssidTag = "ESSID:";
|
||||
public class NetworkSettings : SingletonBase<NetworkSettings> {
|
||||
private const String EssidTag = "ESSID:";
|
||||
|
||||
/// <summary>
|
||||
/// Gets the local machine Host Name.
|
||||
/// </summary>
|
||||
public string HostName => Network.HostName;
|
||||
public String HostName => Network.HostName;
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the wireless networks.
|
||||
/// </summary>
|
||||
/// <param name="adapter">The adapter.</param>
|
||||
/// <returns>A list of WiFi networks</returns>
|
||||
public List<WirelessNetworkInfo> RetrieveWirelessNetworks(string adapter) => RetrieveWirelessNetworks(new[] { adapter });
|
||||
public List<WirelessNetworkInfo> RetrieveWirelessNetworks(String adapter) => this.RetrieveWirelessNetworks(new[] { adapter });
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the wireless networks.
|
||||
/// </summary>
|
||||
/// <param name="adapters">The adapters.</param>
|
||||
/// <returns>A list of WiFi networks</returns>
|
||||
public List<WirelessNetworkInfo> RetrieveWirelessNetworks(string[] adapters = null)
|
||||
{
|
||||
var result = new List<WirelessNetworkInfo>();
|
||||
public List<WirelessNetworkInfo> RetrieveWirelessNetworks(String[] adapters = null) {
|
||||
List<WirelessNetworkInfo> result = new List<WirelessNetworkInfo>();
|
||||
|
||||
foreach (var networkAdapter in adapters ?? RetrieveAdapters().Where(x => x.IsWireless).Select(x => x.Name))
|
||||
{
|
||||
var wirelessOutput = ProcessRunner.GetProcessOutputAsync("iwlist", $"{networkAdapter} scanning").Result;
|
||||
var outputLines =
|
||||
foreach(String networkAdapter in adapters ?? this.RetrieveAdapters().Where(x => x.IsWireless).Select(x => x.Name)) {
|
||||
String wirelessOutput = ProcessRunner.GetProcessOutputAsync("iwlist", $"{networkAdapter} scanning").Result;
|
||||
String[] outputLines =
|
||||
wirelessOutput.Split('\n')
|
||||
.Select(x => x.Trim())
|
||||
.Where(x => string.IsNullOrWhiteSpace(x) == false)
|
||||
.Where(x => String.IsNullOrWhiteSpace(x) == false)
|
||||
.ToArray();
|
||||
|
||||
for (var i = 0; i < outputLines.Length; i++)
|
||||
{
|
||||
var line = outputLines[i];
|
||||
for(Int32 i = 0; i < outputLines.Length; i++) {
|
||||
String line = outputLines[i];
|
||||
|
||||
if (line.StartsWith(EssidTag) == false) continue;
|
||||
if(line.StartsWith(EssidTag) == false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var network = new WirelessNetworkInfo()
|
||||
{
|
||||
Name = line.Replace(EssidTag, string.Empty).Replace("\"", string.Empty)
|
||||
WirelessNetworkInfo network = new WirelessNetworkInfo() {
|
||||
Name = line.Replace(EssidTag, String.Empty).Replace("\"", String.Empty)
|
||||
};
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (i + 1 >= outputLines.Length) break;
|
||||
while(true) {
|
||||
if(i + 1 >= outputLines.Length) {
|
||||
break;
|
||||
}
|
||||
|
||||
// should look for two lines before the ESSID acording to the scan
|
||||
line = outputLines[i - 2];
|
||||
|
||||
if (line.StartsWith("Quality="))
|
||||
{
|
||||
network.Quality = line.Replace("Quality=", string.Empty);
|
||||
if(line.StartsWith("Quality=")) {
|
||||
network.Quality = line.Replace("Quality=", String.Empty);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (i + 1 >= outputLines.Length) break;
|
||||
while(true) {
|
||||
if(i + 1 >= outputLines.Length) {
|
||||
break;
|
||||
}
|
||||
|
||||
// should look for a line before the ESSID acording to the scan
|
||||
line = outputLines[i - 1];
|
||||
|
||||
if (line.StartsWith("Encryption key:"))
|
||||
{
|
||||
network.IsEncrypted = line.Replace("Encryption key:", string.Empty).Trim() == "on";
|
||||
if(line.StartsWith("Encryption key:")) {
|
||||
network.IsEncrypted = line.Replace("Encryption key:", String.Empty).Trim() == "on";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (result.Any(x => x.Name == network.Name) == false)
|
||||
if(result.Any(x => x.Name == network.Name) == false) {
|
||||
result.Add(network);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result.OrderBy(x => x.Name).ToList();
|
||||
}
|
||||
@ -102,22 +99,18 @@
|
||||
/// <param name="password">The password.</param>
|
||||
/// <param name="countryCode">The 2-letter country code in uppercase. Default is US.</param>
|
||||
/// <returns>True if successful. Otherwise, false.</returns>
|
||||
public bool SetupWirelessNetwork(string adapterName, string networkSsid, string password = null, string countryCode = "US")
|
||||
{
|
||||
public Boolean SetupWirelessNetwork(String adapterName, String networkSsid, String password = null, String countryCode = "US") {
|
||||
// TODO: Get the country where the device is located to set 'country' param in payload var
|
||||
var payload = $"country={countryCode}\nctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev\nupdate_config=1\n";
|
||||
payload += string.IsNullOrEmpty(password)
|
||||
String payload = $"country={countryCode}\nctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev\nupdate_config=1\n";
|
||||
payload += String.IsNullOrEmpty(password)
|
||||
? $"network={{\n\tssid=\"{networkSsid}\"\n\t}}\n"
|
||||
: $"network={{\n\tssid=\"{networkSsid}\"\n\tpsk=\"{password}\"\n\t}}\n";
|
||||
try
|
||||
{
|
||||
try {
|
||||
File.WriteAllText("/etc/wpa_supplicant/wpa_supplicant.conf", payload);
|
||||
ProcessRunner.GetProcessOutputAsync("pkill", "-f wpa_supplicant").Wait();
|
||||
ProcessRunner.GetProcessOutputAsync("ifdown", adapterName).Wait();
|
||||
ProcessRunner.GetProcessOutputAsync("ifup", adapterName).Wait();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
} catch(Exception ex) {
|
||||
ex.Log(nameof(NetworkSettings));
|
||||
return false;
|
||||
}
|
||||
@ -129,99 +122,92 @@
|
||||
/// Retrieves the network adapters.
|
||||
/// </summary>
|
||||
/// <returns>A list of network adapters.</returns>
|
||||
public List<NetworkAdapterInfo> RetrieveAdapters()
|
||||
{
|
||||
const string hWaddr = "HWaddr ";
|
||||
const string ether = "ether ";
|
||||
public List<NetworkAdapterInfo> RetrieveAdapters() {
|
||||
const String hWaddr = "HWaddr ";
|
||||
const String ether = "ether ";
|
||||
|
||||
var result = new List<NetworkAdapterInfo>();
|
||||
var interfacesOutput = ProcessRunner.GetProcessOutputAsync("ifconfig").Result;
|
||||
var wlanOutput = ProcessRunner.GetProcessOutputAsync("iwconfig")
|
||||
List<NetworkAdapterInfo> result = new List<NetworkAdapterInfo>();
|
||||
String interfacesOutput = ProcessRunner.GetProcessOutputAsync("ifconfig").Result;
|
||||
String[] wlanOutput = ProcessRunner.GetProcessOutputAsync("iwconfig")
|
||||
.Result.Split('\n')
|
||||
.Where(x => x.Contains("no wireless extensions.") == false)
|
||||
.ToArray();
|
||||
|
||||
var outputLines = interfacesOutput.Split('\n').Where(x => string.IsNullOrWhiteSpace(x) == false).ToArray();
|
||||
String[] outputLines = interfacesOutput.Split('\n').Where(x => String.IsNullOrWhiteSpace(x) == false).ToArray();
|
||||
|
||||
for (var i = 0; i < outputLines.Length; i++)
|
||||
{
|
||||
for(Int32 i = 0; i < outputLines.Length; i++) {
|
||||
// grab the current line
|
||||
var line = outputLines[i];
|
||||
String line = outputLines[i];
|
||||
|
||||
// skip if the line is indented
|
||||
if (char.IsLetterOrDigit(line[0]) == false)
|
||||
if(Char.IsLetterOrDigit(line[0]) == false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Read the line as an adatper
|
||||
var adapter = new NetworkAdapterInfo
|
||||
{
|
||||
NetworkAdapterInfo adapter = new NetworkAdapterInfo {
|
||||
Name = line.Substring(0, line.IndexOf(' ')).TrimEnd(':')
|
||||
};
|
||||
|
||||
// Parse the MAC address in old version of ifconfig; it comes in the first line
|
||||
if (line.IndexOf(hWaddr) >= 0)
|
||||
{
|
||||
var startIndexHwd = line.IndexOf(hWaddr) + hWaddr.Length;
|
||||
if(line.IndexOf(hWaddr) >= 0) {
|
||||
Int32 startIndexHwd = line.IndexOf(hWaddr) + hWaddr.Length;
|
||||
adapter.MacAddress = line.Substring(startIndexHwd, 17).Trim();
|
||||
}
|
||||
|
||||
// Parse the info in lines other than the first
|
||||
for (var j = i + 1; j < outputLines.Length; j++)
|
||||
{
|
||||
for(Int32 j = i + 1; j < outputLines.Length; j++) {
|
||||
// Get the contents of the indented line
|
||||
var indentedLine = outputLines[j];
|
||||
String indentedLine = outputLines[j];
|
||||
|
||||
// We have hit the next adapter info
|
||||
if (char.IsLetterOrDigit(indentedLine[0]))
|
||||
{
|
||||
if(Char.IsLetterOrDigit(indentedLine[0])) {
|
||||
i = j - 1;
|
||||
break;
|
||||
}
|
||||
|
||||
// Parse the MAC address in new versions of ifconfig; it no longer comes in the first line
|
||||
if (indentedLine.IndexOf(ether) >= 0 && string.IsNullOrWhiteSpace(adapter.MacAddress))
|
||||
{
|
||||
var startIndexHwd = indentedLine.IndexOf(ether) + ether.Length;
|
||||
if(indentedLine.IndexOf(ether) >= 0 && String.IsNullOrWhiteSpace(adapter.MacAddress)) {
|
||||
Int32 startIndexHwd = indentedLine.IndexOf(ether) + ether.Length;
|
||||
adapter.MacAddress = indentedLine.Substring(startIndexHwd, 17).Trim();
|
||||
}
|
||||
|
||||
// Parse the IPv4 Address
|
||||
{
|
||||
var addressText = ParseOutputTagFromLine(indentedLine, "inet addr:") ?? ParseOutputTagFromLine(indentedLine, "inet ");
|
||||
String addressText = ParseOutputTagFromLine(indentedLine, "inet addr:") ?? ParseOutputTagFromLine(indentedLine, "inet ");
|
||||
|
||||
if (addressText != null)
|
||||
{
|
||||
if (IPAddress.TryParse(addressText, out var outValue))
|
||||
if(addressText != null) {
|
||||
if(IPAddress.TryParse(addressText, out IPAddress outValue)) {
|
||||
adapter.IPv4 = outValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Parse the IPv6 Address
|
||||
{
|
||||
var addressText = ParseOutputTagFromLine(indentedLine, "inet6 addr:") ?? ParseOutputTagFromLine(indentedLine, "inet6 ");
|
||||
String addressText = ParseOutputTagFromLine(indentedLine, "inet6 addr:") ?? ParseOutputTagFromLine(indentedLine, "inet6 ");
|
||||
|
||||
if (addressText != null)
|
||||
{
|
||||
if (IPAddress.TryParse(addressText, out var outValue))
|
||||
if(addressText != null) {
|
||||
if(IPAddress.TryParse(addressText, out IPAddress outValue)) {
|
||||
adapter.IPv6 = outValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// we have hit the end of the output in an indented line
|
||||
if (j >= outputLines.Length - 1)
|
||||
if(j >= outputLines.Length - 1) {
|
||||
i = outputLines.Length;
|
||||
}
|
||||
}
|
||||
|
||||
// Retrieve the wireless LAN info
|
||||
var wlanInfo = wlanOutput.FirstOrDefault(x => x.StartsWith(adapter.Name));
|
||||
String wlanInfo = wlanOutput.FirstOrDefault(x => x.StartsWith(adapter.Name));
|
||||
|
||||
if (wlanInfo != null)
|
||||
{
|
||||
if(wlanInfo != null) {
|
||||
adapter.IsWireless = true;
|
||||
var essidParts = wlanInfo.Split(new[] { EssidTag }, StringSplitOptions.RemoveEmptyEntries);
|
||||
if (essidParts.Length >= 2)
|
||||
{
|
||||
adapter.AccessPointName = essidParts[1].Replace("\"", string.Empty).Trim();
|
||||
String[] essidParts = wlanInfo.Split(new[] { EssidTag }, StringSplitOptions.RemoveEmptyEntries);
|
||||
if(essidParts.Length >= 2) {
|
||||
adapter.AccessPointName = essidParts[1].Replace("\"", String.Empty).Trim();
|
||||
}
|
||||
}
|
||||
|
||||
@ -236,7 +222,7 @@
|
||||
/// Retrieves current wireless connected network name.
|
||||
/// </summary>
|
||||
/// <returns>The connected network name.</returns>
|
||||
public string GetWirelessNetworkName() => ProcessRunner.GetProcessOutputAsync("iwgetid", "-r").Result;
|
||||
public String GetWirelessNetworkName() => ProcessRunner.GetProcessOutputAsync("iwgetid", "-r").Result;
|
||||
|
||||
/// <summary>
|
||||
/// Parses the output tag from the given line.
|
||||
@ -244,20 +230,20 @@
|
||||
/// <param name="indentedLine">The indented line.</param>
|
||||
/// <param name="tagName">Name of the tag.</param>
|
||||
/// <returns>The value after the tag identifier</returns>
|
||||
private static string ParseOutputTagFromLine(string indentedLine, string tagName)
|
||||
{
|
||||
if (indentedLine.IndexOf(tagName) < 0)
|
||||
private static String ParseOutputTagFromLine(String indentedLine, String tagName) {
|
||||
if(indentedLine.IndexOf(tagName) < 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var startIndex = indentedLine.IndexOf(tagName) + tagName.Length;
|
||||
var builder = new StringBuilder(1024);
|
||||
for (var c = startIndex; c < indentedLine.Length; c++)
|
||||
{
|
||||
var currentChar = indentedLine[c];
|
||||
if (!char.IsPunctuation(currentChar) && !char.IsLetterOrDigit(currentChar))
|
||||
Int32 startIndex = indentedLine.IndexOf(tagName) + tagName.Length;
|
||||
StringBuilder builder = new StringBuilder(1024);
|
||||
for(Int32 c = startIndex; c < indentedLine.Length; c++) {
|
||||
Char currentChar = indentedLine[c];
|
||||
if(!Char.IsPunctuation(currentChar) && !Char.IsLetterOrDigit(currentChar)) {
|
||||
break;
|
||||
}
|
||||
|
||||
builder.Append(currentChar);
|
||||
_ = builder.Append(currentChar);
|
||||
}
|
||||
|
||||
return builder.ToString();
|
||||
|
@ -1,46 +1,58 @@
|
||||
namespace Unosquare.RaspberryIO.Computer
|
||||
{
|
||||
using System;
|
||||
|
||||
namespace Unosquare.RaspberryIO.Computer {
|
||||
/// <summary>
|
||||
/// Represents the OS Information
|
||||
/// </summary>
|
||||
public class OsInfo
|
||||
{
|
||||
public class OsInfo {
|
||||
/// <summary>
|
||||
/// System name
|
||||
/// </summary>
|
||||
public string SysName { get; set; }
|
||||
public String SysName {
|
||||
get; set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Node name
|
||||
/// </summary>
|
||||
public string NodeName { get; set; }
|
||||
public String NodeName {
|
||||
get; set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Release level
|
||||
/// </summary>
|
||||
public string Release { get; set; }
|
||||
public String Release {
|
||||
get; set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Version level
|
||||
/// </summary>
|
||||
public string Version { get; set; }
|
||||
public String Version {
|
||||
get; set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Hardware level
|
||||
/// </summary>
|
||||
public string Machine { get; set; }
|
||||
public String Machine {
|
||||
get; set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Domain name
|
||||
/// </summary>
|
||||
public string DomainName { get; set; }
|
||||
public String DomainName {
|
||||
get; set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a <see cref="string" /> that represents this instance.
|
||||
/// Returns a <see cref="String" /> that represents this instance.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="string" /> that represents this instance.
|
||||
/// A <see cref="String" /> that represents this instance.
|
||||
/// </returns>
|
||||
public override string ToString() => $"{SysName} {Release} {Version}";
|
||||
public override String ToString() => $"{this.SysName} {this.Release} {this.Version}";
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,9 @@
|
||||
namespace Unosquare.RaspberryIO.Computer
|
||||
{
|
||||
namespace Unosquare.RaspberryIO.Computer {
|
||||
/// <summary>
|
||||
/// Defines the board revision codes of the different versions of the Raspberry Pi
|
||||
/// http://www.raspberrypi-spy.co.uk/2012/09/checking-your-raspberry-pi-board-version/
|
||||
/// </summary>
|
||||
public enum PiVersion
|
||||
{
|
||||
public enum PiVersion {
|
||||
/// <summary>
|
||||
/// The unknown version
|
||||
/// </summary>
|
||||
|
@ -1,7 +1,5 @@
|
||||
namespace Unosquare.RaspberryIO.Computer
|
||||
{
|
||||
using Native;
|
||||
using Swan.Abstractions;
|
||||
using Unosquare.RaspberryIO.Native;
|
||||
using Unosquare.Swan.Abstractions;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
@ -9,68 +7,64 @@
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Unosquare.RaspberryIO.Computer {
|
||||
/// <summary>
|
||||
/// http://raspberry-pi-guide.readthedocs.io/en/latest/system.html
|
||||
/// </summary>
|
||||
public sealed class SystemInfo : SingletonBase<SystemInfo>
|
||||
{
|
||||
private const string CpuInfoFilePath = "/proc/cpuinfo";
|
||||
private const string MemInfoFilePath = "/proc/meminfo";
|
||||
private const string UptimeFilePath = "/proc/uptime";
|
||||
public sealed class SystemInfo : SingletonBase<SystemInfo> {
|
||||
private const String CpuInfoFilePath = "/proc/cpuinfo";
|
||||
private const String MemInfoFilePath = "/proc/meminfo";
|
||||
private const String UptimeFilePath = "/proc/uptime";
|
||||
private static readonly StringComparer StringComparer = StringComparer.InvariantCultureIgnoreCase;
|
||||
|
||||
private static readonly object SyncRoot = new object();
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Codequalität", "IDE0052:Ungelesene private Member entfernen", Justification = "<Ausstehend>")]
|
||||
private static readonly Object SyncRoot = new Object();
|
||||
|
||||
/// <summary>
|
||||
/// Prevents a default instance of the <see cref="SystemInfo"/> class from being created.
|
||||
/// </summary>
|
||||
/// <exception cref="NotSupportedException">Could not initialize the GPIO controller</exception>
|
||||
private SystemInfo()
|
||||
{
|
||||
private SystemInfo() {
|
||||
#region Obtain and format a property dictionary
|
||||
|
||||
var properties =
|
||||
PropertyInfo[] properties =
|
||||
typeof(SystemInfo).GetTypeInfo()
|
||||
.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
|
||||
.Where(
|
||||
p =>
|
||||
p.CanWrite && p.CanRead &&
|
||||
(p.PropertyType == typeof(string) || p.PropertyType == typeof(string[])))
|
||||
(p.PropertyType == typeof(String) || p.PropertyType == typeof(String[])))
|
||||
.ToArray();
|
||||
var propDictionary = new Dictionary<string, PropertyInfo>(StringComparer);
|
||||
Dictionary<String, PropertyInfo> propDictionary = new Dictionary<String, PropertyInfo>(StringComparer);
|
||||
|
||||
foreach (var prop in properties)
|
||||
{
|
||||
propDictionary[prop.Name.Replace(" ", string.Empty).ToLowerInvariant().Trim()] = prop;
|
||||
foreach(PropertyInfo prop in properties) {
|
||||
propDictionary[prop.Name.Replace(" ", String.Empty).ToLowerInvariant().Trim()] = prop;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Extract CPU information
|
||||
|
||||
if (File.Exists(CpuInfoFilePath))
|
||||
{
|
||||
var cpuInfoLines = File.ReadAllLines(CpuInfoFilePath);
|
||||
if(File.Exists(CpuInfoFilePath)) {
|
||||
String[] cpuInfoLines = File.ReadAllLines(CpuInfoFilePath);
|
||||
|
||||
foreach (var line in cpuInfoLines)
|
||||
{
|
||||
var lineParts = line.Split(new[] { ':' }, 2);
|
||||
if (lineParts.Length != 2)
|
||||
foreach(String line in cpuInfoLines) {
|
||||
String[] lineParts = line.Split(new[] { ':' }, 2);
|
||||
if(lineParts.Length != 2) {
|
||||
continue;
|
||||
|
||||
var propertyKey = lineParts[0].Trim().Replace(" ", string.Empty);
|
||||
var propertyStringValue = lineParts[1].Trim();
|
||||
|
||||
if (!propDictionary.ContainsKey(propertyKey)) continue;
|
||||
|
||||
var property = propDictionary[propertyKey];
|
||||
if (property.PropertyType == typeof(string))
|
||||
{
|
||||
property.SetValue(this, propertyStringValue);
|
||||
}
|
||||
else if (property.PropertyType == typeof(string[]))
|
||||
{
|
||||
var propertyArrayAvalue = propertyStringValue.Split(' ');
|
||||
|
||||
String propertyKey = lineParts[0].Trim().Replace(" ", String.Empty);
|
||||
String propertyStringValue = lineParts[1].Trim();
|
||||
|
||||
if(!propDictionary.ContainsKey(propertyKey)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
PropertyInfo property = propDictionary[propertyKey];
|
||||
if(property.PropertyType == typeof(String)) {
|
||||
property.SetValue(this, propertyStringValue);
|
||||
} else if(property.PropertyType == typeof(String[])) {
|
||||
String[] propertyArrayAvalue = propertyStringValue.Split(' ');
|
||||
property.SetValue(this, propertyArrayAvalue);
|
||||
}
|
||||
}
|
||||
@ -80,23 +74,22 @@
|
||||
|
||||
#region Extract Memory Information
|
||||
|
||||
if (File.Exists(MemInfoFilePath))
|
||||
{
|
||||
var memInfoLines = File.ReadAllLines(MemInfoFilePath);
|
||||
foreach (var line in memInfoLines)
|
||||
{
|
||||
var lineParts = line.Split(new[] { ':' }, 2);
|
||||
if (lineParts.Length != 2)
|
||||
if(File.Exists(MemInfoFilePath)) {
|
||||
String[] memInfoLines = File.ReadAllLines(MemInfoFilePath);
|
||||
foreach(String line in memInfoLines) {
|
||||
String[] lineParts = line.Split(new[] { ':' }, 2);
|
||||
if(lineParts.Length != 2) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (lineParts[0].ToLowerInvariant().Trim().Equals("memtotal") == false)
|
||||
if(lineParts[0].ToLowerInvariant().Trim().Equals("memtotal") == false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
var memKb = lineParts[1].ToLowerInvariant().Trim().Replace("kb", string.Empty).Trim();
|
||||
String memKb = lineParts[1].ToLowerInvariant().Trim().Replace("kb", String.Empty).Trim();
|
||||
|
||||
if (int.TryParse(memKb, out var parsedMem))
|
||||
{
|
||||
InstalledRam = parsedMem * 1024;
|
||||
if(Int32.TryParse(memKb, out Int32 parsedMem)) {
|
||||
this.InstalledRam = parsedMem * 1024;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -106,26 +99,21 @@
|
||||
|
||||
#region Board Version and Form Factor
|
||||
|
||||
try
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(Revision) == false &&
|
||||
int.TryParse(
|
||||
Revision.ToUpperInvariant(),
|
||||
try {
|
||||
if(String.IsNullOrWhiteSpace(this.Revision) == false &&
|
||||
Int32.TryParse(
|
||||
this.Revision.ToUpperInvariant(),
|
||||
NumberStyles.HexNumber,
|
||||
CultureInfo.InvariantCulture,
|
||||
out var boardVersion))
|
||||
{
|
||||
RaspberryPiVersion = PiVersion.Unknown;
|
||||
if (Enum.GetValues(typeof(PiVersion)).Cast<int>().Contains(boardVersion))
|
||||
{
|
||||
RaspberryPiVersion = (PiVersion)boardVersion;
|
||||
out Int32 boardVersion)) {
|
||||
this.RaspberryPiVersion = PiVersion.Unknown;
|
||||
if(Enum.GetValues(typeof(PiVersion)).Cast<Int32>().Contains(boardVersion)) {
|
||||
this.RaspberryPiVersion = (PiVersion)boardVersion;
|
||||
}
|
||||
}
|
||||
|
||||
WiringPiBoardRevision = WiringPi.PiBoardRev();
|
||||
}
|
||||
catch
|
||||
{
|
||||
this.WiringPiBoardRevision = WiringPi.PiBoardRev();
|
||||
} catch {
|
||||
/* Ignore */
|
||||
}
|
||||
|
||||
@ -134,22 +122,20 @@
|
||||
#region Version Information
|
||||
|
||||
{
|
||||
var libParts = WiringPi.WiringPiLibrary.Split('.');
|
||||
var major = int.Parse(libParts[libParts.Length - 2]);
|
||||
var minor = int.Parse(libParts[libParts.Length - 1]);
|
||||
var version = new Version(major, minor);
|
||||
WiringPiVersion = version;
|
||||
String[] libParts = WiringPi.WiringPiLibrary.Split('.');
|
||||
Int32 major = Int32.Parse(libParts[libParts.Length - 2]);
|
||||
Int32 minor = Int32.Parse(libParts[libParts.Length - 1]);
|
||||
Version version = new Version(major, minor);
|
||||
this.WiringPiVersion = version;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Extract OS Info
|
||||
|
||||
try
|
||||
{
|
||||
Standard.Uname(out var unameInfo);
|
||||
OperatingSystem = new OsInfo
|
||||
{
|
||||
try {
|
||||
_ = Standard.Uname(out SystemName unameInfo);
|
||||
this.OperatingSystem = new OsInfo {
|
||||
DomainName = unameInfo.DomainName,
|
||||
Machine = unameInfo.Machine,
|
||||
NodeName = unameInfo.NodeName,
|
||||
@ -157,10 +143,8 @@
|
||||
SysName = unameInfo.SysName,
|
||||
Version = unameInfo.Version
|
||||
};
|
||||
}
|
||||
catch
|
||||
{
|
||||
OperatingSystem = new OsInfo();
|
||||
} catch {
|
||||
this.OperatingSystem = new OsInfo();
|
||||
}
|
||||
|
||||
#endregion
|
||||
@ -169,7 +153,9 @@
|
||||
/// <summary>
|
||||
/// Gets the wiring pi library version.
|
||||
/// </summary>
|
||||
public Version WiringPiVersion { get; }
|
||||
public Version WiringPiVersion {
|
||||
get;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the OS information.
|
||||
@ -177,12 +163,16 @@
|
||||
/// <value>
|
||||
/// The os information.
|
||||
/// </value>
|
||||
public OsInfo OperatingSystem { get; }
|
||||
public OsInfo OperatingSystem {
|
||||
get;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Raspberry Pi version.
|
||||
/// </summary>
|
||||
public PiVersion RaspberryPiVersion { get; }
|
||||
public PiVersion RaspberryPiVersion {
|
||||
get;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Wiring Pi board revision (1 or 2).
|
||||
@ -190,100 +180,112 @@
|
||||
/// <value>
|
||||
/// The wiring pi board revision.
|
||||
/// </value>
|
||||
public int WiringPiBoardRevision { get; }
|
||||
public Int32 WiringPiBoardRevision {
|
||||
get;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of processor cores.
|
||||
/// </summary>
|
||||
public int ProcessorCount
|
||||
{
|
||||
get
|
||||
{
|
||||
if (int.TryParse(Processor, out var outIndex))
|
||||
{
|
||||
return outIndex + 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
public Int32 ProcessorCount => Int32.TryParse(this.Processor, out Int32 outIndex) ? outIndex + 1 : 0;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the installed ram in bytes.
|
||||
/// </summary>
|
||||
public int InstalledRam { get; }
|
||||
public Int32 InstalledRam {
|
||||
get;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this CPU is little endian.
|
||||
/// </summary>
|
||||
public bool IsLittleEndian => BitConverter.IsLittleEndian;
|
||||
public Boolean IsLittleEndian => BitConverter.IsLittleEndian;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the CPU model name.
|
||||
/// </summary>
|
||||
public string ModelName { get; private set; }
|
||||
public String ModelName {
|
||||
get; private set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of supported CPU features.
|
||||
/// </summary>
|
||||
public string[] Features { get; private set; }
|
||||
public String[] Features {
|
||||
get; private set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the CPU implementer hex code.
|
||||
/// </summary>
|
||||
public string CpuImplementer { get; private set; }
|
||||
public String CpuImplementer {
|
||||
get; private set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the CPU architecture code.
|
||||
/// </summary>
|
||||
public string CpuArchitecture { get; private set; }
|
||||
public String CpuArchitecture {
|
||||
get; private set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the CPU variant code.
|
||||
/// </summary>
|
||||
public string CpuVariant { get; private set; }
|
||||
public String CpuVariant {
|
||||
get; private set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the CPU part code.
|
||||
/// </summary>
|
||||
public string CpuPart { get; private set; }
|
||||
public String CpuPart {
|
||||
get; private set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the CPU revision code.
|
||||
/// </summary>
|
||||
public string CpuRevision { get; private set; }
|
||||
public String CpuRevision {
|
||||
get; private set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the hardware model number.
|
||||
/// </summary>
|
||||
public string Hardware { get; private set; }
|
||||
public String Hardware {
|
||||
get; private set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the hardware revision number.
|
||||
/// </summary>
|
||||
public string Revision { get; private set; }
|
||||
public String Revision {
|
||||
get; private set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the serial number.
|
||||
/// </summary>
|
||||
public string Serial { get; private set; }
|
||||
public String Serial {
|
||||
get; private set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the system uptime (in seconds).
|
||||
/// </summary>
|
||||
public double Uptime
|
||||
{
|
||||
get
|
||||
{
|
||||
try
|
||||
{
|
||||
if (File.Exists(UptimeFilePath) == false) return 0;
|
||||
var parts = File.ReadAllText(UptimeFilePath).Trim().Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
if (parts.Length >= 1 && float.TryParse(parts[0], out var result))
|
||||
public Double Uptime {
|
||||
get {
|
||||
try {
|
||||
if(File.Exists(UptimeFilePath) == false) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
String[] parts = File.ReadAllText(UptimeFilePath).Trim().Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
if(parts.Length >= 1 && Single.TryParse(parts[0], out Single result)) {
|
||||
return result;
|
||||
}
|
||||
catch
|
||||
{
|
||||
} catch {
|
||||
/* Ignore */
|
||||
}
|
||||
|
||||
@ -294,51 +296,48 @@
|
||||
/// <summary>
|
||||
/// Gets the uptime in TimeSpan.
|
||||
/// </summary>
|
||||
public TimeSpan UptimeTimeSpan => TimeSpan.FromSeconds(Uptime);
|
||||
public TimeSpan UptimeTimeSpan => TimeSpan.FromSeconds(this.Uptime);
|
||||
|
||||
/// <summary>
|
||||
/// Placeholder for processor index
|
||||
/// </summary>
|
||||
private string Processor { get; set; }
|
||||
private String Processor {
|
||||
get; set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a <see cref="string" /> that represents this instance.
|
||||
/// Returns a <see cref="String" /> that represents this instance.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A <see cref="string" /> that represents this instance.
|
||||
/// A <see cref="String" /> that represents this instance.
|
||||
/// </returns>
|
||||
public override string ToString()
|
||||
{
|
||||
var properties = typeof(SystemInfo).GetTypeInfo().GetProperties(BindingFlags.Instance | BindingFlags.Public)
|
||||
public override String ToString() {
|
||||
PropertyInfo[] properties = typeof(SystemInfo).GetTypeInfo().GetProperties(BindingFlags.Instance | BindingFlags.Public)
|
||||
.Where(p => p.CanRead && (
|
||||
p.PropertyType == typeof(string) ||
|
||||
p.PropertyType == typeof(string[]) ||
|
||||
p.PropertyType == typeof(int) ||
|
||||
p.PropertyType == typeof(bool) ||
|
||||
p.PropertyType == typeof(String) ||
|
||||
p.PropertyType == typeof(String[]) ||
|
||||
p.PropertyType == typeof(Int32) ||
|
||||
p.PropertyType == typeof(Boolean) ||
|
||||
p.PropertyType == typeof(TimeSpan)))
|
||||
.ToArray();
|
||||
|
||||
var properyValues = new List<string>
|
||||
List<String> properyValues = new List<String>
|
||||
{
|
||||
"System Information",
|
||||
$"\t{nameof(WiringPiVersion),-22}: {WiringPiVersion}",
|
||||
$"\t{nameof(RaspberryPiVersion),-22}: {RaspberryPiVersion}"
|
||||
$"\t{nameof(this.WiringPiVersion),-22}: {this.WiringPiVersion}",
|
||||
$"\t{nameof(this.RaspberryPiVersion),-22}: {this.RaspberryPiVersion}"
|
||||
};
|
||||
|
||||
foreach (var property in properties)
|
||||
{
|
||||
if (property.PropertyType != typeof(string[]))
|
||||
{
|
||||
foreach(PropertyInfo property in properties) {
|
||||
if(property.PropertyType != typeof(String[])) {
|
||||
properyValues.Add($"\t{property.Name,-22}: {property.GetValue(this)}");
|
||||
}
|
||||
else if (property.GetValue(this) is string[] allValues)
|
||||
{
|
||||
var concatValues = string.Join(" ", allValues);
|
||||
} else if(property.GetValue(this) is String[] allValues) {
|
||||
String concatValues = String.Join(" ", allValues);
|
||||
properyValues.Add($"\t{property.Name,-22}: {concatValues}");
|
||||
}
|
||||
}
|
||||
|
||||
return string.Join(Environment.NewLine, properyValues.ToArray());
|
||||
return String.Join(Environment.NewLine, properyValues.ToArray());
|
||||
}
|
||||
}
|
||||
}
|
@ -1,23 +1,29 @@
|
||||
namespace Unosquare.RaspberryIO.Computer
|
||||
{
|
||||
using System;
|
||||
|
||||
namespace Unosquare.RaspberryIO.Computer {
|
||||
/// <summary>
|
||||
/// Represents a wireless network information
|
||||
/// </summary>
|
||||
public class WirelessNetworkInfo
|
||||
{
|
||||
public class WirelessNetworkInfo {
|
||||
/// <summary>
|
||||
/// Gets the ESSID of the Wireless network.
|
||||
/// </summary>
|
||||
public string Name { get; internal set; }
|
||||
public String Name {
|
||||
get; internal set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the network quality.
|
||||
/// </summary>
|
||||
public string Quality { get; internal set; }
|
||||
public String Quality {
|
||||
get; internal set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this instance is encrypted.
|
||||
/// </summary>
|
||||
public bool IsEncrypted { get; internal set; }
|
||||
public Boolean IsEncrypted {
|
||||
get; internal set;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,8 @@
|
||||
namespace Unosquare.RaspberryIO.Gpio
|
||||
{
|
||||
namespace Unosquare.RaspberryIO.Gpio {
|
||||
/// <summary>
|
||||
/// Defines the different drive modes of a GPIO pin
|
||||
/// </summary>
|
||||
public enum GpioPinDriveMode
|
||||
{
|
||||
public enum GpioPinDriveMode {
|
||||
/// <summary>
|
||||
/// Input drive mode (perform reads)
|
||||
/// </summary>
|
||||
@ -30,8 +28,7 @@
|
||||
/// The GPIO pin resistor mode. This is used on input pins so that their
|
||||
/// lines are not floating
|
||||
/// </summary>
|
||||
public enum GpioPinResistorPullMode
|
||||
{
|
||||
public enum GpioPinResistorPullMode {
|
||||
/// <summary>
|
||||
/// Pull resistor not active. Line floating
|
||||
/// </summary>
|
||||
@ -51,8 +48,7 @@
|
||||
/// <summary>
|
||||
/// The PWM mode.
|
||||
/// </summary>
|
||||
public enum PwmMode
|
||||
{
|
||||
public enum PwmMode {
|
||||
/// <summary>
|
||||
/// PWM pulses are sent using mark-sign patterns (old school)
|
||||
/// </summary>
|
||||
@ -67,8 +63,7 @@
|
||||
/// <summary>
|
||||
/// Defines the different edge detection modes for pin interrupts
|
||||
/// </summary>
|
||||
public enum EdgeDetection
|
||||
{
|
||||
public enum EdgeDetection {
|
||||
/// <summary>
|
||||
/// Assumes edge detection was already setup externally
|
||||
/// </summary>
|
||||
@ -93,8 +88,7 @@
|
||||
/// <summary>
|
||||
/// Defines the GPIO Pin values 0 for low, 1 for High
|
||||
/// </summary>
|
||||
public enum GpioPinValue
|
||||
{
|
||||
public enum GpioPinValue {
|
||||
/// <summary>
|
||||
/// Digital high
|
||||
/// </summary>
|
||||
@ -109,8 +103,7 @@
|
||||
/// <summary>
|
||||
/// Defines the Header connectors available
|
||||
/// </summary>
|
||||
public enum GpioHeader
|
||||
{
|
||||
public enum GpioHeader {
|
||||
/// <summary>
|
||||
/// Not defined
|
||||
/// </summary>
|
||||
@ -130,8 +123,7 @@
|
||||
/// <summary>
|
||||
/// Defines all the available Wiring Pi Pin Numbers
|
||||
/// </summary>
|
||||
public enum WiringPiPin
|
||||
{
|
||||
public enum WiringPiPin {
|
||||
/// <summary>
|
||||
/// The unknown
|
||||
/// </summary>
|
||||
@ -303,8 +295,7 @@
|
||||
/// as commonly referenced by Raspberry Pi Documentation.
|
||||
/// Enumeration values correspond to the physical pin number.
|
||||
/// </summary>
|
||||
public enum P1
|
||||
{
|
||||
public enum P1 {
|
||||
/// <summary>
|
||||
/// Header P1, GPIO Pin 02
|
||||
/// </summary>
|
||||
@ -441,8 +432,7 @@
|
||||
/// as commonly referenced by Raspberry Pi documentation.
|
||||
/// Enumeration values correspond to the physical pin number.
|
||||
/// </summary>
|
||||
public enum P5
|
||||
{
|
||||
public enum P5 {
|
||||
/// <summary>
|
||||
/// Header P5, GPIO Pin 28
|
||||
/// </summary>
|
||||
@ -467,8 +457,7 @@
|
||||
/// <summary>
|
||||
/// Defines the different pin capabilities
|
||||
/// </summary>
|
||||
public enum PinCapability
|
||||
{
|
||||
public enum PinCapability {
|
||||
/// <summary>
|
||||
/// General Purpose capability: Digital and Analog Read/Write
|
||||
/// </summary>
|
||||
@ -533,8 +522,7 @@
|
||||
/// <summary>
|
||||
/// Defines the SPI channel numbers
|
||||
/// </summary>
|
||||
internal enum SpiChannelNumber
|
||||
{
|
||||
internal enum SpiChannelNumber {
|
||||
/// <summary>
|
||||
/// The channel 0
|
||||
/// </summary>
|
||||
@ -549,8 +537,7 @@
|
||||
/// <summary>
|
||||
/// Defines GPIO controller initialization modes
|
||||
/// </summary>
|
||||
internal enum ControllerMode
|
||||
{
|
||||
internal enum ControllerMode {
|
||||
/// <summary>
|
||||
/// The not initialized
|
||||
/// </summary>
|
||||
|
@ -1,8 +1,6 @@
|
||||
namespace Unosquare.RaspberryIO.Gpio
|
||||
{
|
||||
using Native;
|
||||
using Swan;
|
||||
using Swan.Abstractions;
|
||||
using Unosquare.RaspberryIO.Native;
|
||||
using Unosquare.Swan;
|
||||
using Unosquare.Swan.Abstractions;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
@ -10,21 +8,18 @@
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Unosquare.RaspberryIO.Gpio {
|
||||
/// <summary>
|
||||
/// Represents a singleton of the Raspberry Pi GPIO controller
|
||||
/// as an IReadOnlyCollection of GpioPins
|
||||
/// Low level operations are accomplished by using the Wiring Pi library.
|
||||
/// Use the Instance property to access the singleton's instance
|
||||
/// </summary>
|
||||
public sealed class GpioController : SingletonBase<GpioController>, IReadOnlyCollection<GpioPin>
|
||||
{
|
||||
public sealed class GpioController : SingletonBase<GpioController>, IReadOnlyCollection<GpioPin> {
|
||||
#region Private Declarations
|
||||
|
||||
private const string WiringPiCodesEnvironmentVariable = "WIRINGPI_CODES";
|
||||
private static readonly object SyncRoot = new object();
|
||||
private readonly ReadOnlyCollection<GpioPin> _pinCollection;
|
||||
private readonly ReadOnlyDictionary<int, GpioPin> _headerP1Pins;
|
||||
private readonly ReadOnlyDictionary<int, GpioPin> _headerP5Pins;
|
||||
private const String WiringPiCodesEnvironmentVariable = "WIRINGPI_CODES";
|
||||
private static readonly Object SyncRoot = new Object();
|
||||
private readonly Dictionary<WiringPiPin, GpioPin> _pinsByWiringPiPinNumber = new Dictionary<WiringPiPin, GpioPin>();
|
||||
|
||||
#endregion
|
||||
@ -36,66 +31,65 @@
|
||||
/// It in turn initializes the controller and registers the pin -- in that order.
|
||||
/// </summary>
|
||||
/// <exception cref="Exception">Unable to initialize the GPIO controller.</exception>
|
||||
private GpioController()
|
||||
{
|
||||
if (_pinCollection != null)
|
||||
private GpioController() {
|
||||
if(this.Pins != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (IsInitialized == false)
|
||||
{
|
||||
var initResult = Initialize(ControllerMode.DirectWithWiringPiPins);
|
||||
if (initResult == false)
|
||||
if(IsInitialized == false) {
|
||||
Boolean initResult = this.Initialize(ControllerMode.DirectWithWiringPiPins);
|
||||
if(initResult == false) {
|
||||
throw new Exception("Unable to initialize the GPIO controller.");
|
||||
}
|
||||
}
|
||||
|
||||
#region Pin Registration (32 WiringPi Pins)
|
||||
|
||||
RegisterPin(GpioPin.Pin00.Value);
|
||||
RegisterPin(GpioPin.Pin01.Value);
|
||||
RegisterPin(GpioPin.Pin02.Value);
|
||||
RegisterPin(GpioPin.Pin03.Value);
|
||||
RegisterPin(GpioPin.Pin04.Value);
|
||||
RegisterPin(GpioPin.Pin05.Value);
|
||||
RegisterPin(GpioPin.Pin06.Value);
|
||||
RegisterPin(GpioPin.Pin07.Value);
|
||||
RegisterPin(GpioPin.Pin08.Value);
|
||||
RegisterPin(GpioPin.Pin09.Value);
|
||||
RegisterPin(GpioPin.Pin10.Value);
|
||||
RegisterPin(GpioPin.Pin11.Value);
|
||||
RegisterPin(GpioPin.Pin12.Value);
|
||||
RegisterPin(GpioPin.Pin13.Value);
|
||||
RegisterPin(GpioPin.Pin14.Value);
|
||||
RegisterPin(GpioPin.Pin15.Value);
|
||||
RegisterPin(GpioPin.Pin16.Value);
|
||||
RegisterPin(GpioPin.Pin17.Value);
|
||||
RegisterPin(GpioPin.Pin18.Value);
|
||||
RegisterPin(GpioPin.Pin19.Value);
|
||||
RegisterPin(GpioPin.Pin20.Value);
|
||||
RegisterPin(GpioPin.Pin21.Value);
|
||||
RegisterPin(GpioPin.Pin22.Value);
|
||||
RegisterPin(GpioPin.Pin23.Value);
|
||||
RegisterPin(GpioPin.Pin24.Value);
|
||||
RegisterPin(GpioPin.Pin25.Value);
|
||||
RegisterPin(GpioPin.Pin26.Value);
|
||||
RegisterPin(GpioPin.Pin27.Value);
|
||||
RegisterPin(GpioPin.Pin28.Value);
|
||||
RegisterPin(GpioPin.Pin29.Value);
|
||||
RegisterPin(GpioPin.Pin30.Value);
|
||||
RegisterPin(GpioPin.Pin31.Value);
|
||||
this.RegisterPin(GpioPin.Pin00.Value);
|
||||
this.RegisterPin(GpioPin.Pin01.Value);
|
||||
this.RegisterPin(GpioPin.Pin02.Value);
|
||||
this.RegisterPin(GpioPin.Pin03.Value);
|
||||
this.RegisterPin(GpioPin.Pin04.Value);
|
||||
this.RegisterPin(GpioPin.Pin05.Value);
|
||||
this.RegisterPin(GpioPin.Pin06.Value);
|
||||
this.RegisterPin(GpioPin.Pin07.Value);
|
||||
this.RegisterPin(GpioPin.Pin08.Value);
|
||||
this.RegisterPin(GpioPin.Pin09.Value);
|
||||
this.RegisterPin(GpioPin.Pin10.Value);
|
||||
this.RegisterPin(GpioPin.Pin11.Value);
|
||||
this.RegisterPin(GpioPin.Pin12.Value);
|
||||
this.RegisterPin(GpioPin.Pin13.Value);
|
||||
this.RegisterPin(GpioPin.Pin14.Value);
|
||||
this.RegisterPin(GpioPin.Pin15.Value);
|
||||
this.RegisterPin(GpioPin.Pin16.Value);
|
||||
this.RegisterPin(GpioPin.Pin17.Value);
|
||||
this.RegisterPin(GpioPin.Pin18.Value);
|
||||
this.RegisterPin(GpioPin.Pin19.Value);
|
||||
this.RegisterPin(GpioPin.Pin20.Value);
|
||||
this.RegisterPin(GpioPin.Pin21.Value);
|
||||
this.RegisterPin(GpioPin.Pin22.Value);
|
||||
this.RegisterPin(GpioPin.Pin23.Value);
|
||||
this.RegisterPin(GpioPin.Pin24.Value);
|
||||
this.RegisterPin(GpioPin.Pin25.Value);
|
||||
this.RegisterPin(GpioPin.Pin26.Value);
|
||||
this.RegisterPin(GpioPin.Pin27.Value);
|
||||
this.RegisterPin(GpioPin.Pin28.Value);
|
||||
this.RegisterPin(GpioPin.Pin29.Value);
|
||||
this.RegisterPin(GpioPin.Pin30.Value);
|
||||
this.RegisterPin(GpioPin.Pin31.Value);
|
||||
|
||||
#endregion
|
||||
|
||||
_pinCollection = new ReadOnlyCollection<GpioPin>(_pinsByWiringPiPinNumber.Values.ToArray());
|
||||
var headerP1 = new Dictionary<int, GpioPin>(_pinCollection.Count);
|
||||
var headerP5 = new Dictionary<int, GpioPin>(_pinCollection.Count);
|
||||
foreach (var pin in _pinCollection)
|
||||
{
|
||||
var target = pin.Header == GpioHeader.P1 ? headerP1 : headerP5;
|
||||
this.Pins = new ReadOnlyCollection<GpioPin>(this._pinsByWiringPiPinNumber.Values.ToArray());
|
||||
Dictionary<Int32, GpioPin> headerP1 = new Dictionary<Int32, GpioPin>(this.Pins.Count);
|
||||
Dictionary<Int32, GpioPin> headerP5 = new Dictionary<Int32, GpioPin>(this.Pins.Count);
|
||||
foreach(GpioPin pin in this.Pins) {
|
||||
Dictionary<Int32, GpioPin> target = pin.Header == GpioHeader.P1 ? headerP1 : headerP5;
|
||||
target[pin.HeaderPinNumber] = pin;
|
||||
}
|
||||
|
||||
_headerP1Pins = new ReadOnlyDictionary<int, GpioPin>(headerP1);
|
||||
_headerP5Pins = new ReadOnlyDictionary<int, GpioPin>(headerP5);
|
||||
this.HeaderP1 = new ReadOnlyDictionary<Int32, GpioPin>(headerP1);
|
||||
this.HeaderP5 = new ReadOnlyDictionary<Int32, GpioPin>(headerP5);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -104,12 +98,9 @@
|
||||
/// <value>
|
||||
/// <c>true</c> if the controller is properly initialized; otherwise, <c>false</c>.
|
||||
/// </value>
|
||||
public static bool IsInitialized
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (SyncRoot)
|
||||
{
|
||||
public static Boolean IsInitialized {
|
||||
get {
|
||||
lock(SyncRoot) {
|
||||
return Mode != ControllerMode.NotInitialized;
|
||||
}
|
||||
}
|
||||
@ -118,7 +109,7 @@
|
||||
/// <summary>
|
||||
/// Gets the number of registered pins in the controller.
|
||||
/// </summary>
|
||||
public int Count => _pinCollection.Count;
|
||||
public Int32 Count => this.Pins.Count;
|
||||
|
||||
#endregion
|
||||
|
||||
@ -127,24 +118,30 @@
|
||||
/// <summary>
|
||||
/// Gets the PWM base frequency (in Hz).
|
||||
/// </summary>
|
||||
public int PwmBaseFrequency => 19200000;
|
||||
public Int32 PwmBaseFrequency => 19200000;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a red-only collection of all registered pins.
|
||||
/// </summary>
|
||||
public ReadOnlyCollection<GpioPin> Pins => _pinCollection;
|
||||
public ReadOnlyCollection<GpioPin> Pins {
|
||||
get;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provides all the pins on Header P1 of the Pi as a lookup by physical header pin number.
|
||||
/// This header is the main header and it is the one commonly used.
|
||||
/// </summary>
|
||||
public ReadOnlyDictionary<int, GpioPin> HeaderP1 => _headerP1Pins;
|
||||
public ReadOnlyDictionary<Int32, GpioPin> HeaderP1 {
|
||||
get;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provides all the pins on Header P5 of the Pi as a lookup by physical header pin number.
|
||||
/// This header is the secondary header and it is rarely used.
|
||||
/// </summary>
|
||||
public ReadOnlyDictionary<int, GpioPin> HeaderP5 => _headerP5Pins;
|
||||
public ReadOnlyDictionary<Int32, GpioPin> HeaderP5 {
|
||||
get;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@ -327,7 +324,7 @@
|
||||
/// </value>
|
||||
/// <param name="pinNumber">The pin number.</param>
|
||||
/// <returns>A reference to the GPIO pin</returns>
|
||||
public GpioPin this[WiringPiPin pinNumber] => _pinsByWiringPiPinNumber[pinNumber];
|
||||
public GpioPin this[WiringPiPin pinNumber] => this._pinsByWiringPiPinNumber[pinNumber];
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="GpioPin"/> with the specified pin number.
|
||||
@ -337,7 +334,7 @@
|
||||
/// </value>
|
||||
/// <param name="pinNumber">The pin number.</param>
|
||||
/// <returns>A reference to the GPIO pin</returns>
|
||||
public GpioPin this[P1 pinNumber] => HeaderP1[(int)pinNumber];
|
||||
public GpioPin this[P1 pinNumber] => this.HeaderP1[(Int32)pinNumber];
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="GpioPin"/> with the specified pin number.
|
||||
@ -347,7 +344,7 @@
|
||||
/// </value>
|
||||
/// <param name="pinNumber">The pin number.</param>
|
||||
/// <returns>A reference to the GPIO pin</returns>
|
||||
public GpioPin this[P5 pinNumber] => HeaderP5[(int)pinNumber];
|
||||
public GpioPin this[P5 pinNumber] => this.HeaderP5[(Int32)pinNumber];
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="GpioPin"/> with the specified Wiring Pi pin number.
|
||||
@ -359,14 +356,13 @@
|
||||
/// <param name="wiringPiPinNumber">The pin number as defined by Wiring Pi. This is not the header pin number as pin number in headers are obvoisly repeating.</param>
|
||||
/// <returns>A reference to the GPIO pin</returns>
|
||||
/// <exception cref="IndexOutOfRangeException">When the pin index is not found</exception>
|
||||
public GpioPin this[int wiringPiPinNumber]
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Enum.IsDefined(typeof(WiringPiPin), wiringPiPinNumber) == false)
|
||||
public GpioPin this[Int32 wiringPiPinNumber] {
|
||||
get {
|
||||
if(Enum.IsDefined(typeof(WiringPiPin), wiringPiPinNumber) == false) {
|
||||
throw new IndexOutOfRangeException($"Pin {wiringPiPinNumber} is not registered in the GPIO controller.");
|
||||
}
|
||||
|
||||
return _pinsByWiringPiPinNumber[(WiringPiPin)wiringPiPinNumber];
|
||||
return this._pinsByWiringPiPinNumber[(WiringPiPin)wiringPiPinNumber];
|
||||
}
|
||||
}
|
||||
|
||||
@ -381,11 +377,9 @@
|
||||
/// </summary>
|
||||
/// <param name="group">The group.</param>
|
||||
/// <param name="value">The value.</param>
|
||||
public void SetPadDrive(int group, int value)
|
||||
{
|
||||
lock (SyncRoot)
|
||||
{
|
||||
WiringPi.SetPadDrive(group, value);
|
||||
public void SetPadDrive(Int32 group, Int32 value) {
|
||||
lock(SyncRoot) {
|
||||
_ = WiringPi.SetPadDrive(group, value);
|
||||
}
|
||||
}
|
||||
|
||||
@ -397,7 +391,7 @@
|
||||
/// <param name="group">The group.</param>
|
||||
/// <param name="value">The value.</param>
|
||||
/// <returns>The awaitable task</returns>
|
||||
public Task SetPadDriveAsync(int group, int value) => Task.Run(() => { SetPadDrive(group, value); });
|
||||
public Task SetPadDriveAsync(Int32 group, Int32 value) => Task.Run(() => this.SetPadDrive(group, value));
|
||||
|
||||
/// <summary>
|
||||
/// This writes the 8-bit byte supplied to the first 8 GPIO pins.
|
||||
@ -406,12 +400,9 @@
|
||||
/// </summary>
|
||||
/// <param name="value">The value.</param>
|
||||
/// <exception cref="InvalidOperationException">PinMode</exception>
|
||||
public void WriteByte(byte value)
|
||||
{
|
||||
lock (SyncRoot)
|
||||
{
|
||||
if (this.Skip(0).Take(8).Any(p => p.PinMode != GpioPinDriveMode.Output))
|
||||
{
|
||||
public void WriteByte(Byte value) {
|
||||
lock(SyncRoot) {
|
||||
if(this.Skip(0).Take(8).Any(p => p.PinMode != GpioPinDriveMode.Output)) {
|
||||
throw new InvalidOperationException(
|
||||
$"All firts 8 pins (0 to 7) need their {nameof(GpioPin.PinMode)} to be set to {GpioPinDriveMode.Output}");
|
||||
}
|
||||
@ -427,7 +418,7 @@
|
||||
/// </summary>
|
||||
/// <param name="value">The value.</param>
|
||||
/// <returns>The awaitable task</returns>
|
||||
public Task WriteByteAsync(byte value) => Task.Run(() => { WriteByte(value); });
|
||||
public Task WriteByteAsync(Byte value) => Task.Run(() => this.WriteByte(value));
|
||||
|
||||
/// <summary>
|
||||
/// This reads the 8-bit byte supplied to the first 8 GPIO pins.
|
||||
@ -436,18 +427,15 @@
|
||||
/// </summary>
|
||||
/// <returns>A byte from the GPIO</returns>
|
||||
/// <exception cref="InvalidOperationException">PinMode</exception>
|
||||
public byte ReadByte()
|
||||
{
|
||||
lock (SyncRoot)
|
||||
{
|
||||
public Byte ReadByte() {
|
||||
lock(SyncRoot) {
|
||||
if(this.Skip(0).Take(8).Any(p =>
|
||||
p.PinMode != GpioPinDriveMode.Input && p.PinMode != GpioPinDriveMode.Output))
|
||||
{
|
||||
p.PinMode != GpioPinDriveMode.Input && p.PinMode != GpioPinDriveMode.Output)) {
|
||||
throw new InvalidOperationException(
|
||||
$"All firts 8 pins (0 to 7) need their {nameof(GpioPin.PinMode)} to be set to {GpioPinDriveMode.Input} or {GpioPinDriveMode.Output}");
|
||||
}
|
||||
|
||||
return (byte)WiringPi.DigitalReadByte();
|
||||
return (Byte)WiringPi.DigitalReadByte();
|
||||
}
|
||||
}
|
||||
|
||||
@ -457,7 +445,7 @@
|
||||
/// Please note this function is undocumented and unsopported
|
||||
/// </summary>
|
||||
/// <returns>A byte from the GPIO</returns>
|
||||
public Task<byte> ReadByteAsync() => Task.Run(() => ReadByte());
|
||||
public Task<Byte> ReadByteAsync() => Task.Run(() => this.ReadByte());
|
||||
|
||||
#endregion
|
||||
|
||||
@ -469,7 +457,7 @@
|
||||
/// <returns>
|
||||
/// A <see cref="T:System.Collections.Generic.IEnumerator`1" /> that can be used to iterate through the collection.
|
||||
/// </returns>
|
||||
public IEnumerator<GpioPin> GetEnumerator() => _pinCollection.GetEnumerator();
|
||||
public IEnumerator<GpioPin> GetEnumerator() => this.Pins.GetEnumerator();
|
||||
|
||||
/// <summary>
|
||||
/// Returns an enumerator that iterates through the collection.
|
||||
@ -477,7 +465,7 @@
|
||||
/// <returns>
|
||||
/// An <see cref="T:System.Collections.IEnumerator" /> object that can be used to iterate through the collection.
|
||||
/// </returns>
|
||||
IEnumerator IEnumerable.GetEnumerator() => _pinCollection.GetEnumerator();
|
||||
IEnumerator IEnumerable.GetEnumerator() => this.Pins.GetEnumerator();
|
||||
|
||||
#endregion
|
||||
|
||||
@ -488,17 +476,15 @@
|
||||
/// </summary>
|
||||
/// <param name="bcmPinNumber">The BCM pin number.</param>
|
||||
/// <returns>The GPIO pin</returns>
|
||||
public GpioPin GetGpioPinByBcmPinNumber(int bcmPinNumber) => this.First(pin => pin.BcmPinNumber == bcmPinNumber);
|
||||
public GpioPin GetGpioPinByBcmPinNumber(Int32 bcmPinNumber) => this.First(pin => pin.BcmPinNumber == bcmPinNumber);
|
||||
|
||||
/// <summary>
|
||||
/// Converts the Wirings Pi pin number to the BCM pin number.
|
||||
/// </summary>
|
||||
/// <param name="wiringPiPinNumber">The wiring pi pin number.</param>
|
||||
/// <returns>The converted pin</returns>
|
||||
internal static int WiringPiToBcmPinNumber(int wiringPiPinNumber)
|
||||
{
|
||||
lock (SyncRoot)
|
||||
{
|
||||
internal static Int32 WiringPiToBcmPinNumber(Int32 wiringPiPinNumber) {
|
||||
lock(SyncRoot) {
|
||||
return WiringPi.WpiPinToGpio(wiringPiPinNumber);
|
||||
}
|
||||
}
|
||||
@ -508,10 +494,8 @@
|
||||
/// </summary>
|
||||
/// <param name="headerPinNumber">The header pin number.</param>
|
||||
/// <returns>The converted pin</returns>
|
||||
internal static int HaderToBcmPinNumber(int headerPinNumber)
|
||||
{
|
||||
lock (SyncRoot)
|
||||
{
|
||||
internal static Int32 HaderToBcmPinNumber(Int32 headerPinNumber) {
|
||||
lock(SyncRoot) {
|
||||
return WiringPi.PhysPinToGpio(headerPinNumber);
|
||||
}
|
||||
}
|
||||
@ -520,13 +504,13 @@
|
||||
/// Short-hand method of registering pins
|
||||
/// </summary>
|
||||
/// <param name="pin">The pin.</param>
|
||||
private void RegisterPin(GpioPin pin)
|
||||
{
|
||||
if (_pinsByWiringPiPinNumber.ContainsKey(pin.WiringPiPinNumber) == false)
|
||||
_pinsByWiringPiPinNumber[pin.WiringPiPinNumber] = pin;
|
||||
else
|
||||
private void RegisterPin(GpioPin pin) {
|
||||
if(this._pinsByWiringPiPinNumber.ContainsKey(pin.WiringPiPinNumber) == false) {
|
||||
this._pinsByWiringPiPinNumber[pin.WiringPiPinNumber] = pin;
|
||||
} else {
|
||||
throw new InvalidOperationException($"Pin {pin.WiringPiPinNumber} has been registered");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the controller given the initialization mode and pin numbering scheme
|
||||
@ -538,47 +522,41 @@
|
||||
/// </exception>
|
||||
/// <exception cref="InvalidOperationException">Library was already Initialized</exception>
|
||||
/// <exception cref="ArgumentException">The init mode is invalid</exception>
|
||||
private bool Initialize(ControllerMode mode)
|
||||
{
|
||||
if (Runtime.OS != Swan.OperatingSystem.Unix)
|
||||
private Boolean Initialize(ControllerMode mode) {
|
||||
if(Runtime.OS != Swan.OperatingSystem.Unix) {
|
||||
throw new PlatformNotSupportedException("This library does not support the platform");
|
||||
}
|
||||
|
||||
lock (SyncRoot)
|
||||
{
|
||||
if (IsInitialized)
|
||||
lock(SyncRoot) {
|
||||
if(IsInitialized) {
|
||||
throw new InvalidOperationException($"Cannot call {nameof(Initialize)} more than once.");
|
||||
}
|
||||
|
||||
Environment.SetEnvironmentVariable(WiringPiCodesEnvironmentVariable, "1", EnvironmentVariableTarget.Process);
|
||||
int setpuResult;
|
||||
Int32 setpuResult;
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case ControllerMode.DirectWithWiringPiPins:
|
||||
{
|
||||
switch(mode) {
|
||||
case ControllerMode.DirectWithWiringPiPins: {
|
||||
setpuResult = WiringPi.WiringPiSetup();
|
||||
break;
|
||||
}
|
||||
|
||||
case ControllerMode.DirectWithBcmPins:
|
||||
{
|
||||
case ControllerMode.DirectWithBcmPins: {
|
||||
setpuResult = WiringPi.WiringPiSetupGpio();
|
||||
break;
|
||||
}
|
||||
|
||||
case ControllerMode.DirectWithHeaderPins:
|
||||
{
|
||||
case ControllerMode.DirectWithHeaderPins: {
|
||||
setpuResult = WiringPi.WiringPiSetupPhys();
|
||||
break;
|
||||
}
|
||||
|
||||
case ControllerMode.FileStreamWithHardwarePins:
|
||||
{
|
||||
case ControllerMode.FileStreamWithHardwarePins: {
|
||||
setpuResult = WiringPi.WiringPiSetupSys();
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
default: {
|
||||
throw new ArgumentException($"'{mode}' is not a valid initialization mode.");
|
||||
}
|
||||
}
|
||||
|
@ -1,197 +1,163 @@
|
||||
namespace Unosquare.RaspberryIO.Gpio
|
||||
{
|
||||
using System;
|
||||
using System;
|
||||
|
||||
public partial class GpioPin
|
||||
{
|
||||
namespace Unosquare.RaspberryIO.Gpio {
|
||||
public partial class GpioPin {
|
||||
#region Static Pin Definitions
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin08 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin08, 3)
|
||||
{
|
||||
internal static readonly Lazy<GpioPin> Pin08 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin08, 3) {
|
||||
Capabilities = new[] { PinCapability.GP, PinCapability.I2CSDA },
|
||||
Name = "BCM 2 (SDA)"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin09 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin09, 5)
|
||||
{
|
||||
internal static readonly Lazy<GpioPin> Pin09 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin09, 5) {
|
||||
Capabilities = new[] { PinCapability.GP, PinCapability.I2CSCL },
|
||||
Name = "BCM 3 (SCL)"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin07 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin07, 7)
|
||||
{
|
||||
internal static readonly Lazy<GpioPin> Pin07 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin07, 7) {
|
||||
Capabilities = new[] { PinCapability.GP, PinCapability.GPCLK },
|
||||
Name = "BCM 4 (GPCLK0)"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin00 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin00, 11)
|
||||
{
|
||||
internal static readonly Lazy<GpioPin> Pin00 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin00, 11) {
|
||||
Capabilities = new[] { PinCapability.GP, PinCapability.UARTRTS },
|
||||
Name = "BCM 17"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin02 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin02, 13)
|
||||
{
|
||||
internal static readonly Lazy<GpioPin> Pin02 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin02, 13) {
|
||||
Capabilities = new[] { PinCapability.GP },
|
||||
Name = "BCM 27"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin03 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin03, 15)
|
||||
{
|
||||
internal static readonly Lazy<GpioPin> Pin03 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin03, 15) {
|
||||
Capabilities = new[] { PinCapability.GP },
|
||||
Name = "BCM 22"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin12 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin12, 19)
|
||||
{
|
||||
internal static readonly Lazy<GpioPin> Pin12 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin12, 19) {
|
||||
Capabilities = new[] { PinCapability.GP, PinCapability.SPIMOSI },
|
||||
Name = "BCM 10 (MOSI)"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin13 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin13, 21)
|
||||
{
|
||||
internal static readonly Lazy<GpioPin> Pin13 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin13, 21) {
|
||||
Capabilities = new[] { PinCapability.GP, PinCapability.SPIMISO },
|
||||
Name = "BCM 9 (MISO)"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin14 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin14, 23)
|
||||
{
|
||||
internal static readonly Lazy<GpioPin> Pin14 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin14, 23) {
|
||||
Capabilities = new[] { PinCapability.GP, PinCapability.SPICLK },
|
||||
Name = "BCM 11 (SCLCK)"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin30 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin30, 27)
|
||||
{
|
||||
internal static readonly Lazy<GpioPin> Pin30 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin30, 27) {
|
||||
Capabilities = new[] { PinCapability.I2CSDA },
|
||||
Name = "BCM 0 (ID_SD)"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin31 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin31, 28)
|
||||
{
|
||||
internal static readonly Lazy<GpioPin> Pin31 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin31, 28) {
|
||||
Capabilities = new[] { PinCapability.I2CSCL },
|
||||
Name = "BCM 1 (ID_SC)"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin11 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin11, 26)
|
||||
{
|
||||
internal static readonly Lazy<GpioPin> Pin11 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin11, 26) {
|
||||
Capabilities = new[] { PinCapability.GP, PinCapability.SPICS },
|
||||
Name = "BCM 7 (CE1)"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin10 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin10, 24)
|
||||
{
|
||||
internal static readonly Lazy<GpioPin> Pin10 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin10, 24) {
|
||||
Capabilities = new[] { PinCapability.GP, PinCapability.SPICS },
|
||||
Name = "BCM 8 (CE0)"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin06 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin06, 22)
|
||||
{
|
||||
internal static readonly Lazy<GpioPin> Pin06 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin06, 22) {
|
||||
Capabilities = new[] { PinCapability.GP },
|
||||
Name = "BCM 25"
|
||||
});
|
||||
internal static readonly Lazy<GpioPin> Pin05 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin05, 18)
|
||||
{
|
||||
internal static readonly Lazy<GpioPin> Pin05 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin05, 18) {
|
||||
Capabilities = new[] { PinCapability.GP },
|
||||
Name = "BCM 24"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin04 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin04, 16)
|
||||
{
|
||||
internal static readonly Lazy<GpioPin> Pin04 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin04, 16) {
|
||||
Capabilities = new[] { PinCapability.GP },
|
||||
Name = "BCM 23"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin01 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin01, 12)
|
||||
{
|
||||
internal static readonly Lazy<GpioPin> Pin01 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin01, 12) {
|
||||
Capabilities = new[] { PinCapability.GP, PinCapability.PWM },
|
||||
Name = "BCM 18 (PWM0)"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin16 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin16, 10)
|
||||
{
|
||||
internal static readonly Lazy<GpioPin> Pin16 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin16, 10) {
|
||||
Capabilities = new[] { PinCapability.UARTRXD },
|
||||
Name = "BCM 15 (RXD)"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin15 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin15, 8)
|
||||
{
|
||||
internal static readonly Lazy<GpioPin> Pin15 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin15, 8) {
|
||||
Capabilities = new[] { PinCapability.UARTTXD },
|
||||
Name = "BCM 14 (TXD)"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin21 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin21, 29)
|
||||
{
|
||||
internal static readonly Lazy<GpioPin> Pin21 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin21, 29) {
|
||||
Capabilities = new[] { PinCapability.GP },
|
||||
Name = "BCM 5"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin22 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin22, 31)
|
||||
{
|
||||
internal static readonly Lazy<GpioPin> Pin22 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin22, 31) {
|
||||
Capabilities = new[] { PinCapability.GP },
|
||||
Name = "BCM 6"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin23 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin23, 33)
|
||||
{
|
||||
internal static readonly Lazy<GpioPin> Pin23 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin23, 33) {
|
||||
Capabilities = new[] { PinCapability.GP, PinCapability.PWM },
|
||||
Name = "BCM 13 (PWM1)"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin24 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin24, 35)
|
||||
{
|
||||
internal static readonly Lazy<GpioPin> Pin24 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin24, 35) {
|
||||
Capabilities = new[] { PinCapability.GP, PinCapability.SPIMISO },
|
||||
Name = "BCM 19 (MISO)"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin25 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin25, 37)
|
||||
{
|
||||
internal static readonly Lazy<GpioPin> Pin25 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin25, 37) {
|
||||
Capabilities = new[] { PinCapability.GP },
|
||||
Name = "BCM 26"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin29 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin29, 40)
|
||||
{
|
||||
internal static readonly Lazy<GpioPin> Pin29 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin29, 40) {
|
||||
Capabilities = new[] { PinCapability.GP, PinCapability.SPICLK },
|
||||
Name = "BCM 21 (SCLK)"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin28 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin28, 38)
|
||||
{
|
||||
internal static readonly Lazy<GpioPin> Pin28 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin28, 38) {
|
||||
Capabilities = new[] { PinCapability.GP, PinCapability.SPIMOSI },
|
||||
Name = "BCM 20 (MOSI)"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin27 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin27, 36)
|
||||
{
|
||||
internal static readonly Lazy<GpioPin> Pin27 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin27, 36) {
|
||||
Capabilities = new[] { PinCapability.GP },
|
||||
Name = "BCM 16"
|
||||
});
|
||||
internal static readonly Lazy<GpioPin> Pin26 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin26, 32)
|
||||
{
|
||||
internal static readonly Lazy<GpioPin> Pin26 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin26, 32) {
|
||||
Capabilities = new[] { PinCapability.GP },
|
||||
Name = "BCM 12 (PWM0)"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin17 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin17, 3)
|
||||
{
|
||||
internal static readonly Lazy<GpioPin> Pin17 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin17, 3) {
|
||||
Capabilities = new[] { PinCapability.GP, PinCapability.I2CSDA },
|
||||
Name = "BCM 28 (SDA)"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin18 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin18, 4)
|
||||
{
|
||||
internal static readonly Lazy<GpioPin> Pin18 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin18, 4) {
|
||||
Capabilities = new[] { PinCapability.GP, PinCapability.I2CSCL },
|
||||
Name = "BCM 29 (SCL)"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin19 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin19, 5)
|
||||
{
|
||||
internal static readonly Lazy<GpioPin> Pin19 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin19, 5) {
|
||||
Capabilities = new[] { PinCapability.GP },
|
||||
Name = "BCM 30"
|
||||
});
|
||||
|
||||
internal static readonly Lazy<GpioPin> Pin20 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin20, 6)
|
||||
{
|
||||
internal static readonly Lazy<GpioPin> Pin20 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin20, 6) {
|
||||
Capabilities = new[] { PinCapability.GP },
|
||||
Name = "BCM 31"
|
||||
});
|
||||
|
@ -1,29 +1,27 @@
|
||||
namespace Unosquare.RaspberryIO.Gpio
|
||||
{
|
||||
using Native;
|
||||
using Swan;
|
||||
using Unosquare.RaspberryIO.Native;
|
||||
using Unosquare.Swan;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Unosquare.RaspberryIO.Gpio {
|
||||
/// <summary>
|
||||
/// Represents a GPIO Pin, its location and its capabilities.
|
||||
/// Full pin reference available here:
|
||||
/// http://pinout.xyz/pinout/pin31_gpio6 and http://wiringpi.com/pins/
|
||||
/// </summary>
|
||||
public sealed partial class GpioPin
|
||||
{
|
||||
public sealed partial class GpioPin {
|
||||
#region Property Backing
|
||||
|
||||
private readonly object _syncLock = new object();
|
||||
private readonly Object _syncLock = new Object();
|
||||
private GpioPinDriveMode m_PinMode;
|
||||
private GpioPinResistorPullMode m_ResistorPullMode;
|
||||
private int m_PwmRegister;
|
||||
private Int32 m_PwmRegister;
|
||||
private PwmMode m_PwmMode = PwmMode.Balanced;
|
||||
private uint m_PwmRange = 1024;
|
||||
private int m_PwmClockDivisor = 1;
|
||||
private int m_SoftPwmValue = -1;
|
||||
private int m_SoftToneFrequency = -1;
|
||||
private UInt32 m_PwmRange = 1024;
|
||||
private Int32 m_PwmClockDivisor = 1;
|
||||
private Int32 m_SoftPwmValue = -1;
|
||||
private Int32 m_SoftToneFrequency = -1;
|
||||
|
||||
#endregion
|
||||
|
||||
@ -34,13 +32,12 @@
|
||||
/// </summary>
|
||||
/// <param name="wiringPiPinNumber">The wiring pi pin number.</param>
|
||||
/// <param name="headerPinNumber">The header pin number.</param>
|
||||
private GpioPin(WiringPiPin wiringPiPinNumber, int headerPinNumber)
|
||||
{
|
||||
PinNumber = (int)wiringPiPinNumber;
|
||||
WiringPiPinNumber = wiringPiPinNumber;
|
||||
BcmPinNumber = GpioController.WiringPiToBcmPinNumber((int)wiringPiPinNumber);
|
||||
HeaderPinNumber = headerPinNumber;
|
||||
Header = (PinNumber >= 17 && PinNumber <= 20) ? GpioHeader.P5 : GpioHeader.P1;
|
||||
private GpioPin(WiringPiPin wiringPiPinNumber, Int32 headerPinNumber) {
|
||||
this.PinNumber = (Int32)wiringPiPinNumber;
|
||||
this.WiringPiPinNumber = wiringPiPinNumber;
|
||||
this.BcmPinNumber = GpioController.WiringPiToBcmPinNumber((Int32)wiringPiPinNumber);
|
||||
this.HeaderPinNumber = headerPinNumber;
|
||||
this.Header = (this.PinNumber >= 17 && this.PinNumber <= 20) ? GpioHeader.P5 : GpioHeader.P1;
|
||||
}
|
||||
|
||||
#endregion
|
||||
@ -50,37 +47,51 @@
|
||||
/// <summary>
|
||||
/// Gets or sets the Wiring Pi pin number as an integer.
|
||||
/// </summary>
|
||||
public int PinNumber { get; }
|
||||
public Int32 PinNumber {
|
||||
get;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the WiringPi Pin number
|
||||
/// </summary>
|
||||
public WiringPiPin WiringPiPinNumber { get; }
|
||||
public WiringPiPin WiringPiPinNumber {
|
||||
get;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the BCM chip (hardware) pin number.
|
||||
/// </summary>
|
||||
public int BcmPinNumber { get; }
|
||||
public Int32 BcmPinNumber {
|
||||
get;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or the physical header (physical board) pin number.
|
||||
/// </summary>
|
||||
public int HeaderPinNumber { get; }
|
||||
public Int32 HeaderPinNumber {
|
||||
get;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the pin's header (physical board) location.
|
||||
/// </summary>
|
||||
public GpioHeader Header { get; }
|
||||
public GpioHeader Header {
|
||||
get;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the friendly name of the pin.
|
||||
/// </summary>
|
||||
public string Name { get; private set; }
|
||||
public String Name {
|
||||
get; private set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the hardware mode capabilities of this pin.
|
||||
/// </summary>
|
||||
public PinCapability[] Capabilities { get; private set; }
|
||||
public PinCapability[] Capabilities {
|
||||
get; private set;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@ -93,26 +104,22 @@
|
||||
/// The pin mode.
|
||||
/// </value>
|
||||
/// <exception cref="NotSupportedException">Thrown when a pin does not support the given operation mode.</exception>
|
||||
public GpioPinDriveMode PinMode
|
||||
{
|
||||
get => m_PinMode;
|
||||
public GpioPinDriveMode PinMode {
|
||||
get => this.m_PinMode;
|
||||
|
||||
set
|
||||
{
|
||||
lock (_syncLock)
|
||||
{
|
||||
var mode = value;
|
||||
if ((mode == GpioPinDriveMode.GpioClock && Capabilities.Contains(PinCapability.GPCLK) == false) ||
|
||||
(mode == GpioPinDriveMode.PwmOutput && Capabilities.Contains(PinCapability.PWM) == false) ||
|
||||
(mode == GpioPinDriveMode.Input && Capabilities.Contains(PinCapability.GP) == false) ||
|
||||
(mode == GpioPinDriveMode.Output && Capabilities.Contains(PinCapability.GP) == false))
|
||||
{
|
||||
set {
|
||||
lock(this._syncLock) {
|
||||
GpioPinDriveMode mode = value;
|
||||
if(mode == GpioPinDriveMode.GpioClock && this.Capabilities.Contains(PinCapability.GPCLK) == false ||
|
||||
mode == GpioPinDriveMode.PwmOutput && this.Capabilities.Contains(PinCapability.PWM) == false ||
|
||||
mode == GpioPinDriveMode.Input && this.Capabilities.Contains(PinCapability.GP) == false ||
|
||||
mode == GpioPinDriveMode.Output && this.Capabilities.Contains(PinCapability.GP) == false) {
|
||||
throw new NotSupportedException(
|
||||
$"Pin {WiringPiPinNumber} '{Name}' does not support mode '{mode}'. Pin capabilities are limited to: {string.Join(", ", Capabilities)}");
|
||||
$"Pin {this.WiringPiPinNumber} '{this.Name}' does not support mode '{mode}'. Pin capabilities are limited to: {String.Join(", ", this.Capabilities)}");
|
||||
}
|
||||
|
||||
WiringPi.PinMode(PinNumber, (int)mode);
|
||||
m_PinMode = mode;
|
||||
WiringPi.PinMode(this.PinNumber, (Int32)mode);
|
||||
this.m_PinMode = mode;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -121,7 +128,9 @@
|
||||
/// Gets the interrupt callback. Returns null if no interrupt
|
||||
/// has been registered.
|
||||
/// </summary>
|
||||
public InterruptServiceRoutineCallback InterruptCallback { get; private set; }
|
||||
public InterruptServiceRoutineCallback InterruptCallback {
|
||||
get; private set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the interrupt edge detection mode.
|
||||
@ -138,24 +147,20 @@
|
||||
/// The parameter pud should be; PUD_OFF, (no pull up/down), PUD_DOWN (pull to ground) or PUD_UP (pull to 3.3v)
|
||||
/// The internal pull up/down resistors have a value of approximately 50KΩ on the Raspberry Pi.
|
||||
/// </summary>
|
||||
public GpioPinResistorPullMode InputPullMode
|
||||
{
|
||||
get => PinMode == GpioPinDriveMode.Input ? m_ResistorPullMode : GpioPinResistorPullMode.Off;
|
||||
public GpioPinResistorPullMode InputPullMode {
|
||||
get => this.PinMode == GpioPinDriveMode.Input ? this.m_ResistorPullMode : GpioPinResistorPullMode.Off;
|
||||
|
||||
set
|
||||
{
|
||||
lock (_syncLock)
|
||||
{
|
||||
if (PinMode != GpioPinDriveMode.Input)
|
||||
{
|
||||
m_ResistorPullMode = GpioPinResistorPullMode.Off;
|
||||
set {
|
||||
lock(this._syncLock) {
|
||||
if(this.PinMode != GpioPinDriveMode.Input) {
|
||||
this.m_ResistorPullMode = GpioPinResistorPullMode.Off;
|
||||
throw new InvalidOperationException(
|
||||
$"Unable to set the {nameof(InputPullMode)} for pin {PinNumber} because operating mode is {PinMode}."
|
||||
+ $" Setting the {nameof(InputPullMode)} is only allowed if {nameof(PinMode)} is set to {GpioPinDriveMode.Input}");
|
||||
$"Unable to set the {nameof(this.InputPullMode)} for pin {this.PinNumber} because operating mode is {this.PinMode}."
|
||||
+ $" Setting the {nameof(this.InputPullMode)} is only allowed if {nameof(this.PinMode)} is set to {GpioPinDriveMode.Input}");
|
||||
}
|
||||
|
||||
WiringPi.PullUpDnControl(PinNumber, (int)value);
|
||||
m_ResistorPullMode = value;
|
||||
WiringPi.PullUpDnControl(this.PinNumber, (Int32)value);
|
||||
this.m_ResistorPullMode = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -166,27 +171,23 @@
|
||||
/// <value>
|
||||
/// The PWM register.
|
||||
/// </value>
|
||||
public int PwmRegister
|
||||
{
|
||||
get => m_PwmRegister;
|
||||
public Int32 PwmRegister {
|
||||
get => this.m_PwmRegister;
|
||||
|
||||
set
|
||||
{
|
||||
lock (_syncLock)
|
||||
{
|
||||
if (PinMode != GpioPinDriveMode.PwmOutput)
|
||||
{
|
||||
m_PwmRegister = 0;
|
||||
set {
|
||||
lock(this._syncLock) {
|
||||
if(this.PinMode != GpioPinDriveMode.PwmOutput) {
|
||||
this.m_PwmRegister = 0;
|
||||
|
||||
throw new InvalidOperationException(
|
||||
$"Unable to write PWM register for pin {PinNumber} because operating mode is {PinMode}."
|
||||
+ $" Writing the PWM register is only allowed if {nameof(PinMode)} is set to {GpioPinDriveMode.PwmOutput}");
|
||||
$"Unable to write PWM register for pin {this.PinNumber} because operating mode is {this.PinMode}."
|
||||
+ $" Writing the PWM register is only allowed if {nameof(this.PinMode)} is set to {GpioPinDriveMode.PwmOutput}");
|
||||
}
|
||||
|
||||
var val = value.Clamp(0, 1024);
|
||||
Int32 val = value.Clamp(0, 1024);
|
||||
|
||||
WiringPi.PwmWrite(PinNumber, val);
|
||||
m_PwmRegister = val;
|
||||
WiringPi.PwmWrite(this.PinNumber, val);
|
||||
this.m_PwmRegister = val;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -199,25 +200,21 @@
|
||||
/// The PWM mode.
|
||||
/// </value>
|
||||
/// <exception cref="InvalidOperationException">When pin mode is not set a Pwn output</exception>
|
||||
public PwmMode PwmMode
|
||||
{
|
||||
get => PinMode == GpioPinDriveMode.PwmOutput ? m_PwmMode : PwmMode.Balanced;
|
||||
public PwmMode PwmMode {
|
||||
get => this.PinMode == GpioPinDriveMode.PwmOutput ? this.m_PwmMode : PwmMode.Balanced;
|
||||
|
||||
set
|
||||
{
|
||||
lock (_syncLock)
|
||||
{
|
||||
if (PinMode != GpioPinDriveMode.PwmOutput)
|
||||
{
|
||||
m_PwmMode = PwmMode.Balanced;
|
||||
set {
|
||||
lock(this._syncLock) {
|
||||
if(this.PinMode != GpioPinDriveMode.PwmOutput) {
|
||||
this.m_PwmMode = PwmMode.Balanced;
|
||||
|
||||
throw new InvalidOperationException(
|
||||
$"Unable to set PWM mode for pin {PinNumber} because operating mode is {PinMode}."
|
||||
+ $" Setting the PWM mode is only allowed if {nameof(PinMode)} is set to {GpioPinDriveMode.PwmOutput}");
|
||||
$"Unable to set PWM mode for pin {this.PinNumber} because operating mode is {this.PinMode}."
|
||||
+ $" Setting the PWM mode is only allowed if {nameof(this.PinMode)} is set to {GpioPinDriveMode.PwmOutput}");
|
||||
}
|
||||
|
||||
WiringPi.PwmSetMode((int)value);
|
||||
m_PwmMode = value;
|
||||
WiringPi.PwmSetMode((Int32)value);
|
||||
this.m_PwmMode = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -229,25 +226,21 @@
|
||||
/// The PWM range.
|
||||
/// </value>
|
||||
/// <exception cref="InvalidOperationException">When pin mode is not set to PWM output</exception>
|
||||
public uint PwmRange
|
||||
{
|
||||
get => PinMode == GpioPinDriveMode.PwmOutput ? m_PwmRange : 0;
|
||||
public UInt32 PwmRange {
|
||||
get => this.PinMode == GpioPinDriveMode.PwmOutput ? this.m_PwmRange : 0;
|
||||
|
||||
set
|
||||
{
|
||||
lock (_syncLock)
|
||||
{
|
||||
if (PinMode != GpioPinDriveMode.PwmOutput)
|
||||
{
|
||||
m_PwmRange = 1024;
|
||||
set {
|
||||
lock(this._syncLock) {
|
||||
if(this.PinMode != GpioPinDriveMode.PwmOutput) {
|
||||
this.m_PwmRange = 1024;
|
||||
|
||||
throw new InvalidOperationException(
|
||||
$"Unable to set PWM range for pin {PinNumber} because operating mode is {PinMode}."
|
||||
+ $" Setting the PWM range is only allowed if {nameof(PinMode)} is set to {GpioPinDriveMode.PwmOutput}");
|
||||
$"Unable to set PWM range for pin {this.PinNumber} because operating mode is {this.PinMode}."
|
||||
+ $" Setting the PWM range is only allowed if {nameof(this.PinMode)} is set to {GpioPinDriveMode.PwmOutput}");
|
||||
}
|
||||
|
||||
WiringPi.PwmSetRange(value);
|
||||
m_PwmRange = value;
|
||||
this.m_PwmRange = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -259,25 +252,21 @@
|
||||
/// The PWM clock divisor.
|
||||
/// </value>
|
||||
/// <exception cref="InvalidOperationException">When pin mode is not set to PWM output</exception>
|
||||
public int PwmClockDivisor
|
||||
{
|
||||
get => PinMode == GpioPinDriveMode.PwmOutput ? m_PwmClockDivisor : 0;
|
||||
public Int32 PwmClockDivisor {
|
||||
get => this.PinMode == GpioPinDriveMode.PwmOutput ? this.m_PwmClockDivisor : 0;
|
||||
|
||||
set
|
||||
{
|
||||
lock (_syncLock)
|
||||
{
|
||||
if (PinMode != GpioPinDriveMode.PwmOutput)
|
||||
{
|
||||
m_PwmClockDivisor = 1;
|
||||
set {
|
||||
lock(this._syncLock) {
|
||||
if(this.PinMode != GpioPinDriveMode.PwmOutput) {
|
||||
this.m_PwmClockDivisor = 1;
|
||||
|
||||
throw new InvalidOperationException(
|
||||
$"Unable to set PWM range for pin {PinNumber} because operating mode is {PinMode}."
|
||||
+ $" Setting the PWM range is only allowed if {nameof(PinMode)} is set to {GpioPinDriveMode.PwmOutput}");
|
||||
$"Unable to set PWM range for pin {this.PinNumber} because operating mode is {this.PinMode}."
|
||||
+ $" Setting the PWM range is only allowed if {nameof(this.PinMode)} is set to {GpioPinDriveMode.PwmOutput}");
|
||||
}
|
||||
|
||||
WiringPi.PwmSetClock(value);
|
||||
m_PwmClockDivisor = value;
|
||||
this.m_PwmClockDivisor = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -292,7 +281,7 @@
|
||||
/// <value>
|
||||
/// <c>true</c> if this instance is in soft tone mode; otherwise, <c>false</c>.
|
||||
/// </value>
|
||||
public bool IsInSoftToneMode => m_SoftToneFrequency >= 0;
|
||||
public Boolean IsInSoftToneMode => this.m_SoftToneFrequency >= 0;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the soft tone frequency. 0 to 5000 Hz is typical
|
||||
@ -301,26 +290,21 @@
|
||||
/// The soft tone frequency.
|
||||
/// </value>
|
||||
/// <exception cref="InvalidOperationException">When soft tones cannot be initialized on the pin</exception>
|
||||
public int SoftToneFrequency
|
||||
{
|
||||
get => m_SoftToneFrequency;
|
||||
public Int32 SoftToneFrequency {
|
||||
get => this.m_SoftToneFrequency;
|
||||
|
||||
set
|
||||
{
|
||||
lock (_syncLock)
|
||||
{
|
||||
if (IsInSoftToneMode == false)
|
||||
{
|
||||
var setupResult = WiringPi.SoftToneCreate(PinNumber);
|
||||
if (setupResult != 0)
|
||||
{
|
||||
set {
|
||||
lock(this._syncLock) {
|
||||
if(this.IsInSoftToneMode == false) {
|
||||
Int32 setupResult = WiringPi.SoftToneCreate(this.PinNumber);
|
||||
if(setupResult != 0) {
|
||||
throw new InvalidOperationException(
|
||||
$"Unable to initialize soft tone on pin {PinNumber}. Error Code: {setupResult}");
|
||||
$"Unable to initialize soft tone on pin {this.PinNumber}. Error Code: {setupResult}");
|
||||
}
|
||||
}
|
||||
|
||||
WiringPi.SoftToneWrite(PinNumber, value);
|
||||
m_SoftToneFrequency = value;
|
||||
WiringPi.SoftToneWrite(this.PinNumber, value);
|
||||
this.m_SoftToneFrequency = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -335,7 +319,7 @@
|
||||
/// <value>
|
||||
/// <c>true</c> if this instance is in soft PWM mode; otherwise, <c>false</c>.
|
||||
/// </value>
|
||||
public bool IsInSoftPwmMode => m_SoftPwmValue >= 0;
|
||||
public Boolean IsInSoftPwmMode => this.m_SoftPwmValue >= 0;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the software PWM value on the pin.
|
||||
@ -344,21 +328,15 @@
|
||||
/// The soft PWM value.
|
||||
/// </value>
|
||||
/// <exception cref="InvalidOperationException">StartSoftPwm</exception>
|
||||
public int SoftPwmValue
|
||||
{
|
||||
get => m_SoftPwmValue;
|
||||
public Int32 SoftPwmValue {
|
||||
get => this.m_SoftPwmValue;
|
||||
|
||||
set
|
||||
{
|
||||
lock (_syncLock)
|
||||
{
|
||||
if (IsInSoftPwmMode && value >= 0)
|
||||
{
|
||||
WiringPi.SoftPwmWrite(PinNumber, value);
|
||||
m_SoftPwmValue = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
set {
|
||||
lock(this._syncLock) {
|
||||
if(this.IsInSoftPwmMode && value >= 0) {
|
||||
WiringPi.SoftPwmWrite(this.PinNumber, value);
|
||||
this.m_SoftPwmValue = value;
|
||||
} else {
|
||||
throw new InvalidOperationException($"Software PWM requires a call to {nameof(StartSoftPwm)}.");
|
||||
}
|
||||
}
|
||||
@ -368,7 +346,7 @@
|
||||
/// <summary>
|
||||
/// Gets the software PWM range used upon starting the PWM.
|
||||
/// </summary>
|
||||
public int SoftPwmRange { get; private set; } = -1;
|
||||
public Int32 SoftPwmRange { get; private set; } = -1;
|
||||
|
||||
/// <summary>
|
||||
/// Starts the software based PWM on this pin.
|
||||
@ -378,27 +356,24 @@
|
||||
/// <exception cref="NotSupportedException">When the pin does not suppoert PWM</exception>
|
||||
/// <exception cref="InvalidOperationException">StartSoftPwm
|
||||
/// or</exception>
|
||||
public void StartSoftPwm(int value, int range)
|
||||
{
|
||||
lock (_syncLock)
|
||||
{
|
||||
if (Capabilities.Contains(PinCapability.GP) == false)
|
||||
throw new NotSupportedException($"Pin {PinNumber} does not support software PWM");
|
||||
|
||||
if (IsInSoftPwmMode)
|
||||
throw new InvalidOperationException($"{nameof(StartSoftPwm)} has already been called.");
|
||||
|
||||
var startResult = WiringPi.SoftPwmCreate(PinNumber, value, range);
|
||||
|
||||
if (startResult == 0)
|
||||
{
|
||||
m_SoftPwmValue = value;
|
||||
SoftPwmRange = range;
|
||||
public void StartSoftPwm(Int32 value, Int32 range) {
|
||||
lock(this._syncLock) {
|
||||
if(this.Capabilities.Contains(PinCapability.GP) == false) {
|
||||
throw new NotSupportedException($"Pin {this.PinNumber} does not support software PWM");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
if(this.IsInSoftPwmMode) {
|
||||
throw new InvalidOperationException($"{nameof(StartSoftPwm)} has already been called.");
|
||||
}
|
||||
|
||||
Int32 startResult = WiringPi.SoftPwmCreate(this.PinNumber, value, range);
|
||||
|
||||
if(startResult == 0) {
|
||||
this.m_SoftPwmValue = value;
|
||||
this.SoftPwmRange = range;
|
||||
} else {
|
||||
throw new InvalidOperationException(
|
||||
$"Could not start software based PWM on pin {PinNumber}. Error code: {startResult}");
|
||||
$"Could not start software based PWM on pin {this.PinNumber}. Error code: {startResult}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -412,18 +387,15 @@
|
||||
/// This method performs a digital write
|
||||
/// </summary>
|
||||
/// <param name="value">The value.</param>
|
||||
public void Write(GpioPinValue value)
|
||||
{
|
||||
lock (_syncLock)
|
||||
{
|
||||
if (PinMode != GpioPinDriveMode.Output)
|
||||
{
|
||||
public void Write(GpioPinValue value) {
|
||||
lock(this._syncLock) {
|
||||
if(this.PinMode != GpioPinDriveMode.Output) {
|
||||
throw new InvalidOperationException(
|
||||
$"Unable to write to pin {PinNumber} because operating mode is {PinMode}."
|
||||
+ $" Writes are only allowed if {nameof(PinMode)} is set to {GpioPinDriveMode.Output}");
|
||||
$"Unable to write to pin {this.PinNumber} because operating mode is {this.PinMode}."
|
||||
+ $" Writes are only allowed if {nameof(this.PinMode)} is set to {GpioPinDriveMode.Output}");
|
||||
}
|
||||
|
||||
WiringPi.DigitalWrite(PinNumber, (int)value);
|
||||
WiringPi.DigitalWrite(this.PinNumber, (Int32)value);
|
||||
}
|
||||
}
|
||||
|
||||
@ -432,15 +404,15 @@
|
||||
/// </summary>
|
||||
/// <param name="value">The value.</param>
|
||||
/// <returns>The awaitable task</returns>
|
||||
public Task WriteAsync(GpioPinValue value) => Task.Run(() => { Write(value); });
|
||||
public Task WriteAsync(GpioPinValue value) => Task.Run(() => this.Write(value));
|
||||
|
||||
/// <summary>
|
||||
/// Writes the specified bit value.
|
||||
/// This method performs a digital write
|
||||
/// </summary>
|
||||
/// <param name="value">if set to <c>true</c> [value].</param>
|
||||
public void Write(bool value)
|
||||
=> Write(value ? GpioPinValue.High : GpioPinValue.Low);
|
||||
public void Write(Boolean value)
|
||||
=> this.Write(value ? GpioPinValue.High : GpioPinValue.Low);
|
||||
|
||||
/// <summary>
|
||||
/// Writes the specified bit value.
|
||||
@ -450,14 +422,14 @@
|
||||
/// <returns>
|
||||
/// The awaitable task
|
||||
/// </returns>
|
||||
public Task WriteAsync(bool value) => Task.Run(() => { Write(value); });
|
||||
public Task WriteAsync(Boolean value) => Task.Run(() => this.Write(value));
|
||||
|
||||
/// <summary>
|
||||
/// Writes the specified value. 0 for low, any other value for high
|
||||
/// This method performs a digital write
|
||||
/// </summary>
|
||||
/// <param name="value">The value.</param>
|
||||
public void Write(int value) => Write(value != 0 ? GpioPinValue.High : GpioPinValue.Low);
|
||||
public void Write(Int32 value) => this.Write(value != 0 ? GpioPinValue.High : GpioPinValue.Low);
|
||||
|
||||
/// <summary>
|
||||
/// Writes the specified value. 0 for low, any other value for high
|
||||
@ -465,25 +437,22 @@
|
||||
/// </summary>
|
||||
/// <param name="value">The value.</param>
|
||||
/// <returns>The awaitable task</returns>
|
||||
public Task WriteAsync(int value) => Task.Run(() => { Write(value); });
|
||||
public Task WriteAsync(Int32 value) => Task.Run(() => this.Write(value));
|
||||
|
||||
/// <summary>
|
||||
/// Writes the specified value as an analog level.
|
||||
/// You will need to register additional analog modules to enable this function for devices such as the Gertboard.
|
||||
/// </summary>
|
||||
/// <param name="value">The value.</param>
|
||||
public void WriteLevel(int value)
|
||||
{
|
||||
lock (_syncLock)
|
||||
{
|
||||
if (PinMode != GpioPinDriveMode.Output)
|
||||
{
|
||||
public void WriteLevel(Int32 value) {
|
||||
lock(this._syncLock) {
|
||||
if(this.PinMode != GpioPinDriveMode.Output) {
|
||||
throw new InvalidOperationException(
|
||||
$"Unable to write to pin {PinNumber} because operating mode is {PinMode}."
|
||||
+ $" Writes are only allowed if {nameof(PinMode)} is set to {GpioPinDriveMode.Output}");
|
||||
$"Unable to write to pin {this.PinNumber} because operating mode is {this.PinMode}."
|
||||
+ $" Writes are only allowed if {nameof(this.PinMode)} is set to {GpioPinDriveMode.Output}");
|
||||
}
|
||||
|
||||
WiringPi.AnalogWrite(PinNumber, value);
|
||||
WiringPi.AnalogWrite(this.PinNumber, value);
|
||||
}
|
||||
}
|
||||
|
||||
@ -493,7 +462,7 @@
|
||||
/// </summary>
|
||||
/// <param name="value">The value.</param>
|
||||
/// <returns>The awaitable task</returns>
|
||||
public Task WriteLevelAsync(int value) => Task.Run(() => { WriteLevel(value); });
|
||||
public Task WriteLevelAsync(Int32 value) => Task.Run(() => this.WriteLevel(value));
|
||||
|
||||
#endregion
|
||||
|
||||
@ -505,21 +474,19 @@
|
||||
/// <param name="status">status to check</param>
|
||||
/// <param name="timeOutMillisecond">timeout to reach status</param>
|
||||
/// <returns>true/false</returns>
|
||||
public bool WaitForValue(GpioPinValue status, int timeOutMillisecond)
|
||||
{
|
||||
if (PinMode != GpioPinDriveMode.Input)
|
||||
{
|
||||
public Boolean WaitForValue(GpioPinValue status, Int32 timeOutMillisecond) {
|
||||
if(this.PinMode != GpioPinDriveMode.Input) {
|
||||
throw new InvalidOperationException(
|
||||
$"Unable to read from pin {PinNumber} because operating mode is {PinMode}."
|
||||
+ $" Reads are only allowed if {nameof(PinMode)} is set to {GpioPinDriveMode.Input}");
|
||||
$"Unable to read from pin {this.PinNumber} because operating mode is {this.PinMode}."
|
||||
+ $" Reads are only allowed if {nameof(this.PinMode)} is set to {GpioPinDriveMode.Input}");
|
||||
}
|
||||
|
||||
var hrt = new HighResolutionTimer();
|
||||
HighResolutionTimer hrt = new HighResolutionTimer();
|
||||
hrt.Start();
|
||||
do
|
||||
{
|
||||
if (ReadValue() == status)
|
||||
do {
|
||||
if(this.ReadValue() == status) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Pi.Timing.SleepMicroseconds(101); // 101 uses nanosleep as opposed to a loop.
|
||||
}
|
||||
@ -532,18 +499,15 @@
|
||||
/// Reads the digital value on the pin as a boolean value.
|
||||
/// </summary>
|
||||
/// <returns>The state of the pin</returns>
|
||||
public bool Read()
|
||||
{
|
||||
lock (_syncLock)
|
||||
{
|
||||
if (PinMode != GpioPinDriveMode.Input && PinMode != GpioPinDriveMode.Output)
|
||||
{
|
||||
public Boolean Read() {
|
||||
lock(this._syncLock) {
|
||||
if(this.PinMode != GpioPinDriveMode.Input && this.PinMode != GpioPinDriveMode.Output) {
|
||||
throw new InvalidOperationException(
|
||||
$"Unable to read from pin {PinNumber} because operating mode is {PinMode}."
|
||||
+ $" Reads are only allowed if {nameof(PinMode)} is set to {GpioPinDriveMode.Input} or {GpioPinDriveMode.Output}");
|
||||
$"Unable to read from pin {this.PinNumber} because operating mode is {this.PinMode}."
|
||||
+ $" Reads are only allowed if {nameof(this.PinMode)} is set to {GpioPinDriveMode.Input} or {GpioPinDriveMode.Output}");
|
||||
}
|
||||
|
||||
return WiringPi.DigitalRead(PinNumber) != 0;
|
||||
return WiringPi.DigitalRead(this.PinNumber) != 0;
|
||||
}
|
||||
}
|
||||
|
||||
@ -551,20 +515,20 @@
|
||||
/// Reads the digital value on the pin as a boolean value.
|
||||
/// </summary>
|
||||
/// <returns>The state of the pin</returns>
|
||||
public Task<bool> ReadAsync() => Task.Run(() => Read());
|
||||
public Task<Boolean> ReadAsync() => Task.Run(() => this.Read());
|
||||
|
||||
/// <summary>
|
||||
/// Reads the digital value on the pin as a High or Low value.
|
||||
/// </summary>
|
||||
/// <returns>The state of the pin</returns>
|
||||
public GpioPinValue ReadValue()
|
||||
=> Read() ? GpioPinValue.High : GpioPinValue.Low;
|
||||
=> this.Read() ? GpioPinValue.High : GpioPinValue.Low;
|
||||
|
||||
/// <summary>
|
||||
/// Reads the digital value on the pin as a High or Low value.
|
||||
/// </summary>
|
||||
/// <returns>The state of the pin</returns>
|
||||
public Task<GpioPinValue> ReadValueAsync() => Task.Run(() => ReadValue());
|
||||
public Task<GpioPinValue> ReadValueAsync() => Task.Run(() => this.ReadValue());
|
||||
|
||||
/// <summary>
|
||||
/// Reads the analog value on the pin.
|
||||
@ -574,18 +538,15 @@
|
||||
/// </summary>
|
||||
/// <returns>The analog level</returns>
|
||||
/// <exception cref="InvalidOperationException">When the pin mode is not configured as an input.</exception>
|
||||
public int ReadLevel()
|
||||
{
|
||||
lock (_syncLock)
|
||||
{
|
||||
if (PinMode != GpioPinDriveMode.Input)
|
||||
{
|
||||
public Int32 ReadLevel() {
|
||||
lock(this._syncLock) {
|
||||
if(this.PinMode != GpioPinDriveMode.Input) {
|
||||
throw new InvalidOperationException(
|
||||
$"Unable to read from pin {PinNumber} because operating mode is {PinMode}."
|
||||
+ $" Reads are only allowed if {nameof(PinMode)} is set to {GpioPinDriveMode.Input}");
|
||||
$"Unable to read from pin {this.PinNumber} because operating mode is {this.PinMode}."
|
||||
+ $" Reads are only allowed if {nameof(this.PinMode)} is set to {GpioPinDriveMode.Input}");
|
||||
}
|
||||
|
||||
return WiringPi.AnalogRead(PinNumber);
|
||||
return WiringPi.AnalogRead(this.PinNumber);
|
||||
}
|
||||
}
|
||||
|
||||
@ -596,7 +557,7 @@
|
||||
/// quick2Wire analog board, etc.
|
||||
/// </summary>
|
||||
/// <returns>The analog level</returns>
|
||||
public Task<int> ReadLevelAsync() => Task.Run(() => ReadLevel());
|
||||
public Task<Int32> ReadLevelAsync() => Task.Run(() => this.ReadLevel());
|
||||
|
||||
#endregion
|
||||
|
||||
@ -613,31 +574,27 @@
|
||||
/// or
|
||||
/// RegisterInterruptCallback
|
||||
/// </exception>
|
||||
public void RegisterInterruptCallback(EdgeDetection edgeDetection, InterruptServiceRoutineCallback callback)
|
||||
{
|
||||
if (callback == null)
|
||||
public void RegisterInterruptCallback(EdgeDetection edgeDetection, InterruptServiceRoutineCallback callback) {
|
||||
if(callback == null) {
|
||||
throw new ArgumentException($"{nameof(callback)} cannot be null");
|
||||
}
|
||||
|
||||
if (InterruptCallback != null)
|
||||
if(this.InterruptCallback != null) {
|
||||
throw new InvalidOperationException("An interrupt callback was already registered.");
|
||||
}
|
||||
|
||||
if (PinMode != GpioPinDriveMode.Input)
|
||||
{
|
||||
if(this.PinMode != GpioPinDriveMode.Input) {
|
||||
throw new InvalidOperationException(
|
||||
$"Unable to {nameof(RegisterInterruptCallback)} for pin {PinNumber} because operating mode is {PinMode}."
|
||||
+ $" Calling {nameof(RegisterInterruptCallback)} is only allowed if {nameof(PinMode)} is set to {GpioPinDriveMode.Input}");
|
||||
$"Unable to {nameof(RegisterInterruptCallback)} for pin {this.PinNumber} because operating mode is {this.PinMode}."
|
||||
+ $" Calling {nameof(RegisterInterruptCallback)} is only allowed if {nameof(this.PinMode)} is set to {GpioPinDriveMode.Input}");
|
||||
}
|
||||
|
||||
lock (_syncLock)
|
||||
{
|
||||
var registerResult = WiringPi.WiringPiISR(PinNumber, (int)edgeDetection, callback);
|
||||
if (registerResult == 0)
|
||||
{
|
||||
InterruptEdgeDetection = edgeDetection;
|
||||
InterruptCallback = callback;
|
||||
}
|
||||
else
|
||||
{
|
||||
lock(this._syncLock) {
|
||||
Int32 registerResult = WiringPi.WiringPiISR(this.PinNumber, (Int32)edgeDetection, callback);
|
||||
if(registerResult == 0) {
|
||||
this.InterruptEdgeDetection = edgeDetection;
|
||||
this.InterruptCallback = callback;
|
||||
} else {
|
||||
HardwareException.Throw(nameof(GpioPin), nameof(RegisterInterruptCallback));
|
||||
}
|
||||
}
|
||||
|
@ -1,32 +1,30 @@
|
||||
namespace Unosquare.RaspberryIO.Gpio
|
||||
{
|
||||
using Native;
|
||||
using Swan.Abstractions;
|
||||
using Unosquare.RaspberryIO.Native;
|
||||
using Unosquare.Swan.Abstractions;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System;
|
||||
|
||||
namespace Unosquare.RaspberryIO.Gpio {
|
||||
/// <summary>
|
||||
/// A simple wrapper for the I2c bus on the Raspberry Pi
|
||||
/// </summary>
|
||||
public class I2CBus : SingletonBase<I2CBus>
|
||||
{
|
||||
public class I2CBus : SingletonBase<I2CBus> {
|
||||
// TODO: It would be nice to integrate i2c device detection.
|
||||
private static readonly object SyncRoot = new object();
|
||||
private readonly Dictionary<int, I2CDevice> _devices = new Dictionary<int, I2CDevice>();
|
||||
private static readonly Object SyncRoot = new Object();
|
||||
private readonly Dictionary<Int32, I2CDevice> _devices = new Dictionary<Int32, I2CDevice>();
|
||||
|
||||
/// <summary>
|
||||
/// Prevents a default instance of the <see cref="I2CBus"/> class from being created.
|
||||
/// </summary>
|
||||
private I2CBus()
|
||||
{
|
||||
private I2CBus() {
|
||||
// placeholder
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the registered devices as a read only collection.
|
||||
/// </summary>
|
||||
public ReadOnlyCollection<I2CDevice> Devices => new ReadOnlyCollection<I2CDevice>(_devices.Values.ToArray());
|
||||
public ReadOnlyCollection<I2CDevice> Devices => new ReadOnlyCollection<I2CDevice>(this._devices.Values.ToArray());
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="I2CDevice"/> with the specified device identifier.
|
||||
@ -36,18 +34,16 @@
|
||||
/// </value>
|
||||
/// <param name="deviceId">The device identifier.</param>
|
||||
/// <returns>A reference to an I2C device</returns>
|
||||
public I2CDevice this[int deviceId] => GetDeviceById(deviceId);
|
||||
public I2CDevice this[Int32 deviceId] => this.GetDeviceById(deviceId);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the device by identifier.
|
||||
/// </summary>
|
||||
/// <param name="deviceId">The device identifier.</param>
|
||||
/// <returns>The device reference</returns>
|
||||
public I2CDevice GetDeviceById(int deviceId)
|
||||
{
|
||||
lock (SyncRoot)
|
||||
{
|
||||
return _devices[deviceId];
|
||||
public I2CDevice GetDeviceById(Int32 deviceId) {
|
||||
lock(SyncRoot) {
|
||||
return this._devices[deviceId];
|
||||
}
|
||||
}
|
||||
|
||||
@ -57,19 +53,19 @@
|
||||
/// <param name="deviceId">The device identifier.</param>
|
||||
/// <returns>The device reference</returns>
|
||||
/// <exception cref="KeyNotFoundException">When the device file descriptor is not found</exception>
|
||||
public I2CDevice AddDevice(int deviceId)
|
||||
{
|
||||
lock (SyncRoot)
|
||||
{
|
||||
if (_devices.ContainsKey(deviceId))
|
||||
return _devices[deviceId];
|
||||
public I2CDevice AddDevice(Int32 deviceId) {
|
||||
lock(SyncRoot) {
|
||||
if(this._devices.ContainsKey(deviceId)) {
|
||||
return this._devices[deviceId];
|
||||
}
|
||||
|
||||
var fileDescriptor = SetupFileDescriptor(deviceId);
|
||||
if (fileDescriptor < 0)
|
||||
Int32 fileDescriptor = SetupFileDescriptor(deviceId);
|
||||
if(fileDescriptor < 0) {
|
||||
throw new KeyNotFoundException($"Device with id {deviceId} could not be registered with the I2C bus. Error Code: {fileDescriptor}.");
|
||||
}
|
||||
|
||||
var device = new I2CDevice(deviceId, fileDescriptor);
|
||||
_devices[deviceId] = device;
|
||||
I2CDevice device = new I2CDevice(deviceId, fileDescriptor);
|
||||
this._devices[deviceId] = device;
|
||||
return device;
|
||||
}
|
||||
}
|
||||
@ -82,10 +78,8 @@
|
||||
/// </summary>
|
||||
/// <param name="deviceId">The device identifier.</param>
|
||||
/// <returns>The Linux file handle</returns>
|
||||
private static int SetupFileDescriptor(int deviceId)
|
||||
{
|
||||
lock (SyncRoot)
|
||||
{
|
||||
private static Int32 SetupFileDescriptor(Int32 deviceId) {
|
||||
lock(SyncRoot) {
|
||||
return WiringPi.WiringPiI2CSetup(deviceId);
|
||||
}
|
||||
}
|
||||
|
@ -1,25 +1,22 @@
|
||||
namespace Unosquare.RaspberryIO.Gpio
|
||||
{
|
||||
using System;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Native;
|
||||
using Unosquare.RaspberryIO.Native;
|
||||
|
||||
namespace Unosquare.RaspberryIO.Gpio {
|
||||
/// <summary>
|
||||
/// Represents a device on the I2C Bus
|
||||
/// </summary>
|
||||
public class I2CDevice
|
||||
{
|
||||
private readonly object _syncLock = new object();
|
||||
public class I2CDevice {
|
||||
private readonly Object _syncLock = new Object();
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="I2CDevice"/> class.
|
||||
/// </summary>
|
||||
/// <param name="deviceId">The device identifier.</param>
|
||||
/// <param name="fileDescriptor">The file descriptor.</param>
|
||||
internal I2CDevice(int deviceId, int fileDescriptor)
|
||||
{
|
||||
DeviceId = deviceId;
|
||||
FileDescriptor = fileDescriptor;
|
||||
internal I2CDevice(Int32 deviceId, Int32 fileDescriptor) {
|
||||
this.DeviceId = deviceId;
|
||||
this.FileDescriptor = fileDescriptor;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -28,7 +25,9 @@
|
||||
/// <value>
|
||||
/// The device identifier.
|
||||
/// </value>
|
||||
public int DeviceId { get; }
|
||||
public Int32 DeviceId {
|
||||
get;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the standard POSIX file descriptor.
|
||||
@ -36,19 +35,22 @@
|
||||
/// <value>
|
||||
/// The file descriptor.
|
||||
/// </value>
|
||||
public int FileDescriptor { get; }
|
||||
public Int32 FileDescriptor {
|
||||
get;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads a byte from the specified file descriptor
|
||||
/// </summary>
|
||||
/// <returns>The byte from device</returns>
|
||||
public byte Read()
|
||||
{
|
||||
lock (_syncLock)
|
||||
{
|
||||
var result = WiringPi.WiringPiI2CRead(FileDescriptor);
|
||||
if (result < 0) HardwareException.Throw(nameof(I2CDevice), nameof(Read));
|
||||
return (byte)result;
|
||||
public Byte Read() {
|
||||
lock(this._syncLock) {
|
||||
Int32 result = WiringPi.WiringPiI2CRead(this.FileDescriptor);
|
||||
if(result < 0) {
|
||||
HardwareException.Throw(nameof(I2CDevice), nameof(Read));
|
||||
}
|
||||
|
||||
return (Byte)result;
|
||||
}
|
||||
}
|
||||
|
||||
@ -56,23 +58,23 @@
|
||||
/// Reads a byte from the specified file descriptor
|
||||
/// </summary>
|
||||
/// <returns>The byte from device</returns>
|
||||
public Task<byte> ReadAsync() => Task.Run(() => Read());
|
||||
public Task<Byte> ReadAsync() => Task.Run(() => this.Read());
|
||||
|
||||
/// <summary>
|
||||
/// Reads a buffer of the specified length, one byte at a time
|
||||
/// </summary>
|
||||
/// <param name="length">The length.</param>
|
||||
/// <returns>The byte array from device</returns>
|
||||
public byte[] Read(int length)
|
||||
{
|
||||
lock (_syncLock)
|
||||
{
|
||||
var buffer = new byte[length];
|
||||
for (var i = 0; i < length; i++)
|
||||
{
|
||||
var result = WiringPi.WiringPiI2CRead(FileDescriptor);
|
||||
if (result < 0) HardwareException.Throw(nameof(I2CDevice), nameof(Read));
|
||||
buffer[i] = (byte)result;
|
||||
public Byte[] Read(Int32 length) {
|
||||
lock(this._syncLock) {
|
||||
Byte[] buffer = new Byte[length];
|
||||
for(Int32 i = 0; i < length; i++) {
|
||||
Int32 result = WiringPi.WiringPiI2CRead(this.FileDescriptor);
|
||||
if(result < 0) {
|
||||
HardwareException.Throw(nameof(I2CDevice), nameof(Read));
|
||||
}
|
||||
|
||||
buffer[i] = (Byte)result;
|
||||
}
|
||||
|
||||
return buffer;
|
||||
@ -84,18 +86,18 @@
|
||||
/// </summary>
|
||||
/// <param name="length">The length.</param>
|
||||
/// <returns>The byte array from device</returns>
|
||||
public Task<byte[]> ReadAsync(int length) => Task.Run(() => Read(length));
|
||||
public Task<Byte[]> ReadAsync(Int32 length) => Task.Run(() => this.Read(length));
|
||||
|
||||
/// <summary>
|
||||
/// Writes a byte of data the specified file descriptor.
|
||||
/// </summary>
|
||||
/// <param name="data">The data.</param>
|
||||
public void Write(byte data)
|
||||
{
|
||||
lock (_syncLock)
|
||||
{
|
||||
var result = WiringPi.WiringPiI2CWrite(FileDescriptor, data);
|
||||
if (result < 0) HardwareException.Throw(nameof(I2CDevice), nameof(Write));
|
||||
public void Write(Byte data) {
|
||||
lock(this._syncLock) {
|
||||
Int32 result = WiringPi.WiringPiI2CWrite(this.FileDescriptor, data);
|
||||
if(result < 0) {
|
||||
HardwareException.Throw(nameof(I2CDevice), nameof(Write));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -104,20 +106,19 @@
|
||||
/// </summary>
|
||||
/// <param name="data">The data.</param>
|
||||
/// <returns>The awaitable task</returns>
|
||||
public Task WriteAsync(byte data) => Task.Run(() => { Write(data); });
|
||||
public Task WriteAsync(Byte data) => Task.Run(() => this.Write(data));
|
||||
|
||||
/// <summary>
|
||||
/// Writes a set of bytes to the specified file descriptor.
|
||||
/// </summary>
|
||||
/// <param name="data">The data.</param>
|
||||
public void Write(byte[] data)
|
||||
{
|
||||
lock (_syncLock)
|
||||
{
|
||||
foreach (var b in data)
|
||||
{
|
||||
var result = WiringPi.WiringPiI2CWrite(FileDescriptor, b);
|
||||
if (result < 0) HardwareException.Throw(nameof(I2CDevice), nameof(Write));
|
||||
public void Write(Byte[] data) {
|
||||
lock(this._syncLock) {
|
||||
foreach(Byte b in data) {
|
||||
Int32 result = WiringPi.WiringPiI2CWrite(this.FileDescriptor, b);
|
||||
if(result < 0) {
|
||||
HardwareException.Throw(nameof(I2CDevice), nameof(Write));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -127,22 +128,19 @@
|
||||
/// </summary>
|
||||
/// <param name="data">The data.</param>
|
||||
/// <returns>The awaitable task</returns>
|
||||
public Task WriteAsync(byte[] data)
|
||||
{
|
||||
return Task.Run(() => { Write(data); });
|
||||
}
|
||||
public Task WriteAsync(Byte[] data) => Task.Run(() => this.Write(data));
|
||||
|
||||
/// <summary>
|
||||
/// These write an 8 or 16-bit data value into the device register indicated.
|
||||
/// </summary>
|
||||
/// <param name="address">The register.</param>
|
||||
/// <param name="data">The data.</param>
|
||||
public void WriteAddressByte(int address, byte data)
|
||||
{
|
||||
lock (_syncLock)
|
||||
{
|
||||
var result = WiringPi.WiringPiI2CWriteReg8(FileDescriptor, address, data);
|
||||
if (result < 0) HardwareException.Throw(nameof(I2CDevice), nameof(WriteAddressByte));
|
||||
public void WriteAddressByte(Int32 address, Byte data) {
|
||||
lock(this._syncLock) {
|
||||
Int32 result = WiringPi.WiringPiI2CWriteReg8(this.FileDescriptor, address, data);
|
||||
if(result < 0) {
|
||||
HardwareException.Throw(nameof(I2CDevice), nameof(WriteAddressByte));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -151,12 +149,12 @@
|
||||
/// </summary>
|
||||
/// <param name="address">The register.</param>
|
||||
/// <param name="data">The data.</param>
|
||||
public void WriteAddressWord(int address, ushort data)
|
||||
{
|
||||
lock (_syncLock)
|
||||
{
|
||||
var result = WiringPi.WiringPiI2CWriteReg16(FileDescriptor, address, data);
|
||||
if (result < 0) HardwareException.Throw(nameof(I2CDevice), nameof(WriteAddressWord));
|
||||
public void WriteAddressWord(Int32 address, UInt16 data) {
|
||||
lock(this._syncLock) {
|
||||
Int32 result = WiringPi.WiringPiI2CWriteReg16(this.FileDescriptor, address, data);
|
||||
if(result < 0) {
|
||||
HardwareException.Throw(nameof(I2CDevice), nameof(WriteAddressWord));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -165,14 +163,14 @@
|
||||
/// </summary>
|
||||
/// <param name="address">The register.</param>
|
||||
/// <returns>The address byte from device</returns>
|
||||
public byte ReadAddressByte(int address)
|
||||
{
|
||||
lock (_syncLock)
|
||||
{
|
||||
var result = WiringPi.WiringPiI2CReadReg8(FileDescriptor, address);
|
||||
if (result < 0) HardwareException.Throw(nameof(I2CDevice), nameof(ReadAddressByte));
|
||||
public Byte ReadAddressByte(Int32 address) {
|
||||
lock(this._syncLock) {
|
||||
Int32 result = WiringPi.WiringPiI2CReadReg8(this.FileDescriptor, address);
|
||||
if(result < 0) {
|
||||
HardwareException.Throw(nameof(I2CDevice), nameof(ReadAddressByte));
|
||||
}
|
||||
|
||||
return (byte)result;
|
||||
return (Byte)result;
|
||||
}
|
||||
}
|
||||
|
||||
@ -181,12 +179,12 @@
|
||||
/// </summary>
|
||||
/// <param name="address">The register.</param>
|
||||
/// <returns>The address word from device</returns>
|
||||
public ushort ReadAddressWord(int address)
|
||||
{
|
||||
lock (_syncLock)
|
||||
{
|
||||
var result = WiringPi.WiringPiI2CReadReg16(FileDescriptor, address);
|
||||
if (result < 0) HardwareException.Throw(nameof(I2CDevice), nameof(ReadAddressWord));
|
||||
public UInt16 ReadAddressWord(Int32 address) {
|
||||
lock(this._syncLock) {
|
||||
Int32 result = WiringPi.WiringPiI2CReadReg16(this.FileDescriptor, address);
|
||||
if(result < 0) {
|
||||
HardwareException.Throw(nameof(I2CDevice), nameof(ReadAddressWord));
|
||||
}
|
||||
|
||||
return Convert.ToUInt16(result);
|
||||
}
|
||||
|
@ -1,17 +1,15 @@
|
||||
namespace Unosquare.RaspberryIO.Gpio
|
||||
{
|
||||
using Swan.Abstractions;
|
||||
using System;
|
||||
using Unosquare.Swan.Abstractions;
|
||||
|
||||
namespace Unosquare.RaspberryIO.Gpio {
|
||||
/// <summary>
|
||||
/// The SPI Bus containing the 2 SPI channels
|
||||
/// </summary>
|
||||
public class SpiBus : SingletonBase<SpiBus>
|
||||
{
|
||||
public class SpiBus : SingletonBase<SpiBus> {
|
||||
/// <summary>
|
||||
/// Prevents a default instance of the <see cref="SpiBus"/> class from being created.
|
||||
/// </summary>
|
||||
private SpiBus()
|
||||
{
|
||||
private SpiBus() {
|
||||
// placeholder
|
||||
}
|
||||
|
||||
@ -23,7 +21,9 @@
|
||||
/// <value>
|
||||
/// The channel0 frequency.
|
||||
/// </value>
|
||||
public int Channel0Frequency { get; set; }
|
||||
public Int32 Channel0Frequency {
|
||||
get; set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the SPI bus on channel 1.
|
||||
@ -31,14 +31,13 @@
|
||||
/// <value>
|
||||
/// The channel0.
|
||||
/// </value>
|
||||
public SpiChannel Channel0
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Channel0Frequency == 0)
|
||||
Channel0Frequency = SpiChannel.DefaultFrequency;
|
||||
public SpiChannel Channel0 {
|
||||
get {
|
||||
if(this.Channel0Frequency == 0) {
|
||||
this.Channel0Frequency = SpiChannel.DefaultFrequency;
|
||||
}
|
||||
|
||||
return SpiChannel.Retrieve(SpiChannelNumber.Channel0, Channel0Frequency);
|
||||
return SpiChannel.Retrieve(SpiChannelNumber.Channel0, this.Channel0Frequency);
|
||||
}
|
||||
}
|
||||
|
||||
@ -48,7 +47,9 @@
|
||||
/// <value>
|
||||
/// The channel1 frequency.
|
||||
/// </value>
|
||||
public int Channel1Frequency { get; set; }
|
||||
public Int32 Channel1Frequency {
|
||||
get; set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the SPI bus on channel 1.
|
||||
@ -56,14 +57,13 @@
|
||||
/// <value>
|
||||
/// The channel1.
|
||||
/// </value>
|
||||
public SpiChannel Channel1
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Channel1Frequency == 0)
|
||||
Channel1Frequency = SpiChannel.DefaultFrequency;
|
||||
public SpiChannel Channel1 {
|
||||
get {
|
||||
if(this.Channel1Frequency == 0) {
|
||||
this.Channel1Frequency = SpiChannel.DefaultFrequency;
|
||||
}
|
||||
|
||||
return SpiChannel.Retrieve(SpiChannelNumber.Channel1, Channel1Frequency);
|
||||
return SpiChannel.Retrieve(SpiChannelNumber.Channel1, this.Channel1Frequency);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,53 +1,48 @@
|
||||
namespace Unosquare.RaspberryIO.Gpio
|
||||
{
|
||||
using Native;
|
||||
using Swan;
|
||||
using Unosquare.RaspberryIO.Native;
|
||||
using Unosquare.Swan;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Unosquare.RaspberryIO.Gpio {
|
||||
/// <summary>
|
||||
/// Provides access to using the SPI buses on the GPIO.
|
||||
/// SPI is a bus that works like a ring shift register
|
||||
/// The number of bytes pushed is equal to the number of bytes received.
|
||||
/// </summary>
|
||||
public sealed class SpiChannel
|
||||
{
|
||||
public sealed class SpiChannel {
|
||||
/// <summary>
|
||||
/// The minimum frequency of an SPI Channel
|
||||
/// </summary>
|
||||
public const int MinFrequency = 500000;
|
||||
public const Int32 MinFrequency = 500000;
|
||||
|
||||
/// <summary>
|
||||
/// The maximum frequency of an SPI channel
|
||||
/// </summary>
|
||||
public const int MaxFrequency = 32000000;
|
||||
public const Int32 MaxFrequency = 32000000;
|
||||
|
||||
/// <summary>
|
||||
/// The default frequency of SPI channels
|
||||
/// This is set to 8 Mhz wich is typical in modern hardware.
|
||||
/// </summary>
|
||||
public const int DefaultFrequency = 8000000;
|
||||
public const Int32 DefaultFrequency = 8000000;
|
||||
|
||||
private static readonly object SyncRoot = new object();
|
||||
private static readonly Object SyncRoot = new Object();
|
||||
private static readonly Dictionary<SpiChannelNumber, SpiChannel> Buses = new Dictionary<SpiChannelNumber, SpiChannel>();
|
||||
private readonly object _syncLock = new object();
|
||||
private readonly Object _syncLock = new Object();
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SpiChannel"/> class.
|
||||
/// </summary>
|
||||
/// <param name="channel">The channel.</param>
|
||||
/// <param name="frequency">The frequency.</param>
|
||||
private SpiChannel(SpiChannelNumber channel, int frequency)
|
||||
{
|
||||
lock (SyncRoot)
|
||||
{
|
||||
Frequency = frequency.Clamp(MinFrequency, MaxFrequency);
|
||||
Channel = (int)channel;
|
||||
FileDescriptor = WiringPi.WiringPiSPISetup((int)channel, Frequency);
|
||||
private SpiChannel(SpiChannelNumber channel, Int32 frequency) {
|
||||
lock(SyncRoot) {
|
||||
this.Frequency = frequency.Clamp(MinFrequency, MaxFrequency);
|
||||
this.Channel = (Int32)channel;
|
||||
this.FileDescriptor = WiringPi.WiringPiSPISetup((Int32)channel, this.Frequency);
|
||||
|
||||
if (FileDescriptor < 0)
|
||||
{
|
||||
if(this.FileDescriptor < 0) {
|
||||
HardwareException.Throw(nameof(SpiChannel), channel.ToString());
|
||||
}
|
||||
}
|
||||
@ -60,35 +55,42 @@
|
||||
/// <value>
|
||||
/// The file descriptor.
|
||||
/// </value>
|
||||
public int FileDescriptor { get; }
|
||||
public Int32 FileDescriptor {
|
||||
get;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the channel.
|
||||
/// </summary>
|
||||
public int Channel { get; }
|
||||
public Int32 Channel {
|
||||
get;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the frequency.
|
||||
/// </summary>
|
||||
public int Frequency { get; }
|
||||
public Int32 Frequency {
|
||||
get;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sends data and simultaneously receives the data in the return buffer
|
||||
/// </summary>
|
||||
/// <param name="buffer">The buffer.</param>
|
||||
/// <returns>The read bytes from the ring-style bus</returns>
|
||||
public byte[] SendReceive(byte[] buffer)
|
||||
{
|
||||
if (buffer == null || buffer.Length == 0)
|
||||
public Byte[] SendReceive(Byte[] buffer) {
|
||||
if(buffer == null || buffer.Length == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
lock (_syncLock)
|
||||
{
|
||||
var spiBuffer = new byte[buffer.Length];
|
||||
lock(this._syncLock) {
|
||||
Byte[] spiBuffer = new Byte[buffer.Length];
|
||||
Array.Copy(buffer, spiBuffer, buffer.Length);
|
||||
|
||||
var result = WiringPi.WiringPiSPIDataRW(Channel, spiBuffer, spiBuffer.Length);
|
||||
if (result < 0) HardwareException.Throw(nameof(SpiChannel), nameof(SendReceive));
|
||||
Int32 result = WiringPi.WiringPiSPIDataRW(this.Channel, spiBuffer, spiBuffer.Length);
|
||||
if(result < 0) {
|
||||
HardwareException.Throw(nameof(SpiChannel), nameof(SendReceive));
|
||||
}
|
||||
|
||||
return spiBuffer;
|
||||
}
|
||||
@ -101,7 +103,7 @@
|
||||
/// <returns>
|
||||
/// The read bytes from the ring-style bus
|
||||
/// </returns>
|
||||
public Task<byte[]> SendReceiveAsync(byte[] buffer) => Task.Run(() => SendReceive(buffer));
|
||||
public Task<Byte[]> SendReceiveAsync(Byte[] buffer) => Task.Run(() => this.SendReceive(buffer));
|
||||
|
||||
/// <summary>
|
||||
/// Writes the specified buffer the the underlying FileDescriptor.
|
||||
@ -110,16 +112,15 @@
|
||||
/// like sending data over to those long RGB LED strips
|
||||
/// </summary>
|
||||
/// <param name="buffer">The buffer.</param>
|
||||
public void Write(byte[] buffer)
|
||||
{
|
||||
lock (_syncLock)
|
||||
{
|
||||
var result = Standard.Write(FileDescriptor, buffer, buffer.Length);
|
||||
public void Write(Byte[] buffer) {
|
||||
lock(this._syncLock) {
|
||||
Int32 result = Standard.Write(this.FileDescriptor, buffer, buffer.Length);
|
||||
|
||||
if (result < 0)
|
||||
if(result < 0) {
|
||||
HardwareException.Throw(nameof(SpiChannel), nameof(Write));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the specified buffer the the underlying FileDescriptor.
|
||||
@ -129,7 +130,7 @@
|
||||
/// </summary>
|
||||
/// <param name="buffer">The buffer.</param>
|
||||
/// <returns>The awaitable task</returns>
|
||||
public Task WriteAsync(byte[] buffer) => Task.Run(() => { Write(buffer); });
|
||||
public Task WriteAsync(Byte[] buffer) => Task.Run(() => this.Write(buffer));
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the spi bus. If the bus channel is not registered it sets it up automatically.
|
||||
@ -138,14 +139,13 @@
|
||||
/// <param name="channel">The channel.</param>
|
||||
/// <param name="frequency">The frequency.</param>
|
||||
/// <returns>The usable SPI channel</returns>
|
||||
internal static SpiChannel Retrieve(SpiChannelNumber channel, int frequency)
|
||||
{
|
||||
lock (SyncRoot)
|
||||
{
|
||||
if (Buses.ContainsKey(channel))
|
||||
internal static SpiChannel Retrieve(SpiChannelNumber channel, Int32 frequency) {
|
||||
lock(SyncRoot) {
|
||||
if(Buses.ContainsKey(channel)) {
|
||||
return Buses[channel];
|
||||
}
|
||||
|
||||
var newBus = new SpiChannel(channel, frequency);
|
||||
SpiChannel newBus = new SpiChannel(channel, frequency);
|
||||
Buses[channel] = newBus;
|
||||
return newBus;
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
namespace Unosquare.RaspberryIO.Native
|
||||
{
|
||||
namespace Unosquare.RaspberryIO.Native {
|
||||
/// <summary>
|
||||
/// A delegate defining a callback for an Interrupt Service Routine
|
||||
/// </summary>
|
||||
|
@ -1,38 +1,32 @@
|
||||
namespace Unosquare.RaspberryIO.Native
|
||||
{
|
||||
using Swan;
|
||||
using Unosquare.Swan;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Unosquare.RaspberryIO.Native {
|
||||
/// <summary>
|
||||
/// Represents a low-level exception, typically thrown when return codes from a
|
||||
/// low-level operation is non-zero or in some cases when it is less than zero.
|
||||
/// </summary>
|
||||
/// <seealso cref="Exception" />
|
||||
public class HardwareException : Exception
|
||||
{
|
||||
public class HardwareException : Exception {
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="HardwareException" /> class.
|
||||
/// </summary>
|
||||
/// <param name="errorCode">The error code.</param>
|
||||
/// <param name="component">The component.</param>
|
||||
public HardwareException(int errorCode, string component)
|
||||
: base($"A hardware exception occurred. Error Code: {errorCode}")
|
||||
{
|
||||
ExtendedMessage = null;
|
||||
public HardwareException(Int32 errorCode, String component)
|
||||
: base($"A hardware exception occurred. Error Code: {errorCode}") {
|
||||
this.ExtendedMessage = null;
|
||||
|
||||
try
|
||||
{
|
||||
ExtendedMessage = Standard.Strerror(errorCode);
|
||||
}
|
||||
catch
|
||||
{
|
||||
try {
|
||||
this.ExtendedMessage = Standard.Strerror(errorCode);
|
||||
} catch {
|
||||
// TODO: strerror not working great...
|
||||
$"Could not retrieve native error description using {nameof(Standard.Strerror)}".Error(Pi.LoggerSource);
|
||||
}
|
||||
|
||||
ErrorCode = errorCode;
|
||||
Component = component;
|
||||
this.ErrorCode = errorCode;
|
||||
this.Component = component;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -41,7 +35,9 @@
|
||||
/// <value>
|
||||
/// The error code.
|
||||
/// </value>
|
||||
public int ErrorCode { get; }
|
||||
public Int32 ErrorCode {
|
||||
get;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the component.
|
||||
@ -49,7 +45,9 @@
|
||||
/// <value>
|
||||
/// The component.
|
||||
/// </value>
|
||||
public string Component { get; }
|
||||
public String Component {
|
||||
get;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the extended message (could be null).
|
||||
@ -57,7 +55,9 @@
|
||||
/// <value>
|
||||
/// The extended message.
|
||||
/// </value>
|
||||
public string ExtendedMessage { get; }
|
||||
public String ExtendedMessage {
|
||||
get;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Throws a new instance of a hardware error by retrieving the last error number (errno).
|
||||
@ -65,9 +65,9 @@
|
||||
/// <param name="className">Name of the class.</param>
|
||||
/// <param name="methodName">Name of the method.</param>
|
||||
/// <exception cref="HardwareException">When an error thrown by an API call occurs</exception>
|
||||
public static void Throw(string className, string methodName) => throw new HardwareException(Marshal.GetLastWin32Error(), $"{className}.{methodName}");
|
||||
public static void Throw(String className, String methodName) => throw new HardwareException(Marshal.GetLastWin32Error(), $"{className}.{methodName}");
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string ToString() => $"{GetType()}{(string.IsNullOrWhiteSpace(Component) ? string.Empty : $" on {Component}")}: ({ErrorCode}) - {Message}";
|
||||
public override String ToString() => $"{this.GetType()}{(String.IsNullOrWhiteSpace(this.Component) ? String.Empty : $" on {this.Component}")}: ({this.ErrorCode}) - {this.Message}";
|
||||
}
|
||||
}
|
||||
|
@ -1,32 +1,30 @@
|
||||
namespace Unosquare.RaspberryIO.Native
|
||||
{
|
||||
using System;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Unosquare.RaspberryIO.Native {
|
||||
/// <summary>
|
||||
/// Provides access to a high- esolution, time measuring device.
|
||||
/// </summary>
|
||||
/// <seealso cref="Stopwatch" />
|
||||
public class HighResolutionTimer : Stopwatch
|
||||
{
|
||||
public class HighResolutionTimer : Stopwatch {
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="HighResolutionTimer"/> class.
|
||||
/// </summary>
|
||||
/// <exception cref="NotSupportedException">High-resolution timer not available</exception>
|
||||
public HighResolutionTimer()
|
||||
{
|
||||
if (!IsHighResolution)
|
||||
public HighResolutionTimer() {
|
||||
if(!IsHighResolution) {
|
||||
throw new NotSupportedException("High-resolution timer not available");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the numer of microseconds per timer tick.
|
||||
/// </summary>
|
||||
public static double MicrosecondsPerTick { get; } = 1000000d / Frequency;
|
||||
public static Double MicrosecondsPerTick { get; } = 1000000d / Frequency;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the elapsed microseconds.
|
||||
/// </summary>
|
||||
public long ElapsedMicroseconds => (long)(ElapsedTicks * MicrosecondsPerTick);
|
||||
public Int64 ElapsedMicroseconds => (Int64)(this.ElapsedTicks * MicrosecondsPerTick);
|
||||
}
|
||||
}
|
||||
|
@ -1,16 +1,14 @@
|
||||
namespace Unosquare.RaspberryIO.Native
|
||||
{
|
||||
using Swan;
|
||||
using Unosquare.Swan;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace Unosquare.RaspberryIO.Native {
|
||||
/// <summary>
|
||||
/// Provides standard libc calls using platform-invoke
|
||||
/// </summary>
|
||||
internal static class Standard
|
||||
{
|
||||
internal const string LibCLibrary = "libc";
|
||||
internal static class Standard {
|
||||
internal const String LibCLibrary = "libc";
|
||||
|
||||
#region LibC Calls
|
||||
|
||||
@ -19,18 +17,16 @@
|
||||
/// </summary>
|
||||
/// <param name="error">The error.</param>
|
||||
/// <returns></returns>
|
||||
public static string Strerror(int error)
|
||||
{
|
||||
if (!Runtime.IsUsingMonoRuntime) return StrError(error);
|
||||
|
||||
try
|
||||
{
|
||||
var buffer = new StringBuilder(256);
|
||||
var result = Strerror(error, buffer, (ulong)buffer.Capacity);
|
||||
return (result != -1) ? buffer.ToString() : null;
|
||||
public static String Strerror(Int32 error) {
|
||||
if(!Runtime.IsUsingMonoRuntime) {
|
||||
return StrError(error);
|
||||
}
|
||||
catch (EntryPointNotFoundException)
|
||||
{
|
||||
|
||||
try {
|
||||
StringBuilder buffer = new StringBuilder(256);
|
||||
Int32 result = Strerror(error, buffer, (UInt64)buffer.Capacity);
|
||||
return (result != -1) ? buffer.ToString() : null;
|
||||
} catch(EntryPointNotFoundException) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -42,7 +38,7 @@
|
||||
/// <param name="mode">The mode.</param>
|
||||
/// <returns>The result</returns>
|
||||
[DllImport(LibCLibrary, EntryPoint = "chmod", SetLastError = true)]
|
||||
public static extern int Chmod(string filename, uint mode);
|
||||
public static extern Int32 Chmod(String filename, UInt32 mode);
|
||||
|
||||
/// <summary>
|
||||
/// Converts a string to a 32 bit integer. Use endpointer as IntPtr.Zero
|
||||
@ -52,7 +48,7 @@
|
||||
/// <param name="numberBase">The number base.</param>
|
||||
/// <returns>The result</returns>
|
||||
[DllImport(LibCLibrary, EntryPoint = "strtol", SetLastError = true)]
|
||||
public static extern int StringToInteger(string numberString, IntPtr endPointer, int numberBase);
|
||||
public static extern Int32 StringToInteger(String numberString, IntPtr endPointer, Int32 numberBase);
|
||||
|
||||
/// <summary>
|
||||
/// The write() function attempts to write nbytes from buffer to the file associated with handle. On text files, it expands each LF to a CR/LF.
|
||||
@ -63,7 +59,7 @@
|
||||
/// <param name="count">The count.</param>
|
||||
/// <returns>The result</returns>
|
||||
[DllImport(LibCLibrary, EntryPoint = "write", SetLastError = true)]
|
||||
public static extern int Write(int fd, byte[] buffer, int count);
|
||||
public static extern Int32 Write(Int32 fd, Byte[] buffer, Int32 count);
|
||||
|
||||
/// <summary>
|
||||
/// Fills in the structure with information about the system.
|
||||
@ -71,13 +67,13 @@
|
||||
/// <param name="name">The name.</param>
|
||||
/// <returns>The result</returns>
|
||||
[DllImport(LibCLibrary, EntryPoint = "uname", SetLastError = true)]
|
||||
public static extern int Uname(out SystemName name);
|
||||
public static extern Int32 Uname(out SystemName name);
|
||||
|
||||
[DllImport(LibCLibrary, EntryPoint = "strerror", SetLastError = true)]
|
||||
private static extern string StrError(int errnum);
|
||||
private static extern String StrError(Int32 errnum);
|
||||
|
||||
[DllImport("MonoPosixHelper", EntryPoint = "Mono_Posix_Syscall_strerror_r", SetLastError = true)]
|
||||
private static extern int Strerror(int error, [Out] StringBuilder buffer, ulong length);
|
||||
private static extern Int32 Strerror(Int32 error, [Out] StringBuilder buffer, UInt64 length);
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
@ -1,47 +1,46 @@
|
||||
namespace Unosquare.RaspberryIO.Native
|
||||
{
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Unosquare.RaspberryIO.Native {
|
||||
/// <summary>
|
||||
/// OS uname structure
|
||||
/// </summary>
|
||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
|
||||
internal struct SystemName
|
||||
{
|
||||
internal struct SystemName {
|
||||
/// <summary>
|
||||
/// System name
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 65)]
|
||||
public string SysName;
|
||||
public String SysName;
|
||||
|
||||
/// <summary>
|
||||
/// Node name
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 65)]
|
||||
public string NodeName;
|
||||
public String NodeName;
|
||||
|
||||
/// <summary>
|
||||
/// Release level
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 65)]
|
||||
public string Release;
|
||||
public String Release;
|
||||
|
||||
/// <summary>
|
||||
/// Version level
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 65)]
|
||||
public string Version;
|
||||
public String Version;
|
||||
|
||||
/// <summary>
|
||||
/// Hardware level
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 65)]
|
||||
public string Machine;
|
||||
public String Machine;
|
||||
|
||||
/// <summary>
|
||||
/// Domain name
|
||||
/// </summary>
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 65)]
|
||||
public string DomainName;
|
||||
public String DomainName;
|
||||
}
|
||||
}
|
@ -1,10 +1,8 @@
|
||||
namespace Unosquare.RaspberryIO.Native
|
||||
{
|
||||
namespace Unosquare.RaspberryIO.Native {
|
||||
/// <summary>
|
||||
/// Defines the different threading locking keys
|
||||
/// </summary>
|
||||
public enum ThreadLockKey
|
||||
{
|
||||
public enum ThreadLockKey {
|
||||
/// <summary>
|
||||
/// The lock 0
|
||||
/// </summary>
|
||||
|
@ -1,20 +1,17 @@
|
||||
namespace Unosquare.RaspberryIO.Native
|
||||
{
|
||||
using Swan;
|
||||
using Swan.Abstractions;
|
||||
using Unosquare.Swan;
|
||||
using Unosquare.Swan.Abstractions;
|
||||
using System;
|
||||
|
||||
namespace Unosquare.RaspberryIO.Native {
|
||||
/// <summary>
|
||||
/// Provides access to timing and threading properties and methods
|
||||
/// </summary>
|
||||
public class Timing : SingletonBase<Timing>
|
||||
{
|
||||
public class Timing : SingletonBase<Timing> {
|
||||
/// <summary>
|
||||
/// Prevents a default instance of the <see cref="Timing"/> class from being created.
|
||||
/// </summary>
|
||||
/// <exception cref="NotSupportedException">Could not initialize the GPIO controller</exception>
|
||||
private Timing()
|
||||
{
|
||||
private Timing() {
|
||||
// placeholder
|
||||
}
|
||||
|
||||
@ -26,7 +23,7 @@
|
||||
/// <value>
|
||||
/// The milliseconds since setup.
|
||||
/// </value>
|
||||
public uint MillisecondsSinceSetup => WiringPi.Millis();
|
||||
public UInt32 MillisecondsSinceSetup => WiringPi.Millis();
|
||||
|
||||
/// <summary>
|
||||
/// This returns a number representing the number of microseconds since your
|
||||
@ -36,7 +33,7 @@
|
||||
/// <value>
|
||||
/// The microseconds since setup.
|
||||
/// </value>
|
||||
public uint MicrosecondsSinceSetup => WiringPi.Micros();
|
||||
public UInt32 MicrosecondsSinceSetup => WiringPi.Micros();
|
||||
|
||||
/// <summary>
|
||||
/// This causes program execution to pause for at least howLong milliseconds.
|
||||
@ -44,7 +41,7 @@
|
||||
/// Note that the maximum delay is an unsigned 32-bit integer or approximately 49 days.
|
||||
/// </summary>
|
||||
/// <param name="value">The value.</param>
|
||||
public static void SleepMilliseconds(uint value) => WiringPi.Delay(value);
|
||||
public static void SleepMilliseconds(UInt32 value) => WiringPi.Delay(value);
|
||||
|
||||
/// <summary>
|
||||
/// This causes program execution to pause for at least howLong microseconds.
|
||||
@ -56,7 +53,7 @@
|
||||
/// especially if using threads.
|
||||
/// </summary>
|
||||
/// <param name="value">The value.</param>
|
||||
public void SleepMicroseconds(uint value) => WiringPi.DelayMicroseconds(value);
|
||||
public void SleepMicroseconds(UInt32 value) => WiringPi.DelayMicroseconds(value);
|
||||
|
||||
/// <summary>
|
||||
/// This attempts to shift your program (or thread in a multi-threaded program) to a higher priority and
|
||||
@ -67,11 +64,12 @@
|
||||
/// (as long as no other programs are running with elevated priorities)
|
||||
/// </summary>
|
||||
/// <param name="priority">The priority.</param>
|
||||
public void SetThreadPriority(int priority)
|
||||
{
|
||||
public void SetThreadPriority(Int32 priority) {
|
||||
priority = priority.Clamp(0, 99);
|
||||
var result = WiringPi.PiHiPri(priority);
|
||||
if (result < 0) HardwareException.Throw(nameof(Timing), nameof(SetThreadPriority));
|
||||
Int32 result = WiringPi.PiHiPri(priority);
|
||||
if(result < 0) {
|
||||
HardwareException.Throw(nameof(Timing), nameof(SetThreadPriority));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -80,13 +78,15 @@
|
||||
/// </summary>
|
||||
/// <param name="worker">The worker.</param>
|
||||
/// <exception cref="ArgumentNullException">worker</exception>
|
||||
public void CreateThread(ThreadWorker worker)
|
||||
{
|
||||
if (worker == null)
|
||||
public void CreateThread(ThreadWorker worker) {
|
||||
if(worker == null) {
|
||||
throw new ArgumentNullException(nameof(worker));
|
||||
}
|
||||
|
||||
var result = WiringPi.PiThreadCreate(worker);
|
||||
if (result != 0) HardwareException.Throw(nameof(Timing), nameof(CreateThread));
|
||||
Int32 result = WiringPi.PiThreadCreate(worker);
|
||||
if(result != 0) {
|
||||
HardwareException.Throw(nameof(Timing), nameof(CreateThread));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -95,7 +95,7 @@
|
||||
/// it will be stalled until the first process has unlocked the same key.
|
||||
/// </summary>
|
||||
/// <param name="key">The key.</param>
|
||||
public void Lock(ThreadLockKey key) => WiringPi.PiLock((int)key);
|
||||
public void Lock(ThreadLockKey key) => WiringPi.PiLock((Int32)key);
|
||||
|
||||
/// <summary>
|
||||
/// These allow you to synchronize variable updates from your main program to any threads running in your program.
|
||||
@ -103,6 +103,6 @@
|
||||
/// it will be stalled until the first process has unlocked the same key.
|
||||
/// </summary>
|
||||
/// <param name="key">The key.</param>
|
||||
public void Unlock(ThreadLockKey key) => WiringPi.PiUnlock((int)key);
|
||||
public void Unlock(ThreadLockKey key) => WiringPi.PiUnlock((Int32)key);
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,8 @@
|
||||
namespace Unosquare.RaspberryIO.Native
|
||||
{
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
public partial class WiringPi
|
||||
{
|
||||
namespace Unosquare.RaspberryIO.Native {
|
||||
public partial class WiringPi {
|
||||
#region WiringPi - I2C Library Calls
|
||||
|
||||
/// <summary>
|
||||
@ -12,7 +11,7 @@
|
||||
/// <param name="fd">The fd.</param>
|
||||
/// <returns>The result</returns>
|
||||
[DllImport(WiringPiLibrary, EntryPoint = "wiringPiI2CRead", SetLastError = true)]
|
||||
public static extern int WiringPiI2CRead(int fd);
|
||||
public static extern Int32 WiringPiI2CRead(Int32 fd);
|
||||
|
||||
/// <summary>
|
||||
/// These read an 8-bit value from the device register indicated.
|
||||
@ -21,7 +20,7 @@
|
||||
/// <param name="reg">The reg.</param>
|
||||
/// <returns>The result</returns>
|
||||
[DllImport(WiringPiLibrary, EntryPoint = "wiringPiI2CReadReg8", SetLastError = true)]
|
||||
public static extern int WiringPiI2CReadReg8(int fd, int reg);
|
||||
public static extern Int32 WiringPiI2CReadReg8(Int32 fd, Int32 reg);
|
||||
|
||||
/// <summary>
|
||||
/// These read a 16-bit value from the device register indicated.
|
||||
@ -30,7 +29,7 @@
|
||||
/// <param name="reg">The reg.</param>
|
||||
/// <returns>The result</returns>
|
||||
[DllImport(WiringPiLibrary, EntryPoint = "wiringPiI2CReadReg16", SetLastError = true)]
|
||||
public static extern int WiringPiI2CReadReg16(int fd, int reg);
|
||||
public static extern Int32 WiringPiI2CReadReg16(Int32 fd, Int32 reg);
|
||||
|
||||
/// <summary>
|
||||
/// Simple device write. Some devices accept data this way without needing to access any internal registers.
|
||||
@ -39,7 +38,7 @@
|
||||
/// <param name="data">The data.</param>
|
||||
/// <returns>The result</returns>
|
||||
[DllImport(WiringPiLibrary, EntryPoint = "wiringPiI2CWrite", SetLastError = true)]
|
||||
public static extern int WiringPiI2CWrite(int fd, int data);
|
||||
public static extern Int32 WiringPiI2CWrite(Int32 fd, Int32 data);
|
||||
|
||||
/// <summary>
|
||||
/// These write an 8-bit data value into the device register indicated.
|
||||
@ -49,7 +48,7 @@
|
||||
/// <param name="data">The data.</param>
|
||||
/// <returns>The result</returns>
|
||||
[DllImport(WiringPiLibrary, EntryPoint = "wiringPiI2CWriteReg8", SetLastError = true)]
|
||||
public static extern int WiringPiI2CWriteReg8(int fd, int reg, int data);
|
||||
public static extern Int32 WiringPiI2CWriteReg8(Int32 fd, Int32 reg, Int32 data);
|
||||
|
||||
/// <summary>
|
||||
/// These write a 16-bit data value into the device register indicated.
|
||||
@ -59,7 +58,7 @@
|
||||
/// <param name="data">The data.</param>
|
||||
/// <returns>The result</returns>
|
||||
[DllImport(WiringPiLibrary, EntryPoint = "wiringPiI2CWriteReg16", SetLastError = true)]
|
||||
public static extern int WiringPiI2CWriteReg16(int fd, int reg, int data);
|
||||
public static extern Int32 WiringPiI2CWriteReg16(Int32 fd, Int32 reg, Int32 data);
|
||||
|
||||
/// <summary>
|
||||
/// This initialises the I2C system with your given device identifier.
|
||||
@ -71,7 +70,7 @@
|
||||
/// <param name="devId">The dev identifier.</param>
|
||||
/// <returns>The result</returns>
|
||||
[DllImport(WiringPiLibrary, EntryPoint = "wiringPiI2CSetup", SetLastError = true)]
|
||||
public static extern int WiringPiI2CSetup(int devId);
|
||||
public static extern Int32 WiringPiI2CSetup(Int32 devId);
|
||||
|
||||
#endregion
|
||||
|
||||
|
@ -1,9 +1,8 @@
|
||||
namespace Unosquare.RaspberryIO.Native
|
||||
{
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
public partial class WiringPi
|
||||
{
|
||||
namespace Unosquare.RaspberryIO.Native {
|
||||
public partial class WiringPi {
|
||||
#region WiringPi - Serial Port
|
||||
|
||||
/// <summary>
|
||||
@ -17,7 +16,7 @@
|
||||
/// <param name="baud">The baud.</param>
|
||||
/// <returns>The result</returns>
|
||||
[DllImport(WiringPiLibrary, EntryPoint = "serialOpen", SetLastError = true)]
|
||||
public static extern int SerialOpen(string device, int baud);
|
||||
public static extern Int32 SerialOpen(String device, Int32 baud);
|
||||
|
||||
/// <summary>
|
||||
/// Closes the device identified by the file descriptor given.
|
||||
@ -25,7 +24,7 @@
|
||||
/// <param name="fd">The fd.</param>
|
||||
/// <returns>The result</returns>
|
||||
[DllImport(WiringPiLibrary, EntryPoint = "serialClose", SetLastError = true)]
|
||||
public static extern int SerialClose(int fd);
|
||||
public static extern Int32 SerialClose(Int32 fd);
|
||||
|
||||
/// <summary>
|
||||
/// Sends the single byte to the serial device identified by the given file descriptor.
|
||||
@ -33,7 +32,7 @@
|
||||
/// <param name="fd">The fd.</param>
|
||||
/// <param name="c">The c.</param>
|
||||
[DllImport(WiringPiLibrary, EntryPoint = "serialPutchar", SetLastError = true)]
|
||||
public static extern void SerialPutchar(int fd, byte c);
|
||||
public static extern void SerialPutchar(Int32 fd, Byte c);
|
||||
|
||||
/// <summary>
|
||||
/// Sends the nul-terminated string to the serial device identified by the given file descriptor.
|
||||
@ -41,7 +40,7 @@
|
||||
/// <param name="fd">The fd.</param>
|
||||
/// <param name="s">The s.</param>
|
||||
[DllImport(WiringPiLibrary, EntryPoint = "serialPuts", SetLastError = true)]
|
||||
public static extern void SerialPuts(int fd, string s);
|
||||
public static extern void SerialPuts(Int32 fd, String s);
|
||||
|
||||
/// <summary>
|
||||
/// Returns the number of characters available for reading, or -1 for any error condition,
|
||||
@ -50,7 +49,7 @@
|
||||
/// <param name="fd">The fd.</param>
|
||||
/// <returns>The result</returns>
|
||||
[DllImport(WiringPiLibrary, EntryPoint = "serialDataAvail", SetLastError = true)]
|
||||
public static extern int SerialDataAvail(int fd);
|
||||
public static extern Int32 SerialDataAvail(Int32 fd);
|
||||
|
||||
/// <summary>
|
||||
/// Returns the next character available on the serial device.
|
||||
@ -59,14 +58,14 @@
|
||||
/// <param name="fd">The fd.</param>
|
||||
/// <returns>The result</returns>
|
||||
[DllImport(WiringPiLibrary, EntryPoint = "serialGetchar", SetLastError = true)]
|
||||
public static extern int SerialGetchar(int fd);
|
||||
public static extern Int32 SerialGetchar(Int32 fd);
|
||||
|
||||
/// <summary>
|
||||
/// This discards all data received, or waiting to be send down the given device.
|
||||
/// </summary>
|
||||
/// <param name="fd">The fd.</param>
|
||||
[DllImport(WiringPiLibrary, EntryPoint = "serialFlush", SetLastError = true)]
|
||||
public static extern void SerialFlush(int fd);
|
||||
public static extern void SerialFlush(Int32 fd);
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
@ -1,9 +1,8 @@
|
||||
namespace Unosquare.RaspberryIO.Native
|
||||
{
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
public partial class WiringPi
|
||||
{
|
||||
namespace Unosquare.RaspberryIO.Native {
|
||||
public partial class WiringPi {
|
||||
#region WiringPi - Shift Library
|
||||
|
||||
/// <summary>
|
||||
@ -16,7 +15,7 @@
|
||||
/// <param name="order">The order.</param>
|
||||
/// <returns>The result</returns>
|
||||
[DllImport(WiringPiLibrary, EntryPoint = "shiftIn", SetLastError = true)]
|
||||
public static extern byte ShiftIn(byte dPin, byte cPin, byte order);
|
||||
public static extern Byte ShiftIn(Byte dPin, Byte cPin, Byte order);
|
||||
|
||||
/// <summary>
|
||||
/// The shifts an 8-bit data value val out with the data being sent out on dPin and the clock being sent out on the cPin.
|
||||
@ -28,7 +27,7 @@
|
||||
/// <param name="order">The order.</param>
|
||||
/// <param name="val">The value.</param>
|
||||
[DllImport(WiringPiLibrary, EntryPoint = "shiftOut", SetLastError = true)]
|
||||
public static extern void ShiftOut(byte dPin, byte cPin, byte order, byte val);
|
||||
public static extern void ShiftOut(Byte dPin, Byte cPin, Byte order, Byte val);
|
||||
|
||||
#endregion
|
||||
|
||||
|
@ -1,9 +1,8 @@
|
||||
namespace Unosquare.RaspberryIO.Native
|
||||
{
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
public partial class WiringPi
|
||||
{
|
||||
namespace Unosquare.RaspberryIO.Native {
|
||||
public partial class WiringPi {
|
||||
#region WiringPi - Soft PWM (https://github.com/WiringPi/WiringPi/blob/master/wiringPi/softPwm.h)
|
||||
|
||||
/// <summary>
|
||||
@ -16,7 +15,7 @@
|
||||
/// <param name="pwmRange">The PWM range.</param>
|
||||
/// <returns>The result</returns>
|
||||
[DllImport(WiringPiLibrary, EntryPoint = "softPwmCreate", SetLastError = true)]
|
||||
public static extern int SoftPwmCreate(int pin, int initialValue, int pwmRange);
|
||||
public static extern Int32 SoftPwmCreate(Int32 pin, Int32 initialValue, Int32 pwmRange);
|
||||
|
||||
/// <summary>
|
||||
/// This updates the PWM value on the given pin. The value is checked to be in-range and pins that haven’t previously
|
||||
@ -25,14 +24,14 @@
|
||||
/// <param name="pin">The pin.</param>
|
||||
/// <param name="value">The value.</param>
|
||||
[DllImport(WiringPiLibrary, EntryPoint = "softPwmWrite", SetLastError = true)]
|
||||
public static extern void SoftPwmWrite(int pin, int value);
|
||||
public static extern void SoftPwmWrite(Int32 pin, Int32 value);
|
||||
|
||||
/// <summary>
|
||||
/// This function is undocumented
|
||||
/// </summary>
|
||||
/// <param name="pin">The pin.</param>
|
||||
[DllImport(WiringPiLibrary, EntryPoint = "softPwmStop", SetLastError = true)]
|
||||
public static extern void SoftPwmStop(int pin);
|
||||
public static extern void SoftPwmStop(Int32 pin);
|
||||
|
||||
/// <summary>
|
||||
/// This creates a software controlled tone pin. You can use any GPIO pin and the pin numbering will be that of the wiringPiSetup() function you used.
|
||||
@ -41,14 +40,14 @@
|
||||
/// <param name="pin">The pin.</param>
|
||||
/// <returns>The result</returns>
|
||||
[DllImport(WiringPiLibrary, EntryPoint = "softToneCreate", SetLastError = true)]
|
||||
public static extern int SoftToneCreate(int pin);
|
||||
public static extern Int32 SoftToneCreate(Int32 pin);
|
||||
|
||||
/// <summary>
|
||||
/// This function is undocumented
|
||||
/// </summary>
|
||||
/// <param name="pin">The pin.</param>
|
||||
[DllImport(WiringPiLibrary, EntryPoint = "softToneStop", SetLastError = true)]
|
||||
public static extern void SoftToneStop(int pin);
|
||||
public static extern void SoftToneStop(Int32 pin);
|
||||
|
||||
/// <summary>
|
||||
/// This updates the tone frequency value on the given pin. The tone will be played until you set the frequency to 0.
|
||||
@ -56,7 +55,7 @@
|
||||
/// <param name="pin">The pin.</param>
|
||||
/// <param name="freq">The freq.</param>
|
||||
[DllImport(WiringPiLibrary, EntryPoint = "softToneWrite", SetLastError = true)]
|
||||
public static extern void SoftToneWrite(int pin, int freq);
|
||||
public static extern void SoftToneWrite(Int32 pin, Int32 freq);
|
||||
|
||||
#endregion
|
||||
|
||||
|
@ -1,9 +1,8 @@
|
||||
namespace Unosquare.RaspberryIO.Native
|
||||
{
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
public partial class WiringPi
|
||||
{
|
||||
namespace Unosquare.RaspberryIO.Native {
|
||||
public partial class WiringPi {
|
||||
#region WiringPi - SPI Library Calls
|
||||
|
||||
/// <summary>
|
||||
@ -12,7 +11,7 @@
|
||||
/// <param name="channel">The channel.</param>
|
||||
/// <returns>Unknown</returns>
|
||||
[DllImport(WiringPiLibrary, EntryPoint = "wiringPiSPIGetFd", SetLastError = true)]
|
||||
public static extern int WiringPiSPIGetFd(int channel);
|
||||
public static extern Int32 WiringPiSPIGetFd(Int32 channel);
|
||||
|
||||
/// <summary>
|
||||
/// This performs a simultaneous write/read transaction over the selected SPI bus. Data that was in your buffer is overwritten by data returned from the SPI bus.
|
||||
@ -25,7 +24,7 @@
|
||||
/// <param name="len">The length.</param>
|
||||
/// <returns>The result</returns>
|
||||
[DllImport(WiringPiLibrary, EntryPoint = "wiringPiSPIDataRW", SetLastError = true)]
|
||||
public static extern int WiringPiSPIDataRW(int channel, byte[] data, int len);
|
||||
public static extern Int32 WiringPiSPIDataRW(Int32 channel, Byte[] data, Int32 len);
|
||||
|
||||
/// <summary>
|
||||
/// This function is undocumented
|
||||
@ -35,7 +34,7 @@
|
||||
/// <param name="mode">The mode.</param>
|
||||
/// <returns>Unkown</returns>
|
||||
[DllImport(WiringPiLibrary, EntryPoint = "wiringPiSPISetupMode", SetLastError = true)]
|
||||
public static extern int WiringPiSPISetupMode(int channel, int speed, int mode);
|
||||
public static extern Int32 WiringPiSPISetupMode(Int32 channel, Int32 speed, Int32 mode);
|
||||
|
||||
/// <summary>
|
||||
/// This is the way to initialize a channel (The Pi has 2 channels; 0 and 1). The speed parameter is an integer
|
||||
@ -46,7 +45,7 @@
|
||||
/// <param name="speed">The speed.</param>
|
||||
/// <returns>The Linux file descriptor for the device or -1 for error</returns>
|
||||
[DllImport(WiringPiLibrary, EntryPoint = "wiringPiSPISetup", SetLastError = true)]
|
||||
public static extern int WiringPiSPISetup(int channel, int speed);
|
||||
public static extern Int32 WiringPiSPISetup(Int32 channel, Int32 speed);
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
@ -1,16 +1,14 @@
|
||||
namespace Unosquare.RaspberryIO.Native
|
||||
{
|
||||
using System;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Unosquare.RaspberryIO.Native {
|
||||
/// <summary>
|
||||
/// Provides native C WiringPi Library function call wrappers
|
||||
/// All credit for the native library goes to the author of http://wiringpi.com/
|
||||
/// The wrappers were written based on https://github.com/WiringPi/WiringPi/blob/master/wiringPi/wiringPi.h
|
||||
/// </summary>
|
||||
public partial class WiringPi
|
||||
{
|
||||
internal const string WiringPiLibrary = "libwiringPi.so.2.46";
|
||||
public partial class WiringPi {
|
||||
internal const String WiringPiLibrary = "libwiringPi.so.2.46";
|
||||
|
||||
#region WiringPi - Core Functions (https://github.com/WiringPi/WiringPi/blob/master/wiringPi/wiringPi.h)
|
||||
|
||||
@ -22,7 +20,7 @@
|
||||
/// </summary>
|
||||
/// <returns>The result code</returns>
|
||||
[DllImport(WiringPiLibrary, EntryPoint = "wiringPiSetup", SetLastError = true)]
|
||||
public static extern int WiringPiSetup();
|
||||
public static extern Int32 WiringPiSetup();
|
||||
|
||||
/// <summary>
|
||||
/// This initialises wiringPi but uses the /sys/class/gpio interface rather than accessing the hardware directly.
|
||||
@ -37,7 +35,7 @@
|
||||
/// </summary>
|
||||
/// <returns>The result code</returns>
|
||||
[DllImport(WiringPiLibrary, EntryPoint = "wiringPiSetupSys", SetLastError = true)]
|
||||
public static extern int WiringPiSetupSys();
|
||||
public static extern Int32 WiringPiSetupSys();
|
||||
|
||||
/// <summary>
|
||||
/// This is identical to wiringPiSetup, however it allows the calling programs to use the Broadcom GPIO
|
||||
@ -47,7 +45,7 @@
|
||||
/// </summary>
|
||||
/// <returns>The result code</returns>
|
||||
[DllImport(WiringPiLibrary, EntryPoint = "wiringPiSetupGpio", SetLastError = true)]
|
||||
public static extern int WiringPiSetupGpio();
|
||||
public static extern Int32 WiringPiSetupGpio();
|
||||
|
||||
/// <summary>
|
||||
/// Identical to wiringPiSetup, however it allows the calling programs to use the physical pin numbers on the P1 connector only.
|
||||
@ -55,7 +53,7 @@
|
||||
/// </summary>
|
||||
/// <returns>The result code</returns>
|
||||
[DllImport(WiringPiLibrary, EntryPoint = "wiringPiSetupPhys", SetLastError = true)]
|
||||
public static extern int WiringPiSetupPhys();
|
||||
public static extern Int32 WiringPiSetupPhys();
|
||||
|
||||
/// <summary>
|
||||
/// This function is undocumented
|
||||
@ -63,7 +61,7 @@
|
||||
/// <param name="pin">The pin.</param>
|
||||
/// <param name="mode">The mode.</param>
|
||||
[DllImport(WiringPiLibrary, EntryPoint = "pinModeAlt", SetLastError = true)]
|
||||
public static extern void PinModeAlt(int pin, int mode);
|
||||
public static extern void PinModeAlt(Int32 pin, Int32 mode);
|
||||
|
||||
/// <summary>
|
||||
/// This sets the mode of a pin to either INPUT, OUTPUT, PWM_OUTPUT or GPIO_CLOCK.
|
||||
@ -76,7 +74,7 @@
|
||||
/// <param name="pin">The pin.</param>
|
||||
/// <param name="mode">The mode.</param>
|
||||
[DllImport(WiringPiLibrary, EntryPoint = "pinMode", SetLastError = true)]
|
||||
public static extern void PinMode(int pin, int mode);
|
||||
public static extern void PinMode(Int32 pin, Int32 mode);
|
||||
|
||||
/// <summary>
|
||||
/// This sets the pull-up or pull-down resistor mode on the given pin, which should be set as an input.
|
||||
@ -90,7 +88,7 @@
|
||||
/// <param name="pin">The pin.</param>
|
||||
/// <param name="pud">The pud.</param>
|
||||
[DllImport(WiringPiLibrary, EntryPoint = "pullUpDnControl", SetLastError = true)]
|
||||
public static extern void PullUpDnControl(int pin, int pud);
|
||||
public static extern void PullUpDnControl(Int32 pin, Int32 pud);
|
||||
|
||||
/// <summary>
|
||||
/// This function returns the value read at the given pin. It will be HIGH or LOW (1 or 0) depending on the logic level at the pin.
|
||||
@ -98,7 +96,7 @@
|
||||
/// <param name="pin">The pin.</param>
|
||||
/// <returns>The result code</returns>
|
||||
[DllImport(WiringPiLibrary, EntryPoint = "digitalRead", SetLastError = true)]
|
||||
public static extern int DigitalRead(int pin);
|
||||
public static extern Int32 DigitalRead(Int32 pin);
|
||||
|
||||
/// <summary>
|
||||
/// Writes the value HIGH or LOW (1 or 0) to the given pin which must have been previously set as an output.
|
||||
@ -107,7 +105,7 @@
|
||||
/// <param name="pin">The pin.</param>
|
||||
/// <param name="value">The value.</param>
|
||||
[DllImport(WiringPiLibrary, EntryPoint = "digitalWrite", SetLastError = true)]
|
||||
public static extern void DigitalWrite(int pin, int value);
|
||||
public static extern void DigitalWrite(Int32 pin, Int32 value);
|
||||
|
||||
/// <summary>
|
||||
/// Writes the value to the PWM register for the given pin. The Raspberry Pi has one
|
||||
@ -118,7 +116,7 @@
|
||||
/// <param name="pin">The pin.</param>
|
||||
/// <param name="value">The value.</param>
|
||||
[DllImport(WiringPiLibrary, EntryPoint = "pwmWrite", SetLastError = true)]
|
||||
public static extern void PwmWrite(int pin, int value);
|
||||
public static extern void PwmWrite(Int32 pin, Int32 value);
|
||||
|
||||
/// <summary>
|
||||
/// This returns the value read on the supplied analog input pin. You will need to
|
||||
@ -127,7 +125,7 @@
|
||||
/// <param name="pin">The pin.</param>
|
||||
/// <returns>The result code</returns>
|
||||
[DllImport(WiringPiLibrary, EntryPoint = "analogRead", SetLastError = true)]
|
||||
public static extern int AnalogRead(int pin);
|
||||
public static extern Int32 AnalogRead(Int32 pin);
|
||||
|
||||
/// <summary>
|
||||
/// This writes the given value to the supplied analog pin. You will need to register additional
|
||||
@ -136,7 +134,7 @@
|
||||
/// <param name="pin">The pin.</param>
|
||||
/// <param name="value">The value.</param>
|
||||
[DllImport(WiringPiLibrary, EntryPoint = "analogWrite", SetLastError = true)]
|
||||
public static extern void AnalogWrite(int pin, int value);
|
||||
public static extern void AnalogWrite(Int32 pin, Int32 value);
|
||||
|
||||
/// <summary>
|
||||
/// This returns the board revision of the Raspberry Pi. It will be either 1 or 2. Some of the BCM_GPIO pins changed number and
|
||||
@ -144,7 +142,7 @@
|
||||
/// </summary>
|
||||
/// <returns>The result code</returns>
|
||||
[DllImport(WiringPiLibrary, EntryPoint = "piBoardRev", SetLastError = true)]
|
||||
public static extern int PiBoardRev();
|
||||
public static extern Int32 PiBoardRev();
|
||||
|
||||
/// <summary>
|
||||
/// This function is undocumented
|
||||
@ -155,7 +153,7 @@
|
||||
/// <param name="overVolted">The over volted.</param>
|
||||
/// <returns>The result code</returns>
|
||||
[DllImport(WiringPiLibrary, EntryPoint = "piBoardId", SetLastError = true)]
|
||||
public static extern int PiBoardId(ref int model, ref int mem, ref int maker, ref int overVolted);
|
||||
public static extern Int32 PiBoardId(ref Int32 model, ref Int32 mem, ref Int32 maker, ref Int32 overVolted);
|
||||
|
||||
/// <summary>
|
||||
/// This returns the BCM_GPIO pin number of the supplied wiringPi pin. It takes the board revision into account.
|
||||
@ -163,7 +161,7 @@
|
||||
/// <param name="wPiPin">The w pi pin.</param>
|
||||
/// <returns>The result code</returns>
|
||||
[DllImport(WiringPiLibrary, EntryPoint = "wpiPinToGpio", SetLastError = true)]
|
||||
public static extern int WpiPinToGpio(int wPiPin);
|
||||
public static extern Int32 WpiPinToGpio(Int32 wPiPin);
|
||||
|
||||
/// <summary>
|
||||
/// This returns the BCM_GPIO pin number of the supplied physical pin on the P1 connector.
|
||||
@ -171,7 +169,7 @@
|
||||
/// <param name="physPin">The physical pin.</param>
|
||||
/// <returns>The result code</returns>
|
||||
[DllImport(WiringPiLibrary, EntryPoint = "physPinToGpio", SetLastError = true)]
|
||||
public static extern int PhysPinToGpio(int physPin);
|
||||
public static extern Int32 PhysPinToGpio(Int32 physPin);
|
||||
|
||||
/// <summary>
|
||||
/// This sets the “strength” of the pad drivers for a particular group of pins.
|
||||
@ -181,7 +179,7 @@
|
||||
/// <param name="value">The value.</param>
|
||||
/// <returns>The result code</returns>
|
||||
[DllImport(WiringPiLibrary, EntryPoint = "setPadDrive", SetLastError = true)]
|
||||
public static extern int SetPadDrive(int group, int value);
|
||||
public static extern Int32 SetPadDrive(Int32 group, Int32 value);
|
||||
|
||||
/// <summary>
|
||||
/// Undocumented function
|
||||
@ -189,7 +187,7 @@
|
||||
/// <param name="pin">The pin.</param>
|
||||
/// <returns>The result code</returns>
|
||||
[DllImport(WiringPiLibrary, EntryPoint = "getAlt", SetLastError = true)]
|
||||
public static extern int GetAlt(int pin);
|
||||
public static extern Int32 GetAlt(Int32 pin);
|
||||
|
||||
/// <summary>
|
||||
/// Undocumented function
|
||||
@ -198,7 +196,7 @@
|
||||
/// <param name="freq">The freq.</param>
|
||||
/// <returns>The result code</returns>
|
||||
[DllImport(WiringPiLibrary, EntryPoint = "pwmToneWrite", SetLastError = true)]
|
||||
public static extern int PwmToneWrite(int pin, int freq);
|
||||
public static extern Int32 PwmToneWrite(Int32 pin, Int32 freq);
|
||||
|
||||
/// <summary>
|
||||
/// This writes the 8-bit byte supplied to the first 8 GPIO pins.
|
||||
@ -206,7 +204,7 @@
|
||||
/// </summary>
|
||||
/// <param name="value">The value.</param>
|
||||
[DllImport(WiringPiLibrary, EntryPoint = "digitalWriteByte", SetLastError = true)]
|
||||
public static extern void DigitalWriteByte(int value);
|
||||
public static extern void DigitalWriteByte(Int32 value);
|
||||
|
||||
/// <summary>
|
||||
/// This writes the 8-bit byte supplied to the first 8 GPIO pins.
|
||||
@ -214,7 +212,7 @@
|
||||
/// </summary>
|
||||
/// <param name="value">The value.</param>
|
||||
[DllImport(WiringPiLibrary, EntryPoint = "digitalWriteByte2", SetLastError = true)]
|
||||
public static extern void DigitalWriteByte2(int value);
|
||||
public static extern void DigitalWriteByte2(Int32 value);
|
||||
|
||||
/// <summary>
|
||||
/// Undocumented function
|
||||
@ -223,7 +221,7 @@
|
||||
/// </summary>
|
||||
/// <returns>The result code</returns>
|
||||
[DllImport(WiringPiLibrary, EntryPoint = "digitalReadByte", SetLastError = true)]
|
||||
public static extern uint DigitalReadByte();
|
||||
public static extern UInt32 DigitalReadByte();
|
||||
|
||||
/// <summary>
|
||||
/// Undocumented function
|
||||
@ -232,7 +230,7 @@
|
||||
/// </summary>
|
||||
/// <returns>The result code</returns>
|
||||
[DllImport(WiringPiLibrary, EntryPoint = "digitalReadByte2", SetLastError = true)]
|
||||
public static extern uint DigitalReadByte2();
|
||||
public static extern UInt32 DigitalReadByte2();
|
||||
|
||||
/// <summary>
|
||||
/// The PWM generator can run in 2 modes – “balanced” and “mark:space”. The mark:space mode is traditional,
|
||||
@ -240,14 +238,14 @@
|
||||
/// </summary>
|
||||
/// <param name="mode">The mode.</param>
|
||||
[DllImport(WiringPiLibrary, EntryPoint = "pwmSetMode", SetLastError = true)]
|
||||
public static extern void PwmSetMode(int mode);
|
||||
public static extern void PwmSetMode(Int32 mode);
|
||||
|
||||
/// <summary>
|
||||
/// This sets the range register in the PWM generator. The default is 1024.
|
||||
/// </summary>
|
||||
/// <param name="range">The range.</param>
|
||||
[DllImport(WiringPiLibrary, EntryPoint = "pwmSetRange", SetLastError = true)]
|
||||
public static extern void PwmSetRange(uint range);
|
||||
public static extern void PwmSetRange(UInt32 range);
|
||||
|
||||
/// <summary>
|
||||
/// This sets the divisor for the PWM clock.
|
||||
@ -256,7 +254,7 @@
|
||||
/// </summary>
|
||||
/// <param name="divisor">The divisor.</param>
|
||||
[DllImport(WiringPiLibrary, EntryPoint = "pwmSetClock", SetLastError = true)]
|
||||
public static extern void PwmSetClock(int divisor);
|
||||
public static extern void PwmSetClock(Int32 divisor);
|
||||
|
||||
/// <summary>
|
||||
/// Undocumented function
|
||||
@ -264,7 +262,7 @@
|
||||
/// <param name="pin">The pin.</param>
|
||||
/// <param name="freq">The freq.</param>
|
||||
[DllImport(WiringPiLibrary, EntryPoint = "gpioClockSet", SetLastError = true)]
|
||||
public static extern void GpioClockSet(int pin, int freq);
|
||||
public static extern void GpioClockSet(Int32 pin, Int32 freq);
|
||||
|
||||
/// <summary>
|
||||
/// Note: Jan 2013: The waitForInterrupt() function is deprecated – you should use the newer and easier to use wiringPiISR() function below.
|
||||
@ -281,7 +279,7 @@
|
||||
/// <returns>The result code</returns>
|
||||
[Obsolete]
|
||||
[DllImport(WiringPiLibrary, EntryPoint = "waitForInterrupt", SetLastError = true)]
|
||||
public static extern int WaitForInterrupt(int pin, int timeout);
|
||||
public static extern Int32 WaitForInterrupt(Int32 pin, Int32 timeout);
|
||||
|
||||
/// <summary>
|
||||
/// This function registers a function to received interrupts on the specified pin.
|
||||
@ -302,7 +300,7 @@
|
||||
/// <param name="method">The method.</param>
|
||||
/// <returns>The result code</returns>
|
||||
[DllImport(WiringPiLibrary, EntryPoint = "wiringPiISR", SetLastError = true)]
|
||||
public static extern int WiringPiISR(int pin, int mode, InterruptServiceRoutineCallback method);
|
||||
public static extern Int32 WiringPiISR(Int32 pin, Int32 mode, InterruptServiceRoutineCallback method);
|
||||
|
||||
/// <summary>
|
||||
/// This function creates a thread which is another function in your program previously declared using the PI_THREAD declaration.
|
||||
@ -313,7 +311,7 @@
|
||||
/// <param name="method">The method.</param>
|
||||
/// <returns>The result code</returns>
|
||||
[DllImport(WiringPiLibrary, EntryPoint = "piThreadCreate", SetLastError = true)]
|
||||
public static extern int PiThreadCreate(ThreadWorker method);
|
||||
public static extern Int32 PiThreadCreate(ThreadWorker method);
|
||||
|
||||
/// <summary>
|
||||
/// These allow you to synchronise variable updates from your main program to any threads running in your program. keyNum is a number from 0 to 3 and represents a key.
|
||||
@ -324,7 +322,7 @@
|
||||
/// </summary>
|
||||
/// <param name="key">The key.</param>
|
||||
[DllImport(WiringPiLibrary, EntryPoint = "piLock", SetLastError = true)]
|
||||
public static extern void PiLock(int key);
|
||||
public static extern void PiLock(Int32 key);
|
||||
|
||||
/// <summary>
|
||||
/// These allow you to synchronise variable updates from your main program to any threads running in your program. keyNum is a number from 0 to 3 and represents a key.
|
||||
@ -335,7 +333,7 @@
|
||||
/// </summary>
|
||||
/// <param name="key">The key.</param>
|
||||
[DllImport(WiringPiLibrary, EntryPoint = "piUnlock", SetLastError = true)]
|
||||
public static extern void PiUnlock(int key);
|
||||
public static extern void PiUnlock(Int32 key);
|
||||
|
||||
/// <summary>
|
||||
/// This attempts to shift your program (or thread in a multi-threaded program) to a higher priority
|
||||
@ -350,7 +348,7 @@
|
||||
/// <param name="priority">The priority.</param>
|
||||
/// <returns>The result code</returns>
|
||||
[DllImport(WiringPiLibrary, EntryPoint = "piHiPri", SetLastError = true)]
|
||||
public static extern int PiHiPri(int priority);
|
||||
public static extern Int32 PiHiPri(Int32 priority);
|
||||
|
||||
/// <summary>
|
||||
/// This causes program execution to pause for at least howLong milliseconds.
|
||||
@ -359,7 +357,7 @@
|
||||
/// </summary>
|
||||
/// <param name="howLong">The how long.</param>
|
||||
[DllImport(WiringPiLibrary, EntryPoint = "delay", SetLastError = true)]
|
||||
public static extern void Delay(uint howLong);
|
||||
public static extern void Delay(UInt32 howLong);
|
||||
|
||||
/// <summary>
|
||||
/// This causes program execution to pause for at least howLong microseconds.
|
||||
@ -371,7 +369,7 @@
|
||||
/// </summary>
|
||||
/// <param name="howLong">The how long.</param>
|
||||
[DllImport(WiringPiLibrary, EntryPoint = "delayMicroseconds", SetLastError = true)]
|
||||
public static extern void DelayMicroseconds(uint howLong);
|
||||
public static extern void DelayMicroseconds(UInt32 howLong);
|
||||
|
||||
/// <summary>
|
||||
/// This returns a number representing the number of milliseconds since your program called one of the wiringPiSetup functions.
|
||||
@ -379,7 +377,7 @@
|
||||
/// </summary>
|
||||
/// <returns>The result code</returns>
|
||||
[DllImport(WiringPiLibrary, EntryPoint = "millis", SetLastError = true)]
|
||||
public static extern uint Millis();
|
||||
public static extern UInt32 Millis();
|
||||
|
||||
/// <summary>
|
||||
/// This returns a number representing the number of microseconds since your program called one of
|
||||
@ -387,7 +385,7 @@
|
||||
/// </summary>
|
||||
/// <returns>The result code</returns>
|
||||
[DllImport(WiringPiLibrary, EntryPoint = "micros", SetLastError = true)]
|
||||
public static extern uint Micros();
|
||||
public static extern UInt32 Micros();
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
@ -1,26 +1,23 @@
|
||||
namespace Unosquare.RaspberryIO
|
||||
{
|
||||
using Camera;
|
||||
using Computer;
|
||||
using Gpio;
|
||||
using Native;
|
||||
using Unosquare.RaspberryIO.Camera;
|
||||
using Unosquare.RaspberryIO.Computer;
|
||||
using Unosquare.RaspberryIO.Gpio;
|
||||
using Unosquare.RaspberryIO.Native;
|
||||
using System.Threading.Tasks;
|
||||
using Swan.Components;
|
||||
using Unosquare.Swan.Components;
|
||||
using System;
|
||||
|
||||
namespace Unosquare.RaspberryIO {
|
||||
/// <summary>
|
||||
/// Our main character. Provides access to the Raspberry Pi's GPIO, system and board information and Camera
|
||||
/// </summary>
|
||||
public static class Pi
|
||||
{
|
||||
private static readonly object SyncLock = new object();
|
||||
public static class Pi {
|
||||
private static readonly Object SyncLock = new Object();
|
||||
|
||||
/// <summary>
|
||||
/// Initializes static members of the <see cref="Pi" /> class.
|
||||
/// </summary>
|
||||
static Pi()
|
||||
{
|
||||
lock (SyncLock)
|
||||
{
|
||||
static Pi() {
|
||||
lock(SyncLock) {
|
||||
// Extraction of embedded resources
|
||||
Resources.EmbeddedResources.ExtractAll();
|
||||
|
||||
@ -40,42 +37,56 @@
|
||||
/// <summary>
|
||||
/// Provides access to the Raspberry Pi's GPIO as a collection of GPIO Pins.
|
||||
/// </summary>
|
||||
public static GpioController Gpio { get; }
|
||||
public static GpioController Gpio {
|
||||
get;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provides information on this Raspberry Pi's CPU and form factor.
|
||||
/// </summary>
|
||||
public static SystemInfo Info { get; }
|
||||
public static SystemInfo Info {
|
||||
get;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provides access to The PI's Timing and threading API
|
||||
/// </summary>
|
||||
public static Timing Timing { get; }
|
||||
public static Timing Timing {
|
||||
get;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provides access to the 2-channel SPI bus
|
||||
/// </summary>
|
||||
public static SpiBus Spi { get; }
|
||||
public static SpiBus Spi {
|
||||
get;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provides access to the functionality of the i2c bus.
|
||||
/// </summary>
|
||||
public static I2CBus I2C { get; }
|
||||
public static I2CBus I2C {
|
||||
get;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provides access to the official Raspberry Pi Camera
|
||||
/// </summary>
|
||||
public static CameraController Camera { get; }
|
||||
public static CameraController Camera {
|
||||
get;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Provides access to the official Raspberry Pi 7-inch DSI Display
|
||||
/// </summary>
|
||||
public static DsiDisplay PiDisplay { get; }
|
||||
public static DsiDisplay PiDisplay {
|
||||
get;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the logger source name.
|
||||
/// </summary>
|
||||
internal static string LoggerSource => typeof(Pi).Namespace;
|
||||
internal static String LoggerSource => typeof(Pi).Namespace;
|
||||
|
||||
#endregion
|
||||
|
||||
|
@ -1,24 +1,18 @@
|
||||
namespace Unosquare.RaspberryIO.Resources
|
||||
{
|
||||
using Native;
|
||||
using Swan;
|
||||
using Unosquare.RaspberryIO.Native;
|
||||
using Unosquare.Swan;
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.IO;
|
||||
|
||||
namespace Unosquare.RaspberryIO.Resources {
|
||||
/// <summary>
|
||||
/// Provides access to embedded assembly files
|
||||
/// </summary>
|
||||
internal static class EmbeddedResources
|
||||
{
|
||||
internal static class EmbeddedResources {
|
||||
/// <summary>
|
||||
/// Initializes static members of the <see cref="EmbeddedResources"/> class.
|
||||
/// </summary>
|
||||
static EmbeddedResources()
|
||||
{
|
||||
ResourceNames =
|
||||
new ReadOnlyCollection<string>(typeof(EmbeddedResources).Assembly().GetManifestResourceNames());
|
||||
}
|
||||
static EmbeddedResources() => ResourceNames = new ReadOnlyCollection<String>(typeof(EmbeddedResources).Assembly().GetManifestResourceNames());
|
||||
|
||||
/// <summary>
|
||||
/// Gets the resource names.
|
||||
@ -26,36 +20,32 @@
|
||||
/// <value>
|
||||
/// The resource names.
|
||||
/// </value>
|
||||
public static ReadOnlyCollection<string> ResourceNames { get; }
|
||||
public static ReadOnlyCollection<String> ResourceNames {
|
||||
get;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Extracts all the file resources to the specified base path.
|
||||
/// </summary>
|
||||
public static void ExtractAll()
|
||||
{
|
||||
var basePath = Runtime.EntryAssemblyDirectory;
|
||||
var executablePermissions = Standard.StringToInteger("0777", IntPtr.Zero, 8);
|
||||
public static void ExtractAll() {
|
||||
String basePath = Runtime.EntryAssemblyDirectory;
|
||||
Int32 executablePermissions = Standard.StringToInteger("0777", IntPtr.Zero, 8);
|
||||
|
||||
foreach (var resourceName in ResourceNames)
|
||||
{
|
||||
var filename = resourceName.Substring($"{typeof(EmbeddedResources).Namespace}.".Length);
|
||||
var targetPath = Path.Combine(basePath, filename);
|
||||
if (File.Exists(targetPath)) return;
|
||||
foreach(String resourceName in ResourceNames) {
|
||||
String filename = resourceName.Substring($"{typeof(EmbeddedResources).Namespace}.".Length);
|
||||
String targetPath = Path.Combine(basePath, filename);
|
||||
if(File.Exists(targetPath)) {
|
||||
return;
|
||||
}
|
||||
|
||||
using (var stream = typeof(EmbeddedResources).Assembly()
|
||||
.GetManifestResourceStream($"{typeof(EmbeddedResources).Namespace}.{filename}"))
|
||||
{
|
||||
using (var outputStream = File.OpenWrite(targetPath))
|
||||
{
|
||||
using(Stream stream = typeof(EmbeddedResources).Assembly().GetManifestResourceStream($"{typeof(EmbeddedResources).Namespace}.{filename}")) {
|
||||
using(FileStream outputStream = File.OpenWrite(targetPath)) {
|
||||
stream?.CopyTo(outputStream);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Standard.Chmod(targetPath, (uint)executablePermissions);
|
||||
}
|
||||
catch
|
||||
{
|
||||
try {
|
||||
_ = Standard.Chmod(targetPath, (UInt32)executablePermissions);
|
||||
} catch {
|
||||
/* Ignore */
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user