Coding styles

This commit is contained in:
BlubbFish 2019-12-03 18:43:54 +01:00
parent d75c3bc73f
commit 186792fde8
37 changed files with 5871 additions and 6009 deletions

View File

@ -1,23 +1,20 @@
namespace Unosquare.RaspberryIO.Camera using Unosquare.Swan;
{
using Swan;
using System; using System;
using System.Linq; using System.Linq;
namespace Unosquare.RaspberryIO.Camera {
/// <summary> /// <summary>
/// A simple RGB color class to represent colors in RGB and YUV colorspaces. /// A simple RGB color class to represent colors in RGB and YUV colorspaces.
/// </summary> /// </summary>
public class CameraColor public class CameraColor {
{
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="CameraColor"/> class. /// Initializes a new instance of the <see cref="CameraColor"/> class.
/// </summary> /// </summary>
/// <param name="r">The red.</param> /// <param name="r">The red.</param>
/// <param name="g">The green.</param> /// <param name="g">The green.</param>
/// <param name="b">The blue.</param> /// <param name="b">The blue.</param>
public CameraColor(int r, int g, int b) public CameraColor(Int32 r, Int32 g, Int32 b)
: this(r, g, b, string.Empty) : this(r, g, b, String.Empty) {
{
} }
/// <summary> /// <summary>
@ -27,16 +24,15 @@
/// <param name="g">The green.</param> /// <param name="g">The green.</param>
/// <param name="b">The blue.</param> /// <param name="b">The blue.</param>
/// <param name="name">The well-known color name.</param> /// <param name="name">The well-known color name.</param>
public CameraColor(int r, int g, int b, string name) 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)) };
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); Single y = this.R * .299000f + this.G * .587000f + this.B * .114000f;
var u = (R * -.168736f) + (G * -.331264f) + (B * .500000f) + 128f; Single u = this.R * -.168736f + this.G * -.331264f + this.B * .500000f + 128f;
var v = (R * .500000f) + (G * -.418688f) + (B * -.081312f) + 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) }; this.YUV = new Byte[] { (Byte)y.Clamp(0, 255), (Byte)u.Clamp(0, 255), (Byte)v.Clamp(0, 255) };
Name = name; this.Name = name;
} }
#region Static Definitions #region Static Definitions
@ -71,32 +67,38 @@
/// <summary> /// <summary>
/// Gets the well-known color name. /// Gets the well-known color name.
/// </summary> /// </summary>
public string Name { get; } public String Name {
get;
}
/// <summary> /// <summary>
/// Gets the red byte. /// Gets the red byte.
/// </summary> /// </summary>
public byte R => RGB[0]; public Byte R => this.RGB[0];
/// <summary> /// <summary>
/// Gets the green byte. /// Gets the green byte.
/// </summary> /// </summary>
public byte G => RGB[1]; public Byte G => this.RGB[1];
/// <summary> /// <summary>
/// Gets the blue byte. /// Gets the blue byte.
/// </summary> /// </summary>
public byte B => RGB[2]; public Byte B => this.RGB[2];
/// <summary> /// <summary>
/// Gets the RGB byte array (3 bytes). /// Gets the RGB byte array (3 bytes).
/// </summary> /// </summary>
public byte[] RGB { get; } public Byte[] RGB {
get;
}
/// <summary> /// <summary>
/// Gets the YUV byte array (3 bytes). /// Gets the YUV byte array (3 bytes).
/// </summary> /// </summary>
public byte[] YUV { get; } public Byte[] YUV {
get;
}
/// <summary> /// <summary>
/// Returns a hexadecimal representation of the RGB byte array. /// Returns a hexadecimal representation of the RGB byte array.
@ -104,10 +106,12 @@
/// </summary> /// </summary>
/// <param name="reverse">if set to <c>true</c> [reverse].</param> /// <param name="reverse">if set to <c>true</c> [reverse].</param>
/// <returns>A string</returns> /// <returns>A string</returns>
public string ToRgbHex(bool reverse) public String ToRgbHex(Boolean reverse) {
{ Byte[] data = this.RGB.ToArray();
var data = RGB.ToArray(); if(reverse) {
if (reverse) Array.Reverse(data); Array.Reverse(data);
}
return ToHex(data); return ToHex(data);
} }
@ -117,10 +121,12 @@
/// </summary> /// </summary>
/// <param name="reverse">if set to <c>true</c> [reverse].</param> /// <param name="reverse">if set to <c>true</c> [reverse].</param>
/// <returns>A string</returns> /// <returns>A string</returns>
public string ToYuvHex(bool reverse) public String ToYuvHex(Boolean reverse) {
{ Byte[] data = this.YUV.ToArray();
var data = YUV.ToArray(); if(reverse) {
if (reverse) Array.Reverse(data); Array.Reverse(data);
}
return ToHex(data); return ToHex(data);
} }
@ -129,6 +135,6 @@
/// </summary> /// </summary>
/// <param name="data">The data.</param> /// <param name="data">The data.</param>
/// <returns>A string</returns> /// <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()}";
} }
} }

View File

@ -1,22 +1,20 @@
namespace Unosquare.RaspberryIO.Camera using Unosquare.Swan.Abstractions;
{
using Swan.Abstractions;
using System; using System;
using Swan.Components; using Unosquare.Swan.Components;
using System.IO; using System.IO;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Unosquare.RaspberryIO.Camera {
/// <summary> /// <summary>
/// The Raspberry Pi's camera controller wrapping raspistill and raspivid programs. /// The Raspberry Pi's camera controller wrapping raspistill and raspivid programs.
/// This class is a singleton /// This class is a singleton
/// </summary> /// </summary>
public class CameraController : SingletonBase<CameraController> public class CameraController : SingletonBase<CameraController> {
{
#region Private Declarations #region Private Declarations
private static readonly ManualResetEventSlim OperationDone = new ManualResetEventSlim(true); 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 CancellationTokenSource _videoTokenSource = new CancellationTokenSource();
private static Task<Task> _videoStreamTask; private static Task<Task> _videoStreamTask;
@ -30,7 +28,7 @@
/// <value> /// <value>
/// <c>true</c> if this instance is busy; otherwise, <c>false</c>. /// <c>true</c> if this instance is busy; otherwise, <c>false</c>.
/// </value> /// </value>
public bool IsBusy => OperationDone.IsSet == false; public Boolean IsBusy => OperationDone.IsSet == false;
#endregion #endregion
@ -43,34 +41,30 @@
/// <param name="ct">The ct.</param> /// <param name="ct">The ct.</param>
/// <returns>The image bytes</returns> /// <returns>The image bytes</returns>
/// <exception cref="InvalidOperationException">Cannot use camera module because it is currently busy.</exception> /// <exception cref="InvalidOperationException">Cannot use camera module because it is currently busy.</exception>
public async Task<byte[]> CaptureImageAsync(CameraStillSettings settings, CancellationToken ct = default) [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) if(Instance.IsBusy) {
throw new InvalidOperationException("Cannot use camera module because it is currently busy."); 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"); throw new ArgumentException($"{nameof(settings.CaptureTimeoutMilliseconds)} needs to be greater than 0");
}
try try {
{
OperationDone.Reset(); OperationDone.Reset();
var output = new MemoryStream(); MemoryStream output = new MemoryStream();
var exitCode = await ProcessRunner.RunProcessAsync( Int32 exitCode = await ProcessRunner.RunProcessAsync(
settings.CommandName, settings.CommandName,
settings.CreateProcessArguments(), settings.CreateProcessArguments(),
(data, proc) => (data, proc) => output.Write(data, 0, data.Length),
{
output.Write(data, 0, data.Length);
},
null, null,
true, true,
ct); ct);
return exitCode != 0 ? new byte[] { } : output.ToArray(); return exitCode != 0 ? new Byte[] { } : output.ToArray();
} } finally {
finally
{
OperationDone.Set(); OperationDone.Set();
} }
} }
@ -80,10 +74,7 @@
/// </summary> /// </summary>
/// <param name="settings">The settings.</param> /// <param name="settings">The settings.</param>
/// <returns>The image bytes</returns> /// <returns>The image bytes</returns>
public byte[] CaptureImage(CameraStillSettings settings) public Byte[] CaptureImage(CameraStillSettings settings) => this.CaptureImageAsync(settings).GetAwaiter().GetResult();
{
return CaptureImageAsync(settings).GetAwaiter().GetResult();
}
/// <summary> /// <summary>
/// Captures a JPEG encoded image asynchronously at 90% quality. /// Captures a JPEG encoded image asynchronously at 90% quality.
@ -92,17 +83,15 @@
/// <param name="height">The height.</param> /// <param name="height">The height.</param>
/// <param name="ct">The ct.</param> /// <param name="ct">The ct.</param>
/// <returns>The image bytes</returns> /// <returns>The image bytes</returns>
public Task<byte[]> CaptureImageJpegAsync(int width, int height, CancellationToken ct = default) public Task<Byte[]> CaptureImageJpegAsync(Int32 width, Int32 height, CancellationToken ct = default) {
{ CameraStillSettings settings = new CameraStillSettings {
var settings = new CameraStillSettings
{
CaptureWidth = width, CaptureWidth = width,
CaptureHeight = height, CaptureHeight = height,
CaptureJpegQuality = 90, CaptureJpegQuality = 90,
CaptureTimeoutMilliseconds = 300, CaptureTimeoutMilliseconds = 300,
}; };
return CaptureImageAsync(settings, ct); return this.CaptureImageAsync(settings, ct);
} }
/// <summary> /// <summary>
@ -111,7 +100,7 @@
/// <param name="width">The width.</param> /// <param name="width">The width.</param>
/// <param name="height">The height.</param> /// <param name="height">The height.</param>
/// <returns>The image bytes</returns> /// <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 #endregion
@ -123,17 +112,15 @@
/// </summary> /// </summary>
/// <param name="onDataCallback">The on data callback.</param> /// <param name="onDataCallback">The on data callback.</param>
/// <param name="onExitCallback">The on exit callback.</param> /// <param name="onExitCallback">The on exit callback.</param>
public void OpenVideoStream(Action<byte[]> onDataCallback, Action onExitCallback = null) public void OpenVideoStream(Action<Byte[]> onDataCallback, Action onExitCallback = null) {
{ CameraVideoSettings settings = new CameraVideoSettings {
var settings = new CameraVideoSettings
{
CaptureTimeoutMilliseconds = 0, CaptureTimeoutMilliseconds = 0,
CaptureDisplayPreview = false, CaptureDisplayPreview = false,
CaptureWidth = 1920, CaptureWidth = 1920,
CaptureHeight = 1080 CaptureHeight = 1080
}; };
OpenVideoStream(settings, onDataCallback, onExitCallback); this.OpenVideoStream(settings, onDataCallback, onExitCallback);
} }
/// <summary> /// <summary>
@ -144,21 +131,19 @@
/// <param name="onExitCallback">The on exit callback.</param> /// <param name="onExitCallback">The on exit callback.</param>
/// <exception cref="InvalidOperationException">Cannot use camera module because it is currently busy.</exception> /// <exception cref="InvalidOperationException">Cannot use camera module because it is currently busy.</exception>
/// <exception cref="ArgumentException">CaptureTimeoutMilliseconds</exception> /// <exception cref="ArgumentException">CaptureTimeoutMilliseconds</exception>
public void OpenVideoStream(CameraVideoSettings settings, Action<byte[]> onDataCallback, Action onExitCallback) public void OpenVideoStream(CameraVideoSettings settings, Action<Byte[]> onDataCallback, Action onExitCallback) {
{ if(Instance.IsBusy) {
if (Instance.IsBusy)
throw new InvalidOperationException("Cannot use camera module because it is currently busy."); 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"); throw new ArgumentException($"{nameof(settings.CaptureTimeoutMilliseconds)} needs to be greater than or equal to 0");
}
try try {
{
OperationDone.Reset(); OperationDone.Reset();
_videoStreamTask = Task.Factory.StartNew(() => VideoWorkerDoWork(settings, onDataCallback, onExitCallback), _videoTokenSource.Token); _videoStreamTask = Task.Factory.StartNew(() => VideoWorkerDoWork(settings, onDataCallback, onExitCallback), _videoTokenSource.Token);
} } catch {
catch
{
OperationDone.Set(); OperationDone.Set();
throw; throw;
} }
@ -167,16 +152,14 @@
/// <summary> /// <summary>
/// Closes the video stream of a video stream is open. /// Closes the video stream of a video stream is open.
/// </summary> /// </summary>
public void CloseVideoStream() public void CloseVideoStream() {
{ lock(SyncRoot) {
lock (SyncRoot) if(this.IsBusy == false) {
{
if (IsBusy == false)
return; return;
} }
}
if (_videoTokenSource.IsCancellationRequested == false) if(_videoTokenSource.IsCancellationRequested == false) {
{
_videoTokenSource.Cancel(); _videoTokenSource.Cancel();
_videoStreamTask.Wait(); _videoStreamTask.Wait();
} }
@ -184,13 +167,8 @@
_videoTokenSource = new CancellationTokenSource(); _videoTokenSource = new CancellationTokenSource();
} }
private static async Task VideoWorkerDoWork( private static async Task VideoWorkerDoWork(CameraVideoSettings settings, Action<Byte[]> onDataCallback, Action onExitCallback) {
CameraVideoSettings settings, try {
Action<byte[]> onDataCallback,
Action onExitCallback)
{
try
{
await ProcessRunner.RunProcessAsync( await ProcessRunner.RunProcessAsync(
settings.CommandName, settings.CommandName,
settings.CreateProcessArguments(), settings.CreateProcessArguments(),
@ -200,13 +178,9 @@
_videoTokenSource.Token); _videoTokenSource.Token);
onExitCallback?.Invoke(); onExitCallback?.Invoke();
} } catch {
catch
{
// swallow // swallow
} } finally {
finally
{
Instance.CloseVideoStream(); Instance.CloseVideoStream();
OperationDone.Set(); OperationDone.Set();
} }

View File

@ -1,13 +1,12 @@
namespace Unosquare.RaspberryIO.Camera using Unosquare.Swan;
{ using System;
using Swan;
using System.Globalization; using System.Globalization;
namespace Unosquare.RaspberryIO.Camera {
/// <summary> /// <summary>
/// Defines the Raspberry Pi camera's sensor ROI (Region of Interest) /// Defines the Raspberry Pi camera's sensor ROI (Region of Interest)
/// </summary> /// </summary>
public struct CameraRect public struct CameraRect {
{
/// <summary> /// <summary>
/// The default ROI which is the entire area. /// The default ROI which is the entire area.
/// </summary> /// </summary>
@ -19,7 +18,9 @@
/// <value> /// <value>
/// The x. /// The x.
/// </value> /// </value>
public decimal X { get; set; } public Decimal X {
get; set;
}
/// <summary> /// <summary>
/// Gets or sets the y location in relative coordinates. (0.0 to 1.0) /// Gets or sets the y location in relative coordinates. (0.0 to 1.0)
@ -27,7 +28,9 @@
/// <value> /// <value>
/// The y. /// The y.
/// </value> /// </value>
public decimal Y { get; set; } public Decimal Y {
get; set;
}
/// <summary> /// <summary>
/// Gets or sets the width in relative coordinates. (0.0 to 1.0) /// Gets or sets the width in relative coordinates. (0.0 to 1.0)
@ -35,7 +38,9 @@
/// <value> /// <value>
/// The w. /// The w.
/// </value> /// </value>
public decimal W { get; set; } public Decimal W {
get; set;
}
/// <summary> /// <summary>
/// Gets or sets the height in relative coordinates. (0.0 to 1.0) /// Gets or sets the height in relative coordinates. (0.0 to 1.0)
@ -43,7 +48,9 @@
/// <value> /// <value>
/// The h. /// The h.
/// </value> /// </value>
public decimal H { get; set; } public Decimal H {
get; set;
}
/// <summary> /// <summary>
/// Gets a value indicating whether this instance is equal to the default (The entire area). /// Gets a value indicating whether this instance is equal to the default (The entire area).
@ -51,32 +58,29 @@
/// <value> /// <value>
/// <c>true</c> if this instance is default; otherwise, <c>false</c>. /// <c>true</c> if this instance is default; otherwise, <c>false</c>.
/// </value> /// </value>
public bool IsDefault public Boolean IsDefault {
{ get {
get this.Clamp();
{ return this.X == Default.X && this.Y == Default.Y && this.W == Default.W && this.H == Default.H;
Clamp();
return X == Default.X && Y == Default.Y && W == Default.W && H == Default.H;
} }
} }
/// <summary> /// <summary>
/// Clamps the members of this ROI to their minimum and maximum values /// Clamps the members of this ROI to their minimum and maximum values
/// </summary> /// </summary>
public void Clamp() public void Clamp() {
{ this.X = this.X.Clamp(0M, 1M);
X = X.Clamp(0M, 1M); this.Y = this.Y.Clamp(0M, 1M);
Y = Y.Clamp(0M, 1M); this.W = this.W.Clamp(0M, 1M - this.X);
W = W.Clamp(0M, 1M - X); this.H = this.H.Clamp(0M, 1M - this.Y);
H = H.Clamp(0M, 1M - Y);
} }
/// <summary> /// <summary>
/// Returns a <see cref="string" /> that represents this instance. /// Returns a <see cref="String" /> that represents this instance.
/// </summary> /// </summary>
/// <returns> /// <returns>
/// A <see cref="string" /> that represents this instance. /// A <see cref="String" /> that represents this instance.
/// </returns> /// </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)}";
} }
} }

View File

@ -1,16 +1,15 @@
namespace Unosquare.RaspberryIO.Camera using Unosquare.Swan;
{
using Swan;
using System.Globalization; using System.Globalization;
using System.Text; using System.Text;
using System;
namespace Unosquare.RaspberryIO.Camera {
/// <summary> /// <summary>
/// A base class to implement raspistill and raspivid wrappers /// A base class to implement raspistill and raspivid wrappers
/// Full documentation available at /// Full documentation available at
/// https://www.raspberrypi.org/documentation/raspbian/applications/camera.md /// https://www.raspberrypi.org/documentation/raspbian/applications/camera.md
/// </summary> /// </summary>
public abstract class CameraSettingsBase public abstract class CameraSettingsBase {
{
/// <summary> /// <summary>
/// The Invariant Culture shorthand /// The Invariant Culture shorthand
/// </summary> /// </summary>
@ -23,27 +22,27 @@
/// Default value is 5000 /// Default value is 5000
/// Recommended value is at least 300 in order to let the light collectors open /// Recommended value is at least 300 in order to let the light collectors open
/// </summary> /// </summary>
public int CaptureTimeoutMilliseconds { get; set; } = 5000; public Int32 CaptureTimeoutMilliseconds { get; set; } = 5000;
/// <summary> /// <summary>
/// Gets or sets a value indicating whether or not to show a preview window on the screen /// Gets or sets a value indicating whether or not to show a preview window on the screen
/// </summary> /// </summary>
public bool CaptureDisplayPreview { get; set; } = false; public Boolean CaptureDisplayPreview { get; set; } = false;
/// <summary> /// <summary>
/// Gets or sets a value indicating whether a preview window is shown in full screen mode if enabled /// Gets or sets a value indicating whether a preview window is shown in full screen mode if enabled
/// </summary> /// </summary>
public bool CaptureDisplayPreviewInFullScreen { get; set; } = true; public Boolean CaptureDisplayPreviewInFullScreen { get; set; } = true;
/// <summary> /// <summary>
/// Gets or sets a value indicating whether video stabilization should be enabled. /// Gets or sets a value indicating whether video stabilization should be enabled.
/// </summary> /// </summary>
public bool CaptureVideoStabilizationEnabled { get; set; } = false; public Boolean CaptureVideoStabilizationEnabled { get; set; } = false;
/// <summary> /// <summary>
/// Gets or sets the display preview opacity only if the display preview property is enabled. /// Gets or sets the display preview opacity only if the display preview property is enabled.
/// </summary> /// </summary>
public byte CaptureDisplayPreviewOpacity { get; set; } = 255; public Byte CaptureDisplayPreviewOpacity { get; set; } = 255;
/// <summary> /// <summary>
/// Gets or sets the capture sensor region of interest in relative coordinates. /// 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. /// Gets or sets the capture shutter speed in microseconds.
/// Default -1, Range 0 to 6000000 (equivalent to 6 seconds) /// Default -1, Range 0 to 6000000 (equivalent to 6 seconds)
/// </summary> /// </summary>
public int CaptureShutterSpeedMicroseconds { get; set; } = -1; public Int32 CaptureShutterSpeedMicroseconds { get; set; } = -1;
/// <summary> /// <summary>
/// Gets or sets the exposure mode. /// 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; /// 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. /// which one is changed usually depends on the camera's exposure mode.
/// </summary> /// </summary>
public int CaptureExposureCompensation { get; set; } = 0; public Int32 CaptureExposureCompensation { get; set; } = 0;
/// <summary> /// <summary>
/// Gets or sets the capture metering mode. /// Gets or sets the capture metering mode.
@ -85,20 +84,22 @@
/// Only takes effect if White balance control is set to off. /// Only takes effect if White balance control is set to off.
/// Default is 0 /// Default is 0
/// </summary> /// </summary>
public decimal CaptureWhiteBalanceGainBlue { get; set; } = 0M; public Decimal CaptureWhiteBalanceGainBlue { get; set; } = 0M;
/// <summary> /// <summary>
/// Gets or sets the capture white balance gain on the red channel. Example: 1.75 /// 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. /// Only takes effect if White balance control is set to off.
/// Default is 0 /// Default is 0
/// </summary> /// </summary>
public decimal CaptureWhiteBalanceGainRed { get; set; } = 0M; public Decimal CaptureWhiteBalanceGainRed { get; set; } = 0M;
/// <summary> /// <summary>
/// Gets or sets the dynamic range compensation. /// 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. /// 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> /// </summary>
public CameraDynamicRangeCompensation CaptureDynamicRangeCompensation { get; set; } = public CameraDynamicRangeCompensation CaptureDynamicRangeCompensation {
get; set;
} =
CameraDynamicRangeCompensation.Off; CameraDynamicRangeCompensation.Off;
#endregion #endregion
@ -109,39 +110,39 @@
/// Gets or sets the width of the picture to take. /// 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. /// Less than or equal to 0 in either width or height means maximum resolution available.
/// </summary> /// </summary>
public int CaptureWidth { get; set; } = 640; public Int32 CaptureWidth { get; set; } = 640;
/// <summary> /// <summary>
/// Gets or sets the height of the picture to take. /// 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. /// Less than or equal to 0 in either width or height means maximum resolution available.
/// </summary> /// </summary>
public int CaptureHeight { get; set; } = 480; public Int32 CaptureHeight { get; set; } = 480;
/// <summary> /// <summary>
/// Gets or sets the picture sharpness. Default is 0, Range form -100 to 100 /// Gets or sets the picture sharpness. Default is 0, Range form -100 to 100
/// </summary> /// </summary>
public int ImageSharpness { get; set; } = 0; public Int32 ImageSharpness { get; set; } = 0;
/// <summary> /// <summary>
/// Gets or sets the picture contrast. Default is 0, Range form -100 to 100 /// Gets or sets the picture contrast. Default is 0, Range form -100 to 100
/// </summary> /// </summary>
public int ImageContrast { get; set; } = 0; public Int32 ImageContrast { get; set; } = 0;
/// <summary> /// <summary>
/// Gets or sets the picture brightness. Default is 50, Range form 0 to 100 /// Gets or sets the picture brightness. Default is 50, Range form 0 to 100
/// </summary> /// </summary>
public int ImageBrightness { get; set; } = 50; // from 0 to 100 public Int32 ImageBrightness { get; set; } = 50; // from 0 to 100
/// <summary> /// <summary>
/// Gets or sets the picture saturation. Default is 0, Range form -100 to 100 /// Gets or sets the picture saturation. Default is 0, Range form -100 to 100
/// </summary> /// </summary>
public int ImageSaturation { get; set; } = 0; public Int32 ImageSaturation { get; set; } = 0;
/// <summary> /// <summary>
/// Gets or sets the picture ISO. Default is -1 Range is 100 to 800 /// Gets or sets the picture ISO. Default is -1 Range is 100 to 800
/// The higher the value, the more light the sensor absorbs /// The higher the value, the more light the sensor absorbs
/// </summary> /// </summary>
public int ImageIso { get; set; } = -1; public Int32 ImageIso { get; set; } = -1;
/// <summary> /// <summary>
/// Gets or sets the image capture effect to be applied. /// Gets or sets the image capture effect to be applied.
@ -153,14 +154,14 @@
/// Default is -1, Range is 0 to 255 /// Default is -1, Range is 0 to 255
/// 128:128 should be effectively a monochrome image. /// 128:128 should be effectively a monochrome image.
/// </summary> /// </summary>
public int ImageColorEffectU { get; set; } = -1; // 0 to 255 public Int32 ImageColorEffectU { get; set; } = -1; // 0 to 255
/// <summary> /// <summary>
/// Gets or sets the color effect V coordinates. /// Gets or sets the color effect V coordinates.
/// Default is -1, Range is 0 to 255 /// Default is -1, Range is 0 to 255
/// 128:128 should be effectively a monochrome image. /// 128:128 should be effectively a monochrome image.
/// </summary> /// </summary>
public int ImageColorEffectV { get; set; } = -1; // 0 to 255 public Int32 ImageColorEffectV { get; set; } = -1; // 0 to 255
/// <summary> /// <summary>
/// Gets or sets the image rotation. Default is no rotation /// Gets or sets the image rotation. Default is no rotation
@ -170,12 +171,16 @@
/// <summary> /// <summary>
/// Gets or sets a value indicating whether the image should be flipped horizontally. /// Gets or sets a value indicating whether the image should be flipped horizontally.
/// </summary> /// </summary>
public bool ImageFlipHorizontally { get; set; } public Boolean ImageFlipHorizontally {
get; set;
}
/// <summary> /// <summary>
/// Gets or sets a value indicating whether the image should be flipped vertically. /// Gets or sets a value indicating whether the image should be flipped vertically.
/// </summary> /// </summary>
public bool ImageFlipVertically { get; set; } public Boolean ImageFlipVertically {
get; set;
}
/// <summary> /// <summary>
/// Gets or sets the image annotations using a bitmask (or flags) notation. /// 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. /// 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 /// Example: ABC %Y-%m-%d %X will output ABC 2015-10-28 20:09:33
/// </summary> /// </summary>
public string ImageAnnotationsText { get; set; } = string.Empty; public String ImageAnnotationsText { get; set; } = String.Empty;
/// <summary> /// <summary>
/// Gets or sets the font size of the text annotations /// Gets or sets the font size of the text annotations
/// Default is -1, range is 6 to 160 /// Default is -1, range is 6 to 160
/// </summary> /// </summary>
public int ImageAnnotationFontSize { get; set; } = -1; public Int32 ImageAnnotationFontSize { get; set; } = -1;
/// <summary> /// <summary>
/// Gets or sets the color of the text annotations. /// Gets or sets the color of the text annotations.
@ -219,118 +224,134 @@
/// <summary> /// <summary>
/// Gets the command file executable. /// Gets the command file executable.
/// </summary> /// </summary>
public abstract string CommandName { get; } public abstract String CommandName {
get;
}
/// <summary> /// <summary>
/// Creates the process arguments. /// Creates the process arguments.
/// </summary> /// </summary>
/// <returns>The string that represents the process arguments</returns> /// <returns>The string that represents the process arguments</returns>
public virtual string CreateProcessArguments() public virtual String CreateProcessArguments() {
{ StringBuilder sb = new StringBuilder();
var sb = new StringBuilder(); _ = sb.Append("-o -"); // output to standard output as opposed to a file.
sb.Append("-o -"); // output to standard output as opposed to a file. _ = sb.Append($" -t {(this.CaptureTimeoutMilliseconds < 0 ? "0" : this.CaptureTimeoutMilliseconds.ToString(Ci))}");
sb.Append($" -t {(CaptureTimeoutMilliseconds < 0 ? "0" : CaptureTimeoutMilliseconds.ToString(Ci))}");
// Basic Width and height // Basic Width and height
if (CaptureWidth > 0 && CaptureHeight > 0) if(this.CaptureWidth > 0 && this.CaptureHeight > 0) {
{ _ = sb.Append($" -w {this.CaptureWidth.ToString(Ci)}");
sb.Append($" -w {CaptureWidth.ToString(Ci)}"); _ = sb.Append($" -h {this.CaptureHeight.ToString(Ci)}");
sb.Append($" -h {CaptureHeight.ToString(Ci)}");
} }
// Display Preview // Display Preview
if (CaptureDisplayPreview) if(this.CaptureDisplayPreview) {
{ if(this.CaptureDisplayPreviewInFullScreen) {
if (CaptureDisplayPreviewInFullScreen) _ = sb.Append(" -f");
sb.Append(" -f");
if (CaptureDisplayPreviewOpacity != byte.MaxValue)
sb.Append($" -op {CaptureDisplayPreviewOpacity.ToString(Ci)}");
} }
else
{ if(this.CaptureDisplayPreviewOpacity != Byte.MaxValue) {
sb.Append(" -n"); // no preview _ = sb.Append($" -op {this.CaptureDisplayPreviewOpacity.ToString(Ci)}");
}
} else {
_ = sb.Append(" -n"); // no preview
} }
// Picture Settings // Picture Settings
if (ImageSharpness != 0) if(this.ImageSharpness != 0) {
sb.Append($" -sh {ImageSharpness.Clamp(-100, 100).ToString(Ci)}"); _ = sb.Append($" -sh {this.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 (CaptureMeteringMode != CameraMeteringMode.Average) if(this.ImageContrast != 0) {
sb.Append($" -mm {CaptureMeteringMode.ToString().ToLowerInvariant()}"); _ = sb.Append($" -co {this.ImageContrast.Clamp(-100, 100).ToString(Ci)}");
}
if (ImageRotation != CameraImageRotation.None) if(this.ImageBrightness != 50) {
sb.Append($" -rot {((int)ImageRotation).ToString(Ci)}"); _ = sb.Append($" -br {this.ImageBrightness.Clamp(0, 100).ToString(Ci)}");
}
if (ImageFlipHorizontally) if(this.ImageSaturation != 0) {
sb.Append(" -hf"); _ = sb.Append($" -sa {this.ImageSaturation.Clamp(-100, 100).ToString(Ci)}");
}
if (ImageFlipVertically) if(this.ImageIso >= 100) {
sb.Append(" -vf"); _ = sb.Append($" -ISO {this.ImageIso.Clamp(100, 800).ToString(Ci)}");
}
if (CaptureSensorRoi.IsDefault == false) if(this.CaptureVideoStabilizationEnabled) {
sb.Append($" -roi {CaptureSensorRoi}"); _ = sb.Append(" -vs");
}
if (CaptureShutterSpeedMicroseconds > 0) if(this.CaptureExposureCompensation != 0) {
sb.Append($" -ss {CaptureShutterSpeedMicroseconds.Clamp(0, 6000000).ToString(Ci)}"); _ = sb.Append($" -ev {this.CaptureExposureCompensation.Clamp(-10, 10).ToString(Ci)}");
}
if (CaptureDynamicRangeCompensation != CameraDynamicRangeCompensation.Off) if(this.CaptureExposure != CameraExposureMode.Auto) {
sb.Append($" -drc {CaptureDynamicRangeCompensation.ToString().ToLowerInvariant()}"); _ = sb.Append($" -ex {this.CaptureExposure.ToString().ToLowerInvariant()}");
}
if (CaptureWhiteBalanceControl == CameraWhiteBalanceMode.Off && if(this.CaptureWhiteBalanceControl != CameraWhiteBalanceMode.Auto) {
(CaptureWhiteBalanceGainBlue != 0M || CaptureWhiteBalanceGainRed != 0M)) _ = sb.Append($" -awb {this.CaptureWhiteBalanceControl.ToString().ToLowerInvariant()}");
sb.Append($" -awbg {CaptureWhiteBalanceGainBlue.ToString(Ci)},{CaptureWhiteBalanceGainRed.ToString(Ci)}"); }
if (ImageAnnotationFontSize > 0) if(this.ImageEffect != CameraImageEffect.None) {
{ _ = sb.Append($" -ifx {this.ImageEffect.ToString().ToLowerInvariant()}");
sb.Append($" -ae {ImageAnnotationFontSize.Clamp(6, 160).ToString(Ci)}"); }
sb.Append($",{(ImageAnnotationFontColor == null ? "0xff" : ImageAnnotationFontColor.ToYuvHex(true))}");
if (ImageAnnotationBackground != null) if(this.ImageColorEffectU >= 0 && this.ImageColorEffectV >= 0) {
{ _ = sb.Append(
ImageAnnotations |= CameraAnnotation.SolidBackground; $" -cfx {this.ImageColorEffectU.Clamp(0, 255).ToString(Ci)}:{this.ImageColorEffectV.Clamp(0, 255).ToString(Ci)}");
sb.Append($",{ImageAnnotationBackground.ToYuvHex(true)}"); }
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) if(this.ImageAnnotations != CameraAnnotation.None) {
sb.Append($" -a {((int)ImageAnnotations).ToString(Ci)}"); _ = sb.Append($" -a {((Int32)this.ImageAnnotations).ToString(Ci)}");
}
if (string.IsNullOrWhiteSpace(ImageAnnotationsText) == false) if(String.IsNullOrWhiteSpace(this.ImageAnnotationsText) == false) {
sb.Append($" -a \"{ImageAnnotationsText.Replace("\"", "'")}\""); _ = sb.Append($" -a \"{this.ImageAnnotationsText.Replace("\"", "'")}\"");
}
return sb.ToString(); return sb.ToString();
} }

View File

@ -1,26 +1,24 @@
namespace Unosquare.RaspberryIO.Camera using Unosquare.Swan;
{
using Swan;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; using System.Text;
namespace Unosquare.RaspberryIO.Camera {
/// <summary> /// <summary>
/// Defines a wrapper for the raspistill program and its settings (command-line arguments) /// Defines a wrapper for the raspistill program and its settings (command-line arguments)
/// </summary> /// </summary>
/// <seealso cref="CameraSettingsBase" /> /// <seealso cref="CameraSettingsBase" />
public class CameraStillSettings : CameraSettingsBase public class CameraStillSettings : CameraSettingsBase {
{ private Int32 _rotate;
private int _rotate;
/// <inheritdoc /> /// <inheritdoc />
public override string CommandName => "raspistill"; public override String CommandName => "raspistill";
/// <summary> /// <summary>
/// Gets or sets a value indicating whether the preview window (if enabled) uses native capture resolution /// Gets or sets a value indicating whether the preview window (if enabled) uses native capture resolution
/// This may slow down preview FPS /// This may slow down preview FPS
/// </summary> /// </summary>
public bool CaptureDisplayPreviewAtResolution { get; set; } = false; public Boolean CaptureDisplayPreviewAtResolution { get; set; } = false;
/// <summary> /// <summary>
/// Gets or sets the encoding format the hardware will use for the output. /// 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. /// Gets or sets the quality for JPEG only encoding mode.
/// Value ranges from 0 to 100 /// Value ranges from 0 to 100
/// </summary> /// </summary>
public int CaptureJpegQuality { get; set; } = 90; public Int32 CaptureJpegQuality { get; set; } = 90;
/// <summary> /// <summary>
/// Gets or sets a value indicating whether the JPEG encoder should add raw bayer metadata. /// Gets or sets a value indicating whether the JPEG encoder should add raw bayer metadata.
/// </summary> /// </summary>
public bool CaptureJpegIncludeRawBayerMetadata { get; set; } = false; public Boolean CaptureJpegIncludeRawBayerMetadata { get; set; } = false;
/// <summary> /// <summary>
/// JPEG EXIF data /// JPEG EXIF data
/// Keys and values must be already properly escaped. Otherwise the command will fail. /// Keys and values must be already properly escaped. Otherwise the command will fail.
/// </summary> /// </summary>
public Dictionary<string, string> CaptureJpegExtendedInfo { get; } = new Dictionary<string, string>(); public Dictionary<String, String> CaptureJpegExtendedInfo { get; } = new Dictionary<String, String>();
/// <summary> /// <summary>
/// Gets or sets a value indicating whether [horizontal flip]. /// Gets or sets a value indicating whether [horizontal flip].
@ -50,7 +48,7 @@
/// <value> /// <value>
/// <c>true</c> if [horizontal flip]; otherwise, <c>false</c>. /// <c>true</c> if [horizontal flip]; otherwise, <c>false</c>.
/// </value> /// </value>
public bool HorizontalFlip { get; set; } = false; public Boolean HorizontalFlip { get; set; } = false;
/// <summary> /// <summary>
/// Gets or sets a value indicating whether [vertical flip]. /// Gets or sets a value indicating whether [vertical flip].
@ -58,61 +56,64 @@
/// <value> /// <value>
/// <c>true</c> if [vertical flip]; otherwise, <c>false</c>. /// <c>true</c> if [vertical flip]; otherwise, <c>false</c>.
/// </value> /// </value>
public bool VerticalFlip { get; set; } = false; public Boolean VerticalFlip { get; set; } = false;
/// <summary> /// <summary>
/// Gets or sets the rotation. /// Gets or sets the rotation.
/// </summary> /// </summary>
/// <exception cref="ArgumentOutOfRangeException">Valid range 0-359</exception> /// <exception cref="ArgumentOutOfRangeException">Valid range 0-359</exception>
public int Rotation public Int32 Rotation {
{ get => this._rotate;
get => _rotate; set {
set if(value < 0 || value > 359) {
{
if (value < 0 || value > 359)
{
throw new ArgumentOutOfRangeException(nameof(value), "Valid range 0-359"); throw new ArgumentOutOfRangeException(nameof(value), "Valid range 0-359");
} }
_rotate = value; this._rotate = value;
} }
} }
/// <inheritdoc /> /// <inheritdoc />
public override string CreateProcessArguments() public override String CreateProcessArguments() {
{ StringBuilder sb = new StringBuilder(base.CreateProcessArguments());
var sb = new StringBuilder(base.CreateProcessArguments()); _ = sb.Append($" -e {this.CaptureEncoding.ToString().ToLowerInvariant()}");
sb.Append($" -e {CaptureEncoding.ToString().ToLowerInvariant()}");
// JPEG Encoder specific arguments // JPEG Encoder specific arguments
if (CaptureEncoding == CameraImageEncodingFormat.Jpg) if(this.CaptureEncoding == CameraImageEncodingFormat.Jpg) {
{ _ = sb.Append($" -q {this.CaptureJpegQuality.Clamp(0, 100).ToString(Ci)}");
sb.Append($" -q {CaptureJpegQuality.Clamp(0, 100).ToString(Ci)}");
if (CaptureJpegIncludeRawBayerMetadata) if(this.CaptureJpegIncludeRawBayerMetadata) {
sb.Append(" -r"); _ = sb.Append(" -r");
}
// JPEG EXIF data // JPEG EXIF data
if (CaptureJpegExtendedInfo.Count > 0) if(this.CaptureJpegExtendedInfo.Count > 0) {
{ foreach(KeyValuePair<String, String> kvp in this.CaptureJpegExtendedInfo) {
foreach (var kvp in CaptureJpegExtendedInfo) if(String.IsNullOrWhiteSpace(kvp.Key) || String.IsNullOrWhiteSpace(kvp.Value)) {
{
if (string.IsNullOrWhiteSpace(kvp.Key) || string.IsNullOrWhiteSpace(kvp.Value))
continue; continue;
}
sb.Append($" -x \"{kvp.Key.Replace("\"", "'")}={kvp.Value.Replace("\"", "'")}\""); _ = sb.Append($" -x \"{kvp.Key.Replace("\"", "'")}={kvp.Value.Replace("\"", "'")}\"");
} }
} }
} }
// Display preview settings // 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(); return sb.ToString();
} }

View File

@ -1,43 +1,42 @@
namespace Unosquare.RaspberryIO.Camera using Unosquare.Swan;
{ using System;
using Swan;
using System.Text; using System.Text;
namespace Unosquare.RaspberryIO.Camera {
/// <summary> /// <summary>
/// Represents the raspivid camera settings for video capture functionality /// Represents the raspivid camera settings for video capture functionality
/// </summary> /// </summary>
/// <seealso cref="CameraSettingsBase" /> /// <seealso cref="CameraSettingsBase" />
public class CameraVideoSettings : CameraSettingsBase public class CameraVideoSettings : CameraSettingsBase {
{
/// <inheritdoc /> /// <inheritdoc />
public override string CommandName => "raspivid"; public override String CommandName => "raspivid";
/// <summary> /// <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. /// 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. /// Maximum bitrate is 25Mbits/s (-b 25000000), but much over 17Mbits/s won't show noticeable improvement at 1080p30.
/// Default -1 /// Default -1
/// </summary> /// </summary>
public int CaptureBitrate { get; set; } = -1; public Int32 CaptureBitrate { get; set; } = -1;
/// <summary> /// <summary>
/// Gets or sets the framerate. /// Gets or sets the framerate.
/// Default 25, range 2 to 30 /// Default 25, range 2 to 30
/// </summary> /// </summary>
public int CaptureFramerate { get; set; } = 25; public Int32 CaptureFramerate { get; set; } = 25;
/// <summary> /// <summary>
/// Sets the intra refresh period (GoP) rate for the recorded video. H264 video uses a complete frame (I-frame) every intra /// 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. /// 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. /// Larger numbers here will reduce the size of the resulting video, and smaller numbers make the stream less error-prone.
/// </summary> /// </summary>
public int CaptureKeyframeRate { get; set; } = 25; public Int32 CaptureKeyframeRate { get; set; } = 25;
/// <summary> /// <summary>
/// Sets the initial quantisation parameter for the stream. Varies from approximately 10 to 40, and will greatly affect /// 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 /// 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. /// bitrate of 0 to set a completely variable bitrate.
/// </summary> /// </summary>
public int CaptureQuantisation { get; set; } = 23; public Int32 CaptureQuantisation { get; set; } = 23;
/// <summary> /// <summary>
/// Gets or sets the profile. /// Gets or sets the profile.
@ -53,7 +52,7 @@
/// <value> /// <value>
/// <c>true</c> if [interleave headers]; otherwise, <c>false</c>. /// <c>true</c> if [interleave headers]; otherwise, <c>false</c>.
/// </value> /// </value>
public bool CaptureInterleaveHeaders { get; set; } = true; public Boolean CaptureInterleaveHeaders { get; set; } = true;
/// <summary> /// <summary>
/// Switch on an option to display the preview after compression. This will show any compression artefacts in the preview window. In normal operation, /// 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> /// <value>
/// <c>true</c> if [capture display preview encoded]; otherwise, <c>false</c>. /// <c>true</c> if [capture display preview encoded]; otherwise, <c>false</c>.
/// </value> /// </value>
public bool CaptureDisplayPreviewEncoded { get; set; } = false; public Boolean CaptureDisplayPreviewEncoded { get; set; } = false;
/// <inheritdoc /> /// <inheritdoc />
public override string CreateProcessArguments() public override String CreateProcessArguments() {
{ StringBuilder sb = new StringBuilder(base.CreateProcessArguments());
var sb = new StringBuilder(base.CreateProcessArguments());
sb.Append($" -pf {CaptureProfile.ToString().ToLowerInvariant()}"); _ = sb.Append($" -pf {this.CaptureProfile.ToString().ToLowerInvariant()}");
if (CaptureBitrate < 0) if(this.CaptureBitrate < 0) {
sb.Append($" -b {CaptureBitrate.Clamp(0, 25000000).ToString(Ci)}"); _ = sb.Append($" -b {this.CaptureBitrate.Clamp(0, 25000000).ToString(Ci)}");
}
if (CaptureFramerate >= 2) if(this.CaptureFramerate >= 2) {
sb.Append($" -fps {CaptureFramerate.Clamp(2, 30).ToString(Ci)}"); _ = sb.Append($" -fps {this.CaptureFramerate.Clamp(2, 30).ToString(Ci)}");
}
if (CaptureDisplayPreview && CaptureDisplayPreviewEncoded) if(this.CaptureDisplayPreview && this.CaptureDisplayPreviewEncoded) {
sb.Append(" -e"); _ = sb.Append(" -e");
}
if (CaptureKeyframeRate > 0) if(this.CaptureKeyframeRate > 0) {
sb.Append($" -g {CaptureKeyframeRate.ToString(Ci)}"); _ = sb.Append($" -g {this.CaptureKeyframeRate.ToString(Ci)}");
}
if (CaptureQuantisation >= 0) if(this.CaptureQuantisation >= 0) {
sb.Append($" -qp {CaptureQuantisation.Clamp(0, 40).ToString(Ci)}"); _ = sb.Append($" -qp {this.CaptureQuantisation.Clamp(0, 40).ToString(Ci)}");
}
if (CaptureInterleaveHeaders) if(this.CaptureInterleaveHeaders) {
sb.Append(" -ih"); _ = sb.Append(" -ih");
}
return sb.ToString(); return sb.ToString();
} }

View File

@ -1,12 +1,10 @@
namespace Unosquare.RaspberryIO.Camera using System;
{
using System;
namespace Unosquare.RaspberryIO.Camera {
/// <summary> /// <summary>
/// Defines the available encoding formats for the Raspberry Pi camera module /// Defines the available encoding formats for the Raspberry Pi camera module
/// </summary> /// </summary>
public enum CameraImageEncodingFormat public enum CameraImageEncodingFormat {
{
/// <summary> /// <summary>
/// The JPG /// The JPG
/// </summary> /// </summary>
@ -31,8 +29,7 @@
/// <summary> /// <summary>
/// Defines the different exposure modes for the Raspberry Pi's camera module /// Defines the different exposure modes for the Raspberry Pi's camera module
/// </summary> /// </summary>
public enum CameraExposureMode public enum CameraExposureMode {
{
/// <summary> /// <summary>
/// The automatic /// The automatic
/// </summary> /// </summary>
@ -97,8 +94,7 @@
/// <summary> /// <summary>
/// Defines the different AWB (Auto White Balance) modes for the Raspberry Pi's camera module /// Defines the different AWB (Auto White Balance) modes for the Raspberry Pi's camera module
/// </summary> /// </summary>
public enum CameraWhiteBalanceMode public enum CameraWhiteBalanceMode {
{
/// <summary> /// <summary>
/// No white balance /// No white balance
/// </summary> /// </summary>
@ -153,8 +149,7 @@
/// <summary> /// <summary>
/// Defines the available image effects for the Raspberry Pi's camera module /// Defines the available image effects for the Raspberry Pi's camera module
/// </summary> /// </summary>
public enum CameraImageEffect public enum CameraImageEffect {
{
/// <summary> /// <summary>
/// No effect /// No effect
/// </summary> /// </summary>
@ -264,8 +259,7 @@
/// <summary> /// <summary>
/// Defines the different metering modes for the Raspberry Pi's camera module /// Defines the different metering modes for the Raspberry Pi's camera module
/// </summary> /// </summary>
public enum CameraMeteringMode public enum CameraMeteringMode {
{
/// <summary> /// <summary>
/// The average /// The average
/// </summary> /// </summary>
@ -290,8 +284,7 @@
/// <summary> /// <summary>
/// Defines the different image rotation modes for the Raspberry Pi's camera module /// Defines the different image rotation modes for the Raspberry Pi's camera module
/// </summary> /// </summary>
public enum CameraImageRotation public enum CameraImageRotation {
{
/// <summary> /// <summary>
/// No rerotation /// No rerotation
/// </summary> /// </summary>
@ -317,8 +310,7 @@
/// Defines the different DRC (Dynamic Range Compensation) modes for the Raspberry Pi's camera module /// Defines the different DRC (Dynamic Range Compensation) modes for the Raspberry Pi's camera module
/// Helpful for low light photos /// Helpful for low light photos
/// </summary> /// </summary>
public enum CameraDynamicRangeCompensation public enum CameraDynamicRangeCompensation {
{
/// <summary> /// <summary>
/// The off setting /// The off setting
/// </summary> /// </summary>
@ -344,8 +336,7 @@
/// Defines the bit-wise mask flags for the available annotation elements for the Raspberry Pi's camera module /// Defines the bit-wise mask flags for the available annotation elements for the Raspberry Pi's camera module
/// </summary> /// </summary>
[Flags] [Flags]
public enum CameraAnnotation public enum CameraAnnotation {
{
/// <summary> /// <summary>
/// The none /// The none
/// </summary> /// </summary>
@ -400,8 +391,7 @@
/// <summary> /// <summary>
/// Defines the different H.264 encoding profiles to be used when capturing video. /// Defines the different H.264 encoding profiles to be used when capturing video.
/// </summary> /// </summary>
public enum CameraH264Profile public enum CameraH264Profile {
{
/// <summary> /// <summary>
/// BP: Primarily for lower-cost applications with limited computing resources, /// BP: Primarily for lower-cost applications with limited computing resources,
/// this profile is used widely in videoconferencing and mobile applications. /// this profile is used widely in videoconferencing and mobile applications.

View File

@ -1,24 +1,22 @@
namespace Unosquare.RaspberryIO.Computer using Unosquare.Swan.Abstractions;
{
using Swan.Abstractions;
using System.Globalization; using System.Globalization;
using System.IO; using System.IO;
using System;
namespace Unosquare.RaspberryIO.Computer {
/// <summary> /// <summary>
/// The Official Raspberry Pi 7-inch touch display from the foundation /// The Official Raspberry Pi 7-inch touch display from the foundation
/// Some docs available here: /// Some docs available here:
/// http://forums.pimoroni.com/t/official-7-raspberry-pi-touch-screen-faq/959 /// http://forums.pimoroni.com/t/official-7-raspberry-pi-touch-screen-faq/959
/// </summary> /// </summary>
public class DsiDisplay : SingletonBase<DsiDisplay> public class DsiDisplay : SingletonBase<DsiDisplay> {
{ private const String BacklightFilename = "/sys/class/backlight/rpi_backlight/bl_power";
private const string BacklightFilename = "/sys/class/backlight/rpi_backlight/bl_power"; private const String BrightnessFilename = "/sys/class/backlight/rpi_backlight/brightness";
private const string BrightnessFilename = "/sys/class/backlight/rpi_backlight/brightness";
/// <summary> /// <summary>
/// Prevents a default instance of the <see cref="DsiDisplay"/> class from being created. /// Prevents a default instance of the <see cref="DsiDisplay"/> class from being created.
/// </summary> /// </summary>
private DsiDisplay() private DsiDisplay() {
{
// placeholder // placeholder
} }
@ -28,7 +26,7 @@
/// <value> /// <value>
/// <c>true</c> if this instance is present; otherwise, <c>false</c>. /// <c>true</c> if this instance is present; otherwise, <c>false</c>.
/// </value> /// </value>
public bool IsPresent => File.Exists(BrightnessFilename); public Boolean IsPresent => File.Exists(BrightnessFilename);
/// <summary> /// <summary>
/// Gets or sets the brightness of the DSI display via filesystem. /// Gets or sets the brightness of the DSI display via filesystem.
@ -36,17 +34,13 @@
/// <value> /// <value>
/// The brightness. /// The brightness.
/// </value> /// </value>
public byte Brightness public Byte Brightness {
{ get => this.IsPresent == false ? (Byte)0 : Byte.TryParse(File.ReadAllText(BrightnessFilename).Trim(), out Byte brightness) ? brightness : (Byte)0;
get set {
{ if(this.IsPresent == false) {
if (IsPresent == false) return 0; return;
return byte.TryParse(File.ReadAllText(BrightnessFilename).Trim(), out var brightness) ? brightness : (byte)0;
} }
set
{
if (IsPresent == false) return;
File.WriteAllText(BrightnessFilename, value.ToString(CultureInfo.InvariantCulture)); File.WriteAllText(BrightnessFilename, value.ToString(CultureInfo.InvariantCulture));
} }
} }
@ -58,20 +52,12 @@
/// <value> /// <value>
/// <c>true</c> if this instance is backlight on; otherwise, <c>false</c>. /// <c>true</c> if this instance is backlight on; otherwise, <c>false</c>.
/// </value> /// </value>
public bool IsBacklightOn public Boolean IsBacklightOn {
{ get => this.IsPresent == false ? false : Int32.TryParse(File.ReadAllText(BacklightFilename).Trim(), out Int32 backlight) ? backlight == 0 : false;
get set {
{ if(this.IsPresent == false) {
if (IsPresent == false) return false; return;
if (int.TryParse(File.ReadAllText(BacklightFilename).Trim(), out var backlight))
return backlight == 0;
return false;
} }
set
{
if (IsPresent == false) return;
File.WriteAllText(BacklightFilename, value ? "0" : "1"); File.WriteAllText(BacklightFilename, value ? "0" : "1");
} }

View File

@ -1,40 +1,51 @@
namespace Unosquare.RaspberryIO.Computer using System;
{
using System.Net; using System.Net;
namespace Unosquare.RaspberryIO.Computer {
/// <summary> /// <summary>
/// Represents a Network Adapter /// Represents a Network Adapter
/// </summary> /// </summary>
public class NetworkAdapterInfo public class NetworkAdapterInfo {
{
/// <summary> /// <summary>
/// Gets the name. /// Gets the name.
/// </summary> /// </summary>
public string Name { get; internal set; } public String Name {
get; internal set;
}
/// <summary> /// <summary>
/// Gets the IP V4 address. /// Gets the IP V4 address.
/// </summary> /// </summary>
public IPAddress IPv4 { get; internal set; } public IPAddress IPv4 {
get; internal set;
}
/// <summary> /// <summary>
/// Gets the IP V6 address. /// Gets the IP V6 address.
/// </summary> /// </summary>
public IPAddress IPv6 { get; internal set; } public IPAddress IPv6 {
get; internal set;
}
/// <summary> /// <summary>
/// Gets the name of the access point. /// Gets the name of the access point.
/// </summary> /// </summary>
public string AccessPointName { get; internal set; } public String AccessPointName {
get; internal set;
}
/// <summary> /// <summary>
/// Gets the MAC (Physical) address. /// Gets the MAC (Physical) address.
/// </summary> /// </summary>
public string MacAddress { get; internal set; } public String MacAddress {
get; internal set;
}
/// <summary> /// <summary>
/// Gets a value indicating whether this instance is wireless. /// Gets a value indicating whether this instance is wireless.
/// </summary> /// </summary>
public bool IsWireless { get; internal set; } public Boolean IsWireless {
get; internal set;
}
} }
} }

View File

@ -1,8 +1,6 @@
namespace Unosquare.RaspberryIO.Computer using Unosquare.Swan;
{ using Unosquare.Swan.Abstractions;
using Swan; using Unosquare.Swan.Components;
using Swan.Abstractions;
using Swan.Components;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
@ -10,86 +8,85 @@
using System.Net; using System.Net;
using System.Text; using System.Text;
namespace Unosquare.RaspberryIO.Computer {
/// <summary> /// <summary>
/// Represents the network information /// Represents the network information
/// </summary> /// </summary>
public class NetworkSettings : SingletonBase<NetworkSettings> public class NetworkSettings : SingletonBase<NetworkSettings> {
{ private const String EssidTag = "ESSID:";
private const string EssidTag = "ESSID:";
/// <summary> /// <summary>
/// Gets the local machine Host Name. /// Gets the local machine Host Name.
/// </summary> /// </summary>
public string HostName => Network.HostName; public String HostName => Network.HostName;
/// <summary> /// <summary>
/// Retrieves the wireless networks. /// Retrieves the wireless networks.
/// </summary> /// </summary>
/// <param name="adapter">The adapter.</param> /// <param name="adapter">The adapter.</param>
/// <returns>A list of WiFi networks</returns> /// <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> /// <summary>
/// Retrieves the wireless networks. /// Retrieves the wireless networks.
/// </summary> /// </summary>
/// <param name="adapters">The adapters.</param> /// <param name="adapters">The adapters.</param>
/// <returns>A list of WiFi networks</returns> /// <returns>A list of WiFi networks</returns>
public List<WirelessNetworkInfo> RetrieveWirelessNetworks(string[] adapters = null) public List<WirelessNetworkInfo> RetrieveWirelessNetworks(String[] adapters = null) {
{ List<WirelessNetworkInfo> result = new List<WirelessNetworkInfo>();
var result = new List<WirelessNetworkInfo>();
foreach (var networkAdapter in adapters ?? RetrieveAdapters().Where(x => x.IsWireless).Select(x => x.Name)) foreach(String networkAdapter in adapters ?? this.RetrieveAdapters().Where(x => x.IsWireless).Select(x => x.Name)) {
{ String wirelessOutput = ProcessRunner.GetProcessOutputAsync("iwlist", $"{networkAdapter} scanning").Result;
var wirelessOutput = ProcessRunner.GetProcessOutputAsync("iwlist", $"{networkAdapter} scanning").Result; String[] outputLines =
var outputLines =
wirelessOutput.Split('\n') wirelessOutput.Split('\n')
.Select(x => x.Trim()) .Select(x => x.Trim())
.Where(x => string.IsNullOrWhiteSpace(x) == false) .Where(x => String.IsNullOrWhiteSpace(x) == false)
.ToArray(); .ToArray();
for (var i = 0; i < outputLines.Length; i++) for(Int32 i = 0; i < outputLines.Length; i++) {
{ String line = outputLines[i];
var line = outputLines[i];
if (line.StartsWith(EssidTag) == false) continue; if(line.StartsWith(EssidTag) == false) {
continue;
}
var network = new WirelessNetworkInfo() WirelessNetworkInfo network = new WirelessNetworkInfo() {
{ Name = line.Replace(EssidTag, String.Empty).Replace("\"", String.Empty)
Name = line.Replace(EssidTag, string.Empty).Replace("\"", string.Empty)
}; };
while (true) while(true) {
{ if(i + 1 >= outputLines.Length) {
if (i + 1 >= outputLines.Length) break; break;
}
// should look for two lines before the ESSID acording to the scan // should look for two lines before the ESSID acording to the scan
line = outputLines[i - 2]; line = outputLines[i - 2];
if (line.StartsWith("Quality=")) if(line.StartsWith("Quality=")) {
{ network.Quality = line.Replace("Quality=", String.Empty);
network.Quality = line.Replace("Quality=", string.Empty);
break; break;
} }
} }
while (true) while(true) {
{ if(i + 1 >= outputLines.Length) {
if (i + 1 >= outputLines.Length) break; break;
}
// should look for a line before the ESSID acording to the scan // should look for a line before the ESSID acording to the scan
line = outputLines[i - 1]; line = outputLines[i - 1];
if (line.StartsWith("Encryption key:")) if(line.StartsWith("Encryption key:")) {
{ network.IsEncrypted = line.Replace("Encryption key:", String.Empty).Trim() == "on";
network.IsEncrypted = line.Replace("Encryption key:", string.Empty).Trim() == "on";
break; break;
} }
} }
if (result.Any(x => x.Name == network.Name) == false) if(result.Any(x => x.Name == network.Name) == false) {
result.Add(network); result.Add(network);
} }
} }
}
return result.OrderBy(x => x.Name).ToList(); return result.OrderBy(x => x.Name).ToList();
} }
@ -102,22 +99,18 @@
/// <param name="password">The password.</param> /// <param name="password">The password.</param>
/// <param name="countryCode">The 2-letter country code in uppercase. Default is US.</param> /// <param name="countryCode">The 2-letter country code in uppercase. Default is US.</param>
/// <returns>True if successful. Otherwise, false.</returns> /// <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 // 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"; String payload = $"country={countryCode}\nctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev\nupdate_config=1\n";
payload += string.IsNullOrEmpty(password) payload += String.IsNullOrEmpty(password)
? $"network={{\n\tssid=\"{networkSsid}\"\n\t}}\n" ? $"network={{\n\tssid=\"{networkSsid}\"\n\t}}\n"
: $"network={{\n\tssid=\"{networkSsid}\"\n\tpsk=\"{password}\"\n\t}}\n"; : $"network={{\n\tssid=\"{networkSsid}\"\n\tpsk=\"{password}\"\n\t}}\n";
try try {
{
File.WriteAllText("/etc/wpa_supplicant/wpa_supplicant.conf", payload); File.WriteAllText("/etc/wpa_supplicant/wpa_supplicant.conf", payload);
ProcessRunner.GetProcessOutputAsync("pkill", "-f wpa_supplicant").Wait(); ProcessRunner.GetProcessOutputAsync("pkill", "-f wpa_supplicant").Wait();
ProcessRunner.GetProcessOutputAsync("ifdown", adapterName).Wait(); ProcessRunner.GetProcessOutputAsync("ifdown", adapterName).Wait();
ProcessRunner.GetProcessOutputAsync("ifup", adapterName).Wait(); ProcessRunner.GetProcessOutputAsync("ifup", adapterName).Wait();
} } catch(Exception ex) {
catch (Exception ex)
{
ex.Log(nameof(NetworkSettings)); ex.Log(nameof(NetworkSettings));
return false; return false;
} }
@ -129,99 +122,92 @@
/// Retrieves the network adapters. /// Retrieves the network adapters.
/// </summary> /// </summary>
/// <returns>A list of network adapters.</returns> /// <returns>A list of network adapters.</returns>
public List<NetworkAdapterInfo> RetrieveAdapters() public List<NetworkAdapterInfo> RetrieveAdapters() {
{ const String hWaddr = "HWaddr ";
const string hWaddr = "HWaddr "; const String ether = "ether ";
const string ether = "ether ";
var result = new List<NetworkAdapterInfo>(); List<NetworkAdapterInfo> result = new List<NetworkAdapterInfo>();
var interfacesOutput = ProcessRunner.GetProcessOutputAsync("ifconfig").Result; String interfacesOutput = ProcessRunner.GetProcessOutputAsync("ifconfig").Result;
var wlanOutput = ProcessRunner.GetProcessOutputAsync("iwconfig") String[] wlanOutput = ProcessRunner.GetProcessOutputAsync("iwconfig")
.Result.Split('\n') .Result.Split('\n')
.Where(x => x.Contains("no wireless extensions.") == false) .Where(x => x.Contains("no wireless extensions.") == false)
.ToArray(); .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 // grab the current line
var line = outputLines[i]; String line = outputLines[i];
// skip if the line is indented // skip if the line is indented
if (char.IsLetterOrDigit(line[0]) == false) if(Char.IsLetterOrDigit(line[0]) == false) {
continue; continue;
}
// Read the line as an adatper // Read the line as an adatper
var adapter = new NetworkAdapterInfo NetworkAdapterInfo adapter = new NetworkAdapterInfo {
{
Name = line.Substring(0, line.IndexOf(' ')).TrimEnd(':') Name = line.Substring(0, line.IndexOf(' ')).TrimEnd(':')
}; };
// Parse the MAC address in old version of ifconfig; it comes in the first line // Parse the MAC address in old version of ifconfig; it comes in the first line
if (line.IndexOf(hWaddr) >= 0) if(line.IndexOf(hWaddr) >= 0) {
{ Int32 startIndexHwd = line.IndexOf(hWaddr) + hWaddr.Length;
var startIndexHwd = line.IndexOf(hWaddr) + hWaddr.Length;
adapter.MacAddress = line.Substring(startIndexHwd, 17).Trim(); adapter.MacAddress = line.Substring(startIndexHwd, 17).Trim();
} }
// Parse the info in lines other than the first // 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 // Get the contents of the indented line
var indentedLine = outputLines[j]; String indentedLine = outputLines[j];
// We have hit the next adapter info // We have hit the next adapter info
if (char.IsLetterOrDigit(indentedLine[0])) if(Char.IsLetterOrDigit(indentedLine[0])) {
{
i = j - 1; i = j - 1;
break; break;
} }
// Parse the MAC address in new versions of ifconfig; it no longer comes in the first line // 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)) if(indentedLine.IndexOf(ether) >= 0 && String.IsNullOrWhiteSpace(adapter.MacAddress)) {
{ Int32 startIndexHwd = indentedLine.IndexOf(ether) + ether.Length;
var startIndexHwd = indentedLine.IndexOf(ether) + ether.Length;
adapter.MacAddress = indentedLine.Substring(startIndexHwd, 17).Trim(); adapter.MacAddress = indentedLine.Substring(startIndexHwd, 17).Trim();
} }
// Parse the IPv4 Address // 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(addressText != null) {
{ if(IPAddress.TryParse(addressText, out IPAddress outValue)) {
if (IPAddress.TryParse(addressText, out var outValue))
adapter.IPv4 = outValue; adapter.IPv4 = outValue;
} }
} }
}
// Parse the IPv6 Address // 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(addressText != null) {
{ if(IPAddress.TryParse(addressText, out IPAddress outValue)) {
if (IPAddress.TryParse(addressText, out var outValue))
adapter.IPv6 = outValue; adapter.IPv6 = outValue;
} }
} }
}
// we have hit the end of the output in an indented line // 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; i = outputLines.Length;
} }
}
// Retrieve the wireless LAN info // 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; adapter.IsWireless = true;
var essidParts = wlanInfo.Split(new[] { EssidTag }, StringSplitOptions.RemoveEmptyEntries); String[] essidParts = wlanInfo.Split(new[] { EssidTag }, StringSplitOptions.RemoveEmptyEntries);
if (essidParts.Length >= 2) if(essidParts.Length >= 2) {
{ adapter.AccessPointName = essidParts[1].Replace("\"", String.Empty).Trim();
adapter.AccessPointName = essidParts[1].Replace("\"", string.Empty).Trim();
} }
} }
@ -236,7 +222,7 @@
/// Retrieves current wireless connected network name. /// Retrieves current wireless connected network name.
/// </summary> /// </summary>
/// <returns>The connected network name.</returns> /// <returns>The connected network name.</returns>
public string GetWirelessNetworkName() => ProcessRunner.GetProcessOutputAsync("iwgetid", "-r").Result; public String GetWirelessNetworkName() => ProcessRunner.GetProcessOutputAsync("iwgetid", "-r").Result;
/// <summary> /// <summary>
/// Parses the output tag from the given line. /// Parses the output tag from the given line.
@ -244,20 +230,20 @@
/// <param name="indentedLine">The indented line.</param> /// <param name="indentedLine">The indented line.</param>
/// <param name="tagName">Name of the tag.</param> /// <param name="tagName">Name of the tag.</param>
/// <returns>The value after the tag identifier</returns> /// <returns>The value after the tag identifier</returns>
private static string ParseOutputTagFromLine(string indentedLine, string tagName) private static String ParseOutputTagFromLine(String indentedLine, String tagName) {
{ if(indentedLine.IndexOf(tagName) < 0) {
if (indentedLine.IndexOf(tagName) < 0)
return null; return null;
}
var startIndex = indentedLine.IndexOf(tagName) + tagName.Length; Int32 startIndex = indentedLine.IndexOf(tagName) + tagName.Length;
var builder = new StringBuilder(1024); StringBuilder builder = new StringBuilder(1024);
for (var c = startIndex; c < indentedLine.Length; c++) for(Int32 c = startIndex; c < indentedLine.Length; c++) {
{ Char currentChar = indentedLine[c];
var currentChar = indentedLine[c]; if(!Char.IsPunctuation(currentChar) && !Char.IsLetterOrDigit(currentChar)) {
if (!char.IsPunctuation(currentChar) && !char.IsLetterOrDigit(currentChar))
break; break;
}
builder.Append(currentChar); _ = builder.Append(currentChar);
} }
return builder.ToString(); return builder.ToString();

View File

@ -1,46 +1,58 @@
namespace Unosquare.RaspberryIO.Computer using System;
{
namespace Unosquare.RaspberryIO.Computer {
/// <summary> /// <summary>
/// Represents the OS Information /// Represents the OS Information
/// </summary> /// </summary>
public class OsInfo public class OsInfo {
{
/// <summary> /// <summary>
/// System name /// System name
/// </summary> /// </summary>
public string SysName { get; set; } public String SysName {
get; set;
}
/// <summary> /// <summary>
/// Node name /// Node name
/// </summary> /// </summary>
public string NodeName { get; set; } public String NodeName {
get; set;
}
/// <summary> /// <summary>
/// Release level /// Release level
/// </summary> /// </summary>
public string Release { get; set; } public String Release {
get; set;
}
/// <summary> /// <summary>
/// Version level /// Version level
/// </summary> /// </summary>
public string Version { get; set; } public String Version {
get; set;
}
/// <summary> /// <summary>
/// Hardware level /// Hardware level
/// </summary> /// </summary>
public string Machine { get; set; } public String Machine {
get; set;
}
/// <summary> /// <summary>
/// Domain name /// Domain name
/// </summary> /// </summary>
public string DomainName { get; set; } public String DomainName {
get; set;
}
/// <summary> /// <summary>
/// Returns a <see cref="string" /> that represents this instance. /// Returns a <see cref="String" /> that represents this instance.
/// </summary> /// </summary>
/// <returns> /// <returns>
/// A <see cref="string" /> that represents this instance. /// A <see cref="String" /> that represents this instance.
/// </returns> /// </returns>
public override string ToString() => $"{SysName} {Release} {Version}"; public override String ToString() => $"{this.SysName} {this.Release} {this.Version}";
} }
} }

View File

@ -1,11 +1,9 @@
namespace Unosquare.RaspberryIO.Computer namespace Unosquare.RaspberryIO.Computer {
{
/// <summary> /// <summary>
/// Defines the board revision codes of the different versions of the Raspberry Pi /// 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/ /// http://www.raspberrypi-spy.co.uk/2012/09/checking-your-raspberry-pi-board-version/
/// </summary> /// </summary>
public enum PiVersion public enum PiVersion {
{
/// <summary> /// <summary>
/// The unknown version /// The unknown version
/// </summary> /// </summary>

View File

@ -1,7 +1,5 @@
namespace Unosquare.RaspberryIO.Computer using Unosquare.RaspberryIO.Native;
{ using Unosquare.Swan.Abstractions;
using Native;
using Swan.Abstractions;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Globalization; using System.Globalization;
@ -9,68 +7,64 @@
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
namespace Unosquare.RaspberryIO.Computer {
/// <summary> /// <summary>
/// http://raspberry-pi-guide.readthedocs.io/en/latest/system.html /// http://raspberry-pi-guide.readthedocs.io/en/latest/system.html
/// </summary> /// </summary>
public sealed class SystemInfo : SingletonBase<SystemInfo> public sealed class SystemInfo : SingletonBase<SystemInfo> {
{ private const String CpuInfoFilePath = "/proc/cpuinfo";
private const string CpuInfoFilePath = "/proc/cpuinfo"; private const String MemInfoFilePath = "/proc/meminfo";
private const string MemInfoFilePath = "/proc/meminfo"; private const String UptimeFilePath = "/proc/uptime";
private const string UptimeFilePath = "/proc/uptime";
private static readonly StringComparer StringComparer = StringComparer.InvariantCultureIgnoreCase; private static readonly StringComparer StringComparer = StringComparer.InvariantCultureIgnoreCase;
[System.Diagnostics.CodeAnalysis.SuppressMessage("Codequalität", "IDE0052:Ungelesene private Member entfernen", Justification = "<Ausstehend>")]
private static readonly object SyncRoot = new object(); private static readonly Object SyncRoot = new Object();
/// <summary> /// <summary>
/// Prevents a default instance of the <see cref="SystemInfo"/> class from being created. /// Prevents a default instance of the <see cref="SystemInfo"/> class from being created.
/// </summary> /// </summary>
/// <exception cref="NotSupportedException">Could not initialize the GPIO controller</exception> /// <exception cref="NotSupportedException">Could not initialize the GPIO controller</exception>
private SystemInfo() private SystemInfo() {
{
#region Obtain and format a property dictionary #region Obtain and format a property dictionary
var properties = PropertyInfo[] properties =
typeof(SystemInfo).GetTypeInfo() typeof(SystemInfo).GetTypeInfo()
.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) .GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
.Where( .Where(
p => p =>
p.CanWrite && p.CanRead && p.CanWrite && p.CanRead &&
(p.PropertyType == typeof(string) || p.PropertyType == typeof(string[]))) (p.PropertyType == typeof(String) || p.PropertyType == typeof(String[])))
.ToArray(); .ToArray();
var propDictionary = new Dictionary<string, PropertyInfo>(StringComparer); Dictionary<String, PropertyInfo> propDictionary = new Dictionary<String, PropertyInfo>(StringComparer);
foreach (var prop in properties) foreach(PropertyInfo prop in properties) {
{ propDictionary[prop.Name.Replace(" ", String.Empty).ToLowerInvariant().Trim()] = prop;
propDictionary[prop.Name.Replace(" ", string.Empty).ToLowerInvariant().Trim()] = prop;
} }
#endregion #endregion
#region Extract CPU information #region Extract CPU information
if (File.Exists(CpuInfoFilePath)) if(File.Exists(CpuInfoFilePath)) {
{ String[] cpuInfoLines = File.ReadAllLines(CpuInfoFilePath);
var cpuInfoLines = File.ReadAllLines(CpuInfoFilePath);
foreach (var line in cpuInfoLines) foreach(String line in cpuInfoLines) {
{ String[] lineParts = line.Split(new[] { ':' }, 2);
var lineParts = line.Split(new[] { ':' }, 2); if(lineParts.Length != 2) {
if (lineParts.Length != 2)
continue; 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[]))
{ String propertyKey = lineParts[0].Trim().Replace(" ", String.Empty);
var propertyArrayAvalue = propertyStringValue.Split(' '); 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); property.SetValue(this, propertyArrayAvalue);
} }
} }
@ -80,23 +74,22 @@
#region Extract Memory Information #region Extract Memory Information
if (File.Exists(MemInfoFilePath)) if(File.Exists(MemInfoFilePath)) {
{ String[] memInfoLines = File.ReadAllLines(MemInfoFilePath);
var memInfoLines = File.ReadAllLines(MemInfoFilePath); foreach(String line in memInfoLines) {
foreach (var line in memInfoLines) String[] lineParts = line.Split(new[] { ':' }, 2);
{ if(lineParts.Length != 2) {
var lineParts = line.Split(new[] { ':' }, 2);
if (lineParts.Length != 2)
continue; continue;
}
if (lineParts[0].ToLowerInvariant().Trim().Equals("memtotal") == false) if(lineParts[0].ToLowerInvariant().Trim().Equals("memtotal") == false) {
continue; 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)) if(Int32.TryParse(memKb, out Int32 parsedMem)) {
{ this.InstalledRam = parsedMem * 1024;
InstalledRam = parsedMem * 1024;
break; break;
} }
} }
@ -106,26 +99,21 @@
#region Board Version and Form Factor #region Board Version and Form Factor
try try {
{ if(String.IsNullOrWhiteSpace(this.Revision) == false &&
if (string.IsNullOrWhiteSpace(Revision) == false && Int32.TryParse(
int.TryParse( this.Revision.ToUpperInvariant(),
Revision.ToUpperInvariant(),
NumberStyles.HexNumber, NumberStyles.HexNumber,
CultureInfo.InvariantCulture, CultureInfo.InvariantCulture,
out var boardVersion)) out Int32 boardVersion)) {
{ this.RaspberryPiVersion = PiVersion.Unknown;
RaspberryPiVersion = PiVersion.Unknown; if(Enum.GetValues(typeof(PiVersion)).Cast<Int32>().Contains(boardVersion)) {
if (Enum.GetValues(typeof(PiVersion)).Cast<int>().Contains(boardVersion)) this.RaspberryPiVersion = (PiVersion)boardVersion;
{
RaspberryPiVersion = (PiVersion)boardVersion;
} }
} }
WiringPiBoardRevision = WiringPi.PiBoardRev(); this.WiringPiBoardRevision = WiringPi.PiBoardRev();
} } catch {
catch
{
/* Ignore */ /* Ignore */
} }
@ -134,22 +122,20 @@
#region Version Information #region Version Information
{ {
var libParts = WiringPi.WiringPiLibrary.Split('.'); String[] libParts = WiringPi.WiringPiLibrary.Split('.');
var major = int.Parse(libParts[libParts.Length - 2]); Int32 major = Int32.Parse(libParts[libParts.Length - 2]);
var minor = int.Parse(libParts[libParts.Length - 1]); Int32 minor = Int32.Parse(libParts[libParts.Length - 1]);
var version = new Version(major, minor); Version version = new Version(major, minor);
WiringPiVersion = version; this.WiringPiVersion = version;
} }
#endregion #endregion
#region Extract OS Info #region Extract OS Info
try try {
{ _ = Standard.Uname(out SystemName unameInfo);
Standard.Uname(out var unameInfo); this.OperatingSystem = new OsInfo {
OperatingSystem = new OsInfo
{
DomainName = unameInfo.DomainName, DomainName = unameInfo.DomainName,
Machine = unameInfo.Machine, Machine = unameInfo.Machine,
NodeName = unameInfo.NodeName, NodeName = unameInfo.NodeName,
@ -157,10 +143,8 @@
SysName = unameInfo.SysName, SysName = unameInfo.SysName,
Version = unameInfo.Version Version = unameInfo.Version
}; };
} } catch {
catch this.OperatingSystem = new OsInfo();
{
OperatingSystem = new OsInfo();
} }
#endregion #endregion
@ -169,7 +153,9 @@
/// <summary> /// <summary>
/// Gets the wiring pi library version. /// Gets the wiring pi library version.
/// </summary> /// </summary>
public Version WiringPiVersion { get; } public Version WiringPiVersion {
get;
}
/// <summary> /// <summary>
/// Gets the OS information. /// Gets the OS information.
@ -177,12 +163,16 @@
/// <value> /// <value>
/// The os information. /// The os information.
/// </value> /// </value>
public OsInfo OperatingSystem { get; } public OsInfo OperatingSystem {
get;
}
/// <summary> /// <summary>
/// Gets the Raspberry Pi version. /// Gets the Raspberry Pi version.
/// </summary> /// </summary>
public PiVersion RaspberryPiVersion { get; } public PiVersion RaspberryPiVersion {
get;
}
/// <summary> /// <summary>
/// Gets the Wiring Pi board revision (1 or 2). /// Gets the Wiring Pi board revision (1 or 2).
@ -190,100 +180,112 @@
/// <value> /// <value>
/// The wiring pi board revision. /// The wiring pi board revision.
/// </value> /// </value>
public int WiringPiBoardRevision { get; } public Int32 WiringPiBoardRevision {
get;
}
/// <summary> /// <summary>
/// Gets the number of processor cores. /// Gets the number of processor cores.
/// </summary> /// </summary>
public int ProcessorCount public Int32 ProcessorCount => Int32.TryParse(this.Processor, out Int32 outIndex) ? outIndex + 1 : 0;
{
get
{
if (int.TryParse(Processor, out var outIndex))
{
return outIndex + 1;
}
return 0;
}
}
/// <summary> /// <summary>
/// Gets the installed ram in bytes. /// Gets the installed ram in bytes.
/// </summary> /// </summary>
public int InstalledRam { get; } public Int32 InstalledRam {
get;
}
/// <summary> /// <summary>
/// Gets a value indicating whether this CPU is little endian. /// Gets a value indicating whether this CPU is little endian.
/// </summary> /// </summary>
public bool IsLittleEndian => BitConverter.IsLittleEndian; public Boolean IsLittleEndian => BitConverter.IsLittleEndian;
/// <summary> /// <summary>
/// Gets the CPU model name. /// Gets the CPU model name.
/// </summary> /// </summary>
public string ModelName { get; private set; } public String ModelName {
get; private set;
}
/// <summary> /// <summary>
/// Gets a list of supported CPU features. /// Gets a list of supported CPU features.
/// </summary> /// </summary>
public string[] Features { get; private set; } public String[] Features {
get; private set;
}
/// <summary> /// <summary>
/// Gets the CPU implementer hex code. /// Gets the CPU implementer hex code.
/// </summary> /// </summary>
public string CpuImplementer { get; private set; } public String CpuImplementer {
get; private set;
}
/// <summary> /// <summary>
/// Gets the CPU architecture code. /// Gets the CPU architecture code.
/// </summary> /// </summary>
public string CpuArchitecture { get; private set; } public String CpuArchitecture {
get; private set;
}
/// <summary> /// <summary>
/// Gets the CPU variant code. /// Gets the CPU variant code.
/// </summary> /// </summary>
public string CpuVariant { get; private set; } public String CpuVariant {
get; private set;
}
/// <summary> /// <summary>
/// Gets the CPU part code. /// Gets the CPU part code.
/// </summary> /// </summary>
public string CpuPart { get; private set; } public String CpuPart {
get; private set;
}
/// <summary> /// <summary>
/// Gets the CPU revision code. /// Gets the CPU revision code.
/// </summary> /// </summary>
public string CpuRevision { get; private set; } public String CpuRevision {
get; private set;
}
/// <summary> /// <summary>
/// Gets the hardware model number. /// Gets the hardware model number.
/// </summary> /// </summary>
public string Hardware { get; private set; } public String Hardware {
get; private set;
}
/// <summary> /// <summary>
/// Gets the hardware revision number. /// Gets the hardware revision number.
/// </summary> /// </summary>
public string Revision { get; private set; } public String Revision {
get; private set;
}
/// <summary> /// <summary>
/// Gets the serial number. /// Gets the serial number.
/// </summary> /// </summary>
public string Serial { get; private set; } public String Serial {
get; private set;
}
/// <summary> /// <summary>
/// Gets the system uptime (in seconds). /// Gets the system uptime (in seconds).
/// </summary> /// </summary>
public double Uptime public Double Uptime {
{ get {
get try {
{ if(File.Exists(UptimeFilePath) == false) {
try return 0;
{ }
if (File.Exists(UptimeFilePath) == false) return 0;
var parts = File.ReadAllText(UptimeFilePath).Trim().Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); String[] parts = File.ReadAllText(UptimeFilePath).Trim().Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
if (parts.Length >= 1 && float.TryParse(parts[0], out var result)) if(parts.Length >= 1 && Single.TryParse(parts[0], out Single result)) {
return result; return result;
} }
catch } catch {
{
/* Ignore */ /* Ignore */
} }
@ -294,51 +296,48 @@
/// <summary> /// <summary>
/// Gets the uptime in TimeSpan. /// Gets the uptime in TimeSpan.
/// </summary> /// </summary>
public TimeSpan UptimeTimeSpan => TimeSpan.FromSeconds(Uptime); public TimeSpan UptimeTimeSpan => TimeSpan.FromSeconds(this.Uptime);
/// <summary> /// <summary>
/// Placeholder for processor index /// Placeholder for processor index
/// </summary> /// </summary>
private string Processor { get; set; } private String Processor {
get; set;
}
/// <summary> /// <summary>
/// Returns a <see cref="string" /> that represents this instance. /// Returns a <see cref="String" /> that represents this instance.
/// </summary> /// </summary>
/// <returns> /// <returns>
/// A <see cref="string" /> that represents this instance. /// A <see cref="String" /> that represents this instance.
/// </returns> /// </returns>
public override string ToString() public override String ToString() {
{ PropertyInfo[] properties = typeof(SystemInfo).GetTypeInfo().GetProperties(BindingFlags.Instance | BindingFlags.Public)
var properties = typeof(SystemInfo).GetTypeInfo().GetProperties(BindingFlags.Instance | BindingFlags.Public)
.Where(p => p.CanRead && ( .Where(p => p.CanRead && (
p.PropertyType == typeof(string) || p.PropertyType == typeof(String) ||
p.PropertyType == typeof(string[]) || p.PropertyType == typeof(String[]) ||
p.PropertyType == typeof(int) || p.PropertyType == typeof(Int32) ||
p.PropertyType == typeof(bool) || p.PropertyType == typeof(Boolean) ||
p.PropertyType == typeof(TimeSpan))) p.PropertyType == typeof(TimeSpan)))
.ToArray(); .ToArray();
var properyValues = new List<string> List<String> properyValues = new List<String>
{ {
"System Information", "System Information",
$"\t{nameof(WiringPiVersion),-22}: {WiringPiVersion}", $"\t{nameof(this.WiringPiVersion),-22}: {this.WiringPiVersion}",
$"\t{nameof(RaspberryPiVersion),-22}: {RaspberryPiVersion}" $"\t{nameof(this.RaspberryPiVersion),-22}: {this.RaspberryPiVersion}"
}; };
foreach (var property in properties) foreach(PropertyInfo property in properties) {
{ if(property.PropertyType != typeof(String[])) {
if (property.PropertyType != typeof(string[]))
{
properyValues.Add($"\t{property.Name,-22}: {property.GetValue(this)}"); properyValues.Add($"\t{property.Name,-22}: {property.GetValue(this)}");
} } else if(property.GetValue(this) is String[] allValues) {
else if (property.GetValue(this) is string[] allValues) String concatValues = String.Join(" ", allValues);
{
var concatValues = string.Join(" ", allValues);
properyValues.Add($"\t{property.Name,-22}: {concatValues}"); properyValues.Add($"\t{property.Name,-22}: {concatValues}");
} }
} }
return string.Join(Environment.NewLine, properyValues.ToArray()); return String.Join(Environment.NewLine, properyValues.ToArray());
} }
} }
} }

View File

@ -1,23 +1,29 @@
namespace Unosquare.RaspberryIO.Computer using System;
{
namespace Unosquare.RaspberryIO.Computer {
/// <summary> /// <summary>
/// Represents a wireless network information /// Represents a wireless network information
/// </summary> /// </summary>
public class WirelessNetworkInfo public class WirelessNetworkInfo {
{
/// <summary> /// <summary>
/// Gets the ESSID of the Wireless network. /// Gets the ESSID of the Wireless network.
/// </summary> /// </summary>
public string Name { get; internal set; } public String Name {
get; internal set;
}
/// <summary> /// <summary>
/// Gets the network quality. /// Gets the network quality.
/// </summary> /// </summary>
public string Quality { get; internal set; } public String Quality {
get; internal set;
}
/// <summary> /// <summary>
/// Gets a value indicating whether this instance is encrypted. /// Gets a value indicating whether this instance is encrypted.
/// </summary> /// </summary>
public bool IsEncrypted { get; internal set; } public Boolean IsEncrypted {
get; internal set;
}
} }
} }

View File

@ -1,10 +1,8 @@
namespace Unosquare.RaspberryIO.Gpio namespace Unosquare.RaspberryIO.Gpio {
{
/// <summary> /// <summary>
/// Defines the different drive modes of a GPIO pin /// Defines the different drive modes of a GPIO pin
/// </summary> /// </summary>
public enum GpioPinDriveMode public enum GpioPinDriveMode {
{
/// <summary> /// <summary>
/// Input drive mode (perform reads) /// Input drive mode (perform reads)
/// </summary> /// </summary>
@ -30,8 +28,7 @@
/// The GPIO pin resistor mode. This is used on input pins so that their /// The GPIO pin resistor mode. This is used on input pins so that their
/// lines are not floating /// lines are not floating
/// </summary> /// </summary>
public enum GpioPinResistorPullMode public enum GpioPinResistorPullMode {
{
/// <summary> /// <summary>
/// Pull resistor not active. Line floating /// Pull resistor not active. Line floating
/// </summary> /// </summary>
@ -51,8 +48,7 @@
/// <summary> /// <summary>
/// The PWM mode. /// The PWM mode.
/// </summary> /// </summary>
public enum PwmMode public enum PwmMode {
{
/// <summary> /// <summary>
/// PWM pulses are sent using mark-sign patterns (old school) /// PWM pulses are sent using mark-sign patterns (old school)
/// </summary> /// </summary>
@ -67,8 +63,7 @@
/// <summary> /// <summary>
/// Defines the different edge detection modes for pin interrupts /// Defines the different edge detection modes for pin interrupts
/// </summary> /// </summary>
public enum EdgeDetection public enum EdgeDetection {
{
/// <summary> /// <summary>
/// Assumes edge detection was already setup externally /// Assumes edge detection was already setup externally
/// </summary> /// </summary>
@ -93,8 +88,7 @@
/// <summary> /// <summary>
/// Defines the GPIO Pin values 0 for low, 1 for High /// Defines the GPIO Pin values 0 for low, 1 for High
/// </summary> /// </summary>
public enum GpioPinValue public enum GpioPinValue {
{
/// <summary> /// <summary>
/// Digital high /// Digital high
/// </summary> /// </summary>
@ -109,8 +103,7 @@
/// <summary> /// <summary>
/// Defines the Header connectors available /// Defines the Header connectors available
/// </summary> /// </summary>
public enum GpioHeader public enum GpioHeader {
{
/// <summary> /// <summary>
/// Not defined /// Not defined
/// </summary> /// </summary>
@ -130,8 +123,7 @@
/// <summary> /// <summary>
/// Defines all the available Wiring Pi Pin Numbers /// Defines all the available Wiring Pi Pin Numbers
/// </summary> /// </summary>
public enum WiringPiPin public enum WiringPiPin {
{
/// <summary> /// <summary>
/// The unknown /// The unknown
/// </summary> /// </summary>
@ -303,8 +295,7 @@
/// as commonly referenced by Raspberry Pi Documentation. /// as commonly referenced by Raspberry Pi Documentation.
/// Enumeration values correspond to the physical pin number. /// Enumeration values correspond to the physical pin number.
/// </summary> /// </summary>
public enum P1 public enum P1 {
{
/// <summary> /// <summary>
/// Header P1, GPIO Pin 02 /// Header P1, GPIO Pin 02
/// </summary> /// </summary>
@ -441,8 +432,7 @@
/// as commonly referenced by Raspberry Pi documentation. /// as commonly referenced by Raspberry Pi documentation.
/// Enumeration values correspond to the physical pin number. /// Enumeration values correspond to the physical pin number.
/// </summary> /// </summary>
public enum P5 public enum P5 {
{
/// <summary> /// <summary>
/// Header P5, GPIO Pin 28 /// Header P5, GPIO Pin 28
/// </summary> /// </summary>
@ -467,8 +457,7 @@
/// <summary> /// <summary>
/// Defines the different pin capabilities /// Defines the different pin capabilities
/// </summary> /// </summary>
public enum PinCapability public enum PinCapability {
{
/// <summary> /// <summary>
/// General Purpose capability: Digital and Analog Read/Write /// General Purpose capability: Digital and Analog Read/Write
/// </summary> /// </summary>
@ -533,8 +522,7 @@
/// <summary> /// <summary>
/// Defines the SPI channel numbers /// Defines the SPI channel numbers
/// </summary> /// </summary>
internal enum SpiChannelNumber internal enum SpiChannelNumber {
{
/// <summary> /// <summary>
/// The channel 0 /// The channel 0
/// </summary> /// </summary>
@ -549,8 +537,7 @@
/// <summary> /// <summary>
/// Defines GPIO controller initialization modes /// Defines GPIO controller initialization modes
/// </summary> /// </summary>
internal enum ControllerMode internal enum ControllerMode {
{
/// <summary> /// <summary>
/// The not initialized /// The not initialized
/// </summary> /// </summary>

View File

@ -1,8 +1,6 @@
namespace Unosquare.RaspberryIO.Gpio using Unosquare.RaspberryIO.Native;
{ using Unosquare.Swan;
using Native; using Unosquare.Swan.Abstractions;
using Swan;
using Swan.Abstractions;
using System; using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
@ -10,21 +8,18 @@
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Unosquare.RaspberryIO.Gpio {
/// <summary> /// <summary>
/// Represents a singleton of the Raspberry Pi GPIO controller /// Represents a singleton of the Raspberry Pi GPIO controller
/// as an IReadOnlyCollection of GpioPins /// as an IReadOnlyCollection of GpioPins
/// Low level operations are accomplished by using the Wiring Pi library. /// Low level operations are accomplished by using the Wiring Pi library.
/// Use the Instance property to access the singleton's instance /// Use the Instance property to access the singleton's instance
/// </summary> /// </summary>
public sealed class GpioController : SingletonBase<GpioController>, IReadOnlyCollection<GpioPin> public sealed class GpioController : SingletonBase<GpioController>, IReadOnlyCollection<GpioPin> {
{
#region Private Declarations #region Private Declarations
private const string WiringPiCodesEnvironmentVariable = "WIRINGPI_CODES"; private const String WiringPiCodesEnvironmentVariable = "WIRINGPI_CODES";
private static readonly object SyncRoot = new object(); 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 readonly Dictionary<WiringPiPin, GpioPin> _pinsByWiringPiPinNumber = new Dictionary<WiringPiPin, GpioPin>(); private readonly Dictionary<WiringPiPin, GpioPin> _pinsByWiringPiPinNumber = new Dictionary<WiringPiPin, GpioPin>();
#endregion #endregion
@ -36,66 +31,65 @@
/// It in turn initializes the controller and registers the pin -- in that order. /// It in turn initializes the controller and registers the pin -- in that order.
/// </summary> /// </summary>
/// <exception cref="Exception">Unable to initialize the GPIO controller.</exception> /// <exception cref="Exception">Unable to initialize the GPIO controller.</exception>
private GpioController() private GpioController() {
{ if(this.Pins != null) {
if (_pinCollection != null)
return; return;
}
if (IsInitialized == false) if(IsInitialized == false) {
{ Boolean initResult = this.Initialize(ControllerMode.DirectWithWiringPiPins);
var initResult = Initialize(ControllerMode.DirectWithWiringPiPins); if(initResult == false) {
if (initResult == false)
throw new Exception("Unable to initialize the GPIO controller."); throw new Exception("Unable to initialize the GPIO controller.");
} }
}
#region Pin Registration (32 WiringPi Pins) #region Pin Registration (32 WiringPi Pins)
RegisterPin(GpioPin.Pin00.Value); this.RegisterPin(GpioPin.Pin00.Value);
RegisterPin(GpioPin.Pin01.Value); this.RegisterPin(GpioPin.Pin01.Value);
RegisterPin(GpioPin.Pin02.Value); this.RegisterPin(GpioPin.Pin02.Value);
RegisterPin(GpioPin.Pin03.Value); this.RegisterPin(GpioPin.Pin03.Value);
RegisterPin(GpioPin.Pin04.Value); this.RegisterPin(GpioPin.Pin04.Value);
RegisterPin(GpioPin.Pin05.Value); this.RegisterPin(GpioPin.Pin05.Value);
RegisterPin(GpioPin.Pin06.Value); this.RegisterPin(GpioPin.Pin06.Value);
RegisterPin(GpioPin.Pin07.Value); this.RegisterPin(GpioPin.Pin07.Value);
RegisterPin(GpioPin.Pin08.Value); this.RegisterPin(GpioPin.Pin08.Value);
RegisterPin(GpioPin.Pin09.Value); this.RegisterPin(GpioPin.Pin09.Value);
RegisterPin(GpioPin.Pin10.Value); this.RegisterPin(GpioPin.Pin10.Value);
RegisterPin(GpioPin.Pin11.Value); this.RegisterPin(GpioPin.Pin11.Value);
RegisterPin(GpioPin.Pin12.Value); this.RegisterPin(GpioPin.Pin12.Value);
RegisterPin(GpioPin.Pin13.Value); this.RegisterPin(GpioPin.Pin13.Value);
RegisterPin(GpioPin.Pin14.Value); this.RegisterPin(GpioPin.Pin14.Value);
RegisterPin(GpioPin.Pin15.Value); this.RegisterPin(GpioPin.Pin15.Value);
RegisterPin(GpioPin.Pin16.Value); this.RegisterPin(GpioPin.Pin16.Value);
RegisterPin(GpioPin.Pin17.Value); this.RegisterPin(GpioPin.Pin17.Value);
RegisterPin(GpioPin.Pin18.Value); this.RegisterPin(GpioPin.Pin18.Value);
RegisterPin(GpioPin.Pin19.Value); this.RegisterPin(GpioPin.Pin19.Value);
RegisterPin(GpioPin.Pin20.Value); this.RegisterPin(GpioPin.Pin20.Value);
RegisterPin(GpioPin.Pin21.Value); this.RegisterPin(GpioPin.Pin21.Value);
RegisterPin(GpioPin.Pin22.Value); this.RegisterPin(GpioPin.Pin22.Value);
RegisterPin(GpioPin.Pin23.Value); this.RegisterPin(GpioPin.Pin23.Value);
RegisterPin(GpioPin.Pin24.Value); this.RegisterPin(GpioPin.Pin24.Value);
RegisterPin(GpioPin.Pin25.Value); this.RegisterPin(GpioPin.Pin25.Value);
RegisterPin(GpioPin.Pin26.Value); this.RegisterPin(GpioPin.Pin26.Value);
RegisterPin(GpioPin.Pin27.Value); this.RegisterPin(GpioPin.Pin27.Value);
RegisterPin(GpioPin.Pin28.Value); this.RegisterPin(GpioPin.Pin28.Value);
RegisterPin(GpioPin.Pin29.Value); this.RegisterPin(GpioPin.Pin29.Value);
RegisterPin(GpioPin.Pin30.Value); this.RegisterPin(GpioPin.Pin30.Value);
RegisterPin(GpioPin.Pin31.Value); this.RegisterPin(GpioPin.Pin31.Value);
#endregion #endregion
_pinCollection = new ReadOnlyCollection<GpioPin>(_pinsByWiringPiPinNumber.Values.ToArray()); this.Pins = new ReadOnlyCollection<GpioPin>(this._pinsByWiringPiPinNumber.Values.ToArray());
var headerP1 = new Dictionary<int, GpioPin>(_pinCollection.Count); Dictionary<Int32, GpioPin> headerP1 = new Dictionary<Int32, GpioPin>(this.Pins.Count);
var headerP5 = new Dictionary<int, GpioPin>(_pinCollection.Count); Dictionary<Int32, GpioPin> headerP5 = new Dictionary<Int32, GpioPin>(this.Pins.Count);
foreach (var pin in _pinCollection) foreach(GpioPin pin in this.Pins) {
{ Dictionary<Int32, GpioPin> target = pin.Header == GpioHeader.P1 ? headerP1 : headerP5;
var target = pin.Header == GpioHeader.P1 ? headerP1 : headerP5;
target[pin.HeaderPinNumber] = pin; target[pin.HeaderPinNumber] = pin;
} }
_headerP1Pins = new ReadOnlyDictionary<int, GpioPin>(headerP1); this.HeaderP1 = new ReadOnlyDictionary<Int32, GpioPin>(headerP1);
_headerP5Pins = new ReadOnlyDictionary<int, GpioPin>(headerP5); this.HeaderP5 = new ReadOnlyDictionary<Int32, GpioPin>(headerP5);
} }
/// <summary> /// <summary>
@ -104,12 +98,9 @@
/// <value> /// <value>
/// <c>true</c> if the controller is properly initialized; otherwise, <c>false</c>. /// <c>true</c> if the controller is properly initialized; otherwise, <c>false</c>.
/// </value> /// </value>
public static bool IsInitialized public static Boolean IsInitialized {
{ get {
get lock(SyncRoot) {
{
lock (SyncRoot)
{
return Mode != ControllerMode.NotInitialized; return Mode != ControllerMode.NotInitialized;
} }
} }
@ -118,7 +109,7 @@
/// <summary> /// <summary>
/// Gets the number of registered pins in the controller. /// Gets the number of registered pins in the controller.
/// </summary> /// </summary>
public int Count => _pinCollection.Count; public Int32 Count => this.Pins.Count;
#endregion #endregion
@ -127,24 +118,30 @@
/// <summary> /// <summary>
/// Gets the PWM base frequency (in Hz). /// Gets the PWM base frequency (in Hz).
/// </summary> /// </summary>
public int PwmBaseFrequency => 19200000; public Int32 PwmBaseFrequency => 19200000;
/// <summary> /// <summary>
/// Gets a red-only collection of all registered pins. /// Gets a red-only collection of all registered pins.
/// </summary> /// </summary>
public ReadOnlyCollection<GpioPin> Pins => _pinCollection; public ReadOnlyCollection<GpioPin> Pins {
get;
}
/// <summary> /// <summary>
/// Provides all the pins on Header P1 of the Pi as a lookup by physical header pin number. /// 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. /// This header is the main header and it is the one commonly used.
/// </summary> /// </summary>
public ReadOnlyDictionary<int, GpioPin> HeaderP1 => _headerP1Pins; public ReadOnlyDictionary<Int32, GpioPin> HeaderP1 {
get;
}
/// <summary> /// <summary>
/// Provides all the pins on Header P5 of the Pi as a lookup by physical header pin number. /// 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. /// This header is the secondary header and it is rarely used.
/// </summary> /// </summary>
public ReadOnlyDictionary<int, GpioPin> HeaderP5 => _headerP5Pins; public ReadOnlyDictionary<Int32, GpioPin> HeaderP5 {
get;
}
#endregion #endregion
@ -327,7 +324,7 @@
/// </value> /// </value>
/// <param name="pinNumber">The pin number.</param> /// <param name="pinNumber">The pin number.</param>
/// <returns>A reference to the GPIO pin</returns> /// <returns>A reference to the GPIO pin</returns>
public GpioPin this[WiringPiPin pinNumber] => _pinsByWiringPiPinNumber[pinNumber]; public GpioPin this[WiringPiPin pinNumber] => this._pinsByWiringPiPinNumber[pinNumber];
/// <summary> /// <summary>
/// Gets the <see cref="GpioPin"/> with the specified pin number. /// Gets the <see cref="GpioPin"/> with the specified pin number.
@ -337,7 +334,7 @@
/// </value> /// </value>
/// <param name="pinNumber">The pin number.</param> /// <param name="pinNumber">The pin number.</param>
/// <returns>A reference to the GPIO pin</returns> /// <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> /// <summary>
/// Gets the <see cref="GpioPin"/> with the specified pin number. /// Gets the <see cref="GpioPin"/> with the specified pin number.
@ -347,7 +344,7 @@
/// </value> /// </value>
/// <param name="pinNumber">The pin number.</param> /// <param name="pinNumber">The pin number.</param>
/// <returns>A reference to the GPIO pin</returns> /// <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> /// <summary>
/// Gets the <see cref="GpioPin"/> with the specified Wiring Pi pin number. /// 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> /// <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> /// <returns>A reference to the GPIO pin</returns>
/// <exception cref="IndexOutOfRangeException">When the pin index is not found</exception> /// <exception cref="IndexOutOfRangeException">When the pin index is not found</exception>
public GpioPin this[int wiringPiPinNumber] public GpioPin this[Int32 wiringPiPinNumber] {
{ get {
get if(Enum.IsDefined(typeof(WiringPiPin), wiringPiPinNumber) == false) {
{
if (Enum.IsDefined(typeof(WiringPiPin), wiringPiPinNumber) == false)
throw new IndexOutOfRangeException($"Pin {wiringPiPinNumber} is not registered in the GPIO controller."); 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> /// </summary>
/// <param name="group">The group.</param> /// <param name="group">The group.</param>
/// <param name="value">The value.</param> /// <param name="value">The value.</param>
public void SetPadDrive(int group, int value) public void SetPadDrive(Int32 group, Int32 value) {
{ lock(SyncRoot) {
lock (SyncRoot) _ = WiringPi.SetPadDrive(group, value);
{
WiringPi.SetPadDrive(group, value);
} }
} }
@ -397,7 +391,7 @@
/// <param name="group">The group.</param> /// <param name="group">The group.</param>
/// <param name="value">The value.</param> /// <param name="value">The value.</param>
/// <returns>The awaitable task</returns> /// <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> /// <summary>
/// This writes the 8-bit byte supplied to the first 8 GPIO pins. /// This writes the 8-bit byte supplied to the first 8 GPIO pins.
@ -406,12 +400,9 @@
/// </summary> /// </summary>
/// <param name="value">The value.</param> /// <param name="value">The value.</param>
/// <exception cref="InvalidOperationException">PinMode</exception> /// <exception cref="InvalidOperationException">PinMode</exception>
public void WriteByte(byte value) public void WriteByte(Byte value) {
{ lock(SyncRoot) {
lock (SyncRoot) if(this.Skip(0).Take(8).Any(p => p.PinMode != GpioPinDriveMode.Output)) {
{
if (this.Skip(0).Take(8).Any(p => p.PinMode != GpioPinDriveMode.Output))
{
throw new InvalidOperationException( throw new InvalidOperationException(
$"All firts 8 pins (0 to 7) need their {nameof(GpioPin.PinMode)} to be set to {GpioPinDriveMode.Output}"); $"All firts 8 pins (0 to 7) need their {nameof(GpioPin.PinMode)} to be set to {GpioPinDriveMode.Output}");
} }
@ -427,7 +418,7 @@
/// </summary> /// </summary>
/// <param name="value">The value.</param> /// <param name="value">The value.</param>
/// <returns>The awaitable task</returns> /// <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> /// <summary>
/// This reads the 8-bit byte supplied to the first 8 GPIO pins. /// This reads the 8-bit byte supplied to the first 8 GPIO pins.
@ -436,18 +427,15 @@
/// </summary> /// </summary>
/// <returns>A byte from the GPIO</returns> /// <returns>A byte from the GPIO</returns>
/// <exception cref="InvalidOperationException">PinMode</exception> /// <exception cref="InvalidOperationException">PinMode</exception>
public byte ReadByte() public Byte ReadByte() {
{ lock(SyncRoot) {
lock (SyncRoot)
{
if(this.Skip(0).Take(8).Any(p => 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( throw new InvalidOperationException(
$"All firts 8 pins (0 to 7) need their {nameof(GpioPin.PinMode)} to be set to {GpioPinDriveMode.Input} or {GpioPinDriveMode.Output}"); $"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 /// Please note this function is undocumented and unsopported
/// </summary> /// </summary>
/// <returns>A byte from the GPIO</returns> /// <returns>A byte from the GPIO</returns>
public Task<byte> ReadByteAsync() => Task.Run(() => ReadByte()); public Task<Byte> ReadByteAsync() => Task.Run(() => this.ReadByte());
#endregion #endregion
@ -469,7 +457,7 @@
/// <returns> /// <returns>
/// A <see cref="T:System.Collections.Generic.IEnumerator`1" /> that can be used to iterate through the collection. /// A <see cref="T:System.Collections.Generic.IEnumerator`1" /> that can be used to iterate through the collection.
/// </returns> /// </returns>
public IEnumerator<GpioPin> GetEnumerator() => _pinCollection.GetEnumerator(); public IEnumerator<GpioPin> GetEnumerator() => this.Pins.GetEnumerator();
/// <summary> /// <summary>
/// Returns an enumerator that iterates through the collection. /// Returns an enumerator that iterates through the collection.
@ -477,7 +465,7 @@
/// <returns> /// <returns>
/// An <see cref="T:System.Collections.IEnumerator" /> object that can be used to iterate through the collection. /// An <see cref="T:System.Collections.IEnumerator" /> object that can be used to iterate through the collection.
/// </returns> /// </returns>
IEnumerator IEnumerable.GetEnumerator() => _pinCollection.GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => this.Pins.GetEnumerator();
#endregion #endregion
@ -488,17 +476,15 @@
/// </summary> /// </summary>
/// <param name="bcmPinNumber">The BCM pin number.</param> /// <param name="bcmPinNumber">The BCM pin number.</param>
/// <returns>The GPIO pin</returns> /// <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> /// <summary>
/// Converts the Wirings Pi pin number to the BCM pin number. /// Converts the Wirings Pi pin number to the BCM pin number.
/// </summary> /// </summary>
/// <param name="wiringPiPinNumber">The wiring pi pin number.</param> /// <param name="wiringPiPinNumber">The wiring pi pin number.</param>
/// <returns>The converted pin</returns> /// <returns>The converted pin</returns>
internal static int WiringPiToBcmPinNumber(int wiringPiPinNumber) internal static Int32 WiringPiToBcmPinNumber(Int32 wiringPiPinNumber) {
{ lock(SyncRoot) {
lock (SyncRoot)
{
return WiringPi.WpiPinToGpio(wiringPiPinNumber); return WiringPi.WpiPinToGpio(wiringPiPinNumber);
} }
} }
@ -508,10 +494,8 @@
/// </summary> /// </summary>
/// <param name="headerPinNumber">The header pin number.</param> /// <param name="headerPinNumber">The header pin number.</param>
/// <returns>The converted pin</returns> /// <returns>The converted pin</returns>
internal static int HaderToBcmPinNumber(int headerPinNumber) internal static Int32 HaderToBcmPinNumber(Int32 headerPinNumber) {
{ lock(SyncRoot) {
lock (SyncRoot)
{
return WiringPi.PhysPinToGpio(headerPinNumber); return WiringPi.PhysPinToGpio(headerPinNumber);
} }
} }
@ -520,13 +504,13 @@
/// Short-hand method of registering pins /// Short-hand method of registering pins
/// </summary> /// </summary>
/// <param name="pin">The pin.</param> /// <param name="pin">The pin.</param>
private void RegisterPin(GpioPin pin) private void RegisterPin(GpioPin pin) {
{ if(this._pinsByWiringPiPinNumber.ContainsKey(pin.WiringPiPinNumber) == false) {
if (_pinsByWiringPiPinNumber.ContainsKey(pin.WiringPiPinNumber) == false) this._pinsByWiringPiPinNumber[pin.WiringPiPinNumber] = pin;
_pinsByWiringPiPinNumber[pin.WiringPiPinNumber] = pin; } else {
else
throw new InvalidOperationException($"Pin {pin.WiringPiPinNumber} has been registered"); throw new InvalidOperationException($"Pin {pin.WiringPiPinNumber} has been registered");
} }
}
/// <summary> /// <summary>
/// Initializes the controller given the initialization mode and pin numbering scheme /// Initializes the controller given the initialization mode and pin numbering scheme
@ -538,47 +522,41 @@
/// </exception> /// </exception>
/// <exception cref="InvalidOperationException">Library was already Initialized</exception> /// <exception cref="InvalidOperationException">Library was already Initialized</exception>
/// <exception cref="ArgumentException">The init mode is invalid</exception> /// <exception cref="ArgumentException">The init mode is invalid</exception>
private bool Initialize(ControllerMode mode) private Boolean Initialize(ControllerMode mode) {
{ if(Runtime.OS != Swan.OperatingSystem.Unix) {
if (Runtime.OS != Swan.OperatingSystem.Unix)
throw new PlatformNotSupportedException("This library does not support the platform"); throw new PlatformNotSupportedException("This library does not support the platform");
}
lock (SyncRoot) lock(SyncRoot) {
{ if(IsInitialized) {
if (IsInitialized)
throw new InvalidOperationException($"Cannot call {nameof(Initialize)} more than once."); throw new InvalidOperationException($"Cannot call {nameof(Initialize)} more than once.");
}
Environment.SetEnvironmentVariable(WiringPiCodesEnvironmentVariable, "1", EnvironmentVariableTarget.Process); Environment.SetEnvironmentVariable(WiringPiCodesEnvironmentVariable, "1", EnvironmentVariableTarget.Process);
int setpuResult; Int32 setpuResult;
switch (mode) switch(mode) {
{ case ControllerMode.DirectWithWiringPiPins: {
case ControllerMode.DirectWithWiringPiPins:
{
setpuResult = WiringPi.WiringPiSetup(); setpuResult = WiringPi.WiringPiSetup();
break; break;
} }
case ControllerMode.DirectWithBcmPins: case ControllerMode.DirectWithBcmPins: {
{
setpuResult = WiringPi.WiringPiSetupGpio(); setpuResult = WiringPi.WiringPiSetupGpio();
break; break;
} }
case ControllerMode.DirectWithHeaderPins: case ControllerMode.DirectWithHeaderPins: {
{
setpuResult = WiringPi.WiringPiSetupPhys(); setpuResult = WiringPi.WiringPiSetupPhys();
break; break;
} }
case ControllerMode.FileStreamWithHardwarePins: case ControllerMode.FileStreamWithHardwarePins: {
{
setpuResult = WiringPi.WiringPiSetupSys(); setpuResult = WiringPi.WiringPiSetupSys();
break; break;
} }
default: default: {
{
throw new ArgumentException($"'{mode}' is not a valid initialization mode."); throw new ArgumentException($"'{mode}' is not a valid initialization mode.");
} }
} }

View File

@ -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 #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 }, Capabilities = new[] { PinCapability.GP, PinCapability.I2CSDA },
Name = "BCM 2 (SDA)" 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 }, Capabilities = new[] { PinCapability.GP, PinCapability.I2CSCL },
Name = "BCM 3 (SCL)" 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 }, Capabilities = new[] { PinCapability.GP, PinCapability.GPCLK },
Name = "BCM 4 (GPCLK0)" 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 }, Capabilities = new[] { PinCapability.GP, PinCapability.UARTRTS },
Name = "BCM 17" 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 }, Capabilities = new[] { PinCapability.GP },
Name = "BCM 27" 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 }, Capabilities = new[] { PinCapability.GP },
Name = "BCM 22" 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 }, Capabilities = new[] { PinCapability.GP, PinCapability.SPIMOSI },
Name = "BCM 10 (MOSI)" 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 }, Capabilities = new[] { PinCapability.GP, PinCapability.SPIMISO },
Name = "BCM 9 (MISO)" 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 }, Capabilities = new[] { PinCapability.GP, PinCapability.SPICLK },
Name = "BCM 11 (SCLCK)" 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 }, Capabilities = new[] { PinCapability.I2CSDA },
Name = "BCM 0 (ID_SD)" 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 }, Capabilities = new[] { PinCapability.I2CSCL },
Name = "BCM 1 (ID_SC)" 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 }, Capabilities = new[] { PinCapability.GP, PinCapability.SPICS },
Name = "BCM 7 (CE1)" 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 }, Capabilities = new[] { PinCapability.GP, PinCapability.SPICS },
Name = "BCM 8 (CE0)" 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 }, Capabilities = new[] { PinCapability.GP },
Name = "BCM 25" 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 }, Capabilities = new[] { PinCapability.GP },
Name = "BCM 24" 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 }, Capabilities = new[] { PinCapability.GP },
Name = "BCM 23" 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 }, Capabilities = new[] { PinCapability.GP, PinCapability.PWM },
Name = "BCM 18 (PWM0)" 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 }, Capabilities = new[] { PinCapability.UARTRXD },
Name = "BCM 15 (RXD)" 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 }, Capabilities = new[] { PinCapability.UARTTXD },
Name = "BCM 14 (TXD)" 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 }, Capabilities = new[] { PinCapability.GP },
Name = "BCM 5" 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 }, Capabilities = new[] { PinCapability.GP },
Name = "BCM 6" 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 }, Capabilities = new[] { PinCapability.GP, PinCapability.PWM },
Name = "BCM 13 (PWM1)" 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 }, Capabilities = new[] { PinCapability.GP, PinCapability.SPIMISO },
Name = "BCM 19 (MISO)" 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 }, Capabilities = new[] { PinCapability.GP },
Name = "BCM 26" 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 }, Capabilities = new[] { PinCapability.GP, PinCapability.SPICLK },
Name = "BCM 21 (SCLK)" 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 }, Capabilities = new[] { PinCapability.GP, PinCapability.SPIMOSI },
Name = "BCM 20 (MOSI)" 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 }, Capabilities = new[] { PinCapability.GP },
Name = "BCM 16" 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 }, Capabilities = new[] { PinCapability.GP },
Name = "BCM 12 (PWM0)" 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 }, Capabilities = new[] { PinCapability.GP, PinCapability.I2CSDA },
Name = "BCM 28 (SDA)" 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 }, Capabilities = new[] { PinCapability.GP, PinCapability.I2CSCL },
Name = "BCM 29 (SCL)" 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 }, Capabilities = new[] { PinCapability.GP },
Name = "BCM 30" 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 }, Capabilities = new[] { PinCapability.GP },
Name = "BCM 31" Name = "BCM 31"
}); });

View File

@ -1,29 +1,27 @@
namespace Unosquare.RaspberryIO.Gpio using Unosquare.RaspberryIO.Native;
{ using Unosquare.Swan;
using Native;
using Swan;
using System; using System;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Unosquare.RaspberryIO.Gpio {
/// <summary> /// <summary>
/// Represents a GPIO Pin, its location and its capabilities. /// Represents a GPIO Pin, its location and its capabilities.
/// Full pin reference available here: /// Full pin reference available here:
/// http://pinout.xyz/pinout/pin31_gpio6 and http://wiringpi.com/pins/ /// http://pinout.xyz/pinout/pin31_gpio6 and http://wiringpi.com/pins/
/// </summary> /// </summary>
public sealed partial class GpioPin public sealed partial class GpioPin {
{
#region Property Backing #region Property Backing
private readonly object _syncLock = new object(); private readonly Object _syncLock = new Object();
private GpioPinDriveMode m_PinMode; private GpioPinDriveMode m_PinMode;
private GpioPinResistorPullMode m_ResistorPullMode; private GpioPinResistorPullMode m_ResistorPullMode;
private int m_PwmRegister; private Int32 m_PwmRegister;
private PwmMode m_PwmMode = PwmMode.Balanced; private PwmMode m_PwmMode = PwmMode.Balanced;
private uint m_PwmRange = 1024; private UInt32 m_PwmRange = 1024;
private int m_PwmClockDivisor = 1; private Int32 m_PwmClockDivisor = 1;
private int m_SoftPwmValue = -1; private Int32 m_SoftPwmValue = -1;
private int m_SoftToneFrequency = -1; private Int32 m_SoftToneFrequency = -1;
#endregion #endregion
@ -34,13 +32,12 @@
/// </summary> /// </summary>
/// <param name="wiringPiPinNumber">The wiring pi pin number.</param> /// <param name="wiringPiPinNumber">The wiring pi pin number.</param>
/// <param name="headerPinNumber">The header pin number.</param> /// <param name="headerPinNumber">The header pin number.</param>
private GpioPin(WiringPiPin wiringPiPinNumber, int headerPinNumber) private GpioPin(WiringPiPin wiringPiPinNumber, Int32 headerPinNumber) {
{ this.PinNumber = (Int32)wiringPiPinNumber;
PinNumber = (int)wiringPiPinNumber; this.WiringPiPinNumber = wiringPiPinNumber;
WiringPiPinNumber = wiringPiPinNumber; this.BcmPinNumber = GpioController.WiringPiToBcmPinNumber((Int32)wiringPiPinNumber);
BcmPinNumber = GpioController.WiringPiToBcmPinNumber((int)wiringPiPinNumber); this.HeaderPinNumber = headerPinNumber;
HeaderPinNumber = headerPinNumber; this.Header = (this.PinNumber >= 17 && this.PinNumber <= 20) ? GpioHeader.P5 : GpioHeader.P1;
Header = (PinNumber >= 17 && PinNumber <= 20) ? GpioHeader.P5 : GpioHeader.P1;
} }
#endregion #endregion
@ -50,37 +47,51 @@
/// <summary> /// <summary>
/// Gets or sets the Wiring Pi pin number as an integer. /// Gets or sets the Wiring Pi pin number as an integer.
/// </summary> /// </summary>
public int PinNumber { get; } public Int32 PinNumber {
get;
}
/// <summary> /// <summary>
/// Gets the WiringPi Pin number /// Gets the WiringPi Pin number
/// </summary> /// </summary>
public WiringPiPin WiringPiPinNumber { get; } public WiringPiPin WiringPiPinNumber {
get;
}
/// <summary> /// <summary>
/// Gets the BCM chip (hardware) pin number. /// Gets the BCM chip (hardware) pin number.
/// </summary> /// </summary>
public int BcmPinNumber { get; } public Int32 BcmPinNumber {
get;
}
/// <summary> /// <summary>
/// Gets or the physical header (physical board) pin number. /// Gets or the physical header (physical board) pin number.
/// </summary> /// </summary>
public int HeaderPinNumber { get; } public Int32 HeaderPinNumber {
get;
}
/// <summary> /// <summary>
/// Gets the pin's header (physical board) location. /// Gets the pin's header (physical board) location.
/// </summary> /// </summary>
public GpioHeader Header { get; } public GpioHeader Header {
get;
}
/// <summary> /// <summary>
/// Gets the friendly name of the pin. /// Gets the friendly name of the pin.
/// </summary> /// </summary>
public string Name { get; private set; } public String Name {
get; private set;
}
/// <summary> /// <summary>
/// Gets the hardware mode capabilities of this pin. /// Gets the hardware mode capabilities of this pin.
/// </summary> /// </summary>
public PinCapability[] Capabilities { get; private set; } public PinCapability[] Capabilities {
get; private set;
}
#endregion #endregion
@ -93,26 +104,22 @@
/// The pin mode. /// The pin mode.
/// </value> /// </value>
/// <exception cref="NotSupportedException">Thrown when a pin does not support the given operation mode.</exception> /// <exception cref="NotSupportedException">Thrown when a pin does not support the given operation mode.</exception>
public GpioPinDriveMode PinMode public GpioPinDriveMode PinMode {
{ get => this.m_PinMode;
get => m_PinMode;
set set {
{ lock(this._syncLock) {
lock (_syncLock) GpioPinDriveMode mode = value;
{ if(mode == GpioPinDriveMode.GpioClock && this.Capabilities.Contains(PinCapability.GPCLK) == false ||
var mode = value; mode == GpioPinDriveMode.PwmOutput && this.Capabilities.Contains(PinCapability.PWM) == false ||
if ((mode == GpioPinDriveMode.GpioClock && Capabilities.Contains(PinCapability.GPCLK) == false) || mode == GpioPinDriveMode.Input && this.Capabilities.Contains(PinCapability.GP) == false ||
(mode == GpioPinDriveMode.PwmOutput && Capabilities.Contains(PinCapability.PWM) == false) || mode == GpioPinDriveMode.Output && this.Capabilities.Contains(PinCapability.GP) == false) {
(mode == GpioPinDriveMode.Input && Capabilities.Contains(PinCapability.GP) == false) ||
(mode == GpioPinDriveMode.Output && Capabilities.Contains(PinCapability.GP) == false))
{
throw new NotSupportedException( 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); WiringPi.PinMode(this.PinNumber, (Int32)mode);
m_PinMode = mode; this.m_PinMode = mode;
} }
} }
} }
@ -121,7 +128,9 @@
/// Gets the interrupt callback. Returns null if no interrupt /// Gets the interrupt callback. Returns null if no interrupt
/// has been registered. /// has been registered.
/// </summary> /// </summary>
public InterruptServiceRoutineCallback InterruptCallback { get; private set; } public InterruptServiceRoutineCallback InterruptCallback {
get; private set;
}
/// <summary> /// <summary>
/// Gets the interrupt edge detection mode. /// 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 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. /// The internal pull up/down resistors have a value of approximately 50KΩ on the Raspberry Pi.
/// </summary> /// </summary>
public GpioPinResistorPullMode InputPullMode public GpioPinResistorPullMode InputPullMode {
{ get => this.PinMode == GpioPinDriveMode.Input ? this.m_ResistorPullMode : GpioPinResistorPullMode.Off;
get => PinMode == GpioPinDriveMode.Input ? m_ResistorPullMode : GpioPinResistorPullMode.Off;
set set {
{ lock(this._syncLock) {
lock (_syncLock) if(this.PinMode != GpioPinDriveMode.Input) {
{ this.m_ResistorPullMode = GpioPinResistorPullMode.Off;
if (PinMode != GpioPinDriveMode.Input)
{
m_ResistorPullMode = GpioPinResistorPullMode.Off;
throw new InvalidOperationException( throw new InvalidOperationException(
$"Unable to set the {nameof(InputPullMode)} for pin {PinNumber} because operating mode is {PinMode}." $"Unable to set the {nameof(this.InputPullMode)} for pin {this.PinNumber} because operating mode is {this.PinMode}."
+ $" Setting the {nameof(InputPullMode)} is only allowed if {nameof(PinMode)} is set to {GpioPinDriveMode.Input}"); + $" Setting the {nameof(this.InputPullMode)} is only allowed if {nameof(this.PinMode)} is set to {GpioPinDriveMode.Input}");
} }
WiringPi.PullUpDnControl(PinNumber, (int)value); WiringPi.PullUpDnControl(this.PinNumber, (Int32)value);
m_ResistorPullMode = value; this.m_ResistorPullMode = value;
} }
} }
} }
@ -166,27 +171,23 @@
/// <value> /// <value>
/// The PWM register. /// The PWM register.
/// </value> /// </value>
public int PwmRegister public Int32 PwmRegister {
{ get => this.m_PwmRegister;
get => m_PwmRegister;
set set {
{ lock(this._syncLock) {
lock (_syncLock) if(this.PinMode != GpioPinDriveMode.PwmOutput) {
{ this.m_PwmRegister = 0;
if (PinMode != GpioPinDriveMode.PwmOutput)
{
m_PwmRegister = 0;
throw new InvalidOperationException( throw new InvalidOperationException(
$"Unable to write PWM register for pin {PinNumber} because operating mode is {PinMode}." $"Unable to write PWM register for pin {this.PinNumber} because operating mode is {this.PinMode}."
+ $" Writing the PWM register is only allowed if {nameof(PinMode)} is set to {GpioPinDriveMode.PwmOutput}"); + $" 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); WiringPi.PwmWrite(this.PinNumber, val);
m_PwmRegister = val; this.m_PwmRegister = val;
} }
} }
} }
@ -199,25 +200,21 @@
/// The PWM mode. /// The PWM mode.
/// </value> /// </value>
/// <exception cref="InvalidOperationException">When pin mode is not set a Pwn output</exception> /// <exception cref="InvalidOperationException">When pin mode is not set a Pwn output</exception>
public PwmMode PwmMode public PwmMode PwmMode {
{ get => this.PinMode == GpioPinDriveMode.PwmOutput ? this.m_PwmMode : PwmMode.Balanced;
get => PinMode == GpioPinDriveMode.PwmOutput ? m_PwmMode : PwmMode.Balanced;
set set {
{ lock(this._syncLock) {
lock (_syncLock) if(this.PinMode != GpioPinDriveMode.PwmOutput) {
{ this.m_PwmMode = PwmMode.Balanced;
if (PinMode != GpioPinDriveMode.PwmOutput)
{
m_PwmMode = PwmMode.Balanced;
throw new InvalidOperationException( throw new InvalidOperationException(
$"Unable to set PWM mode for pin {PinNumber} because operating mode is {PinMode}." $"Unable to set PWM mode for pin {this.PinNumber} because operating mode is {this.PinMode}."
+ $" Setting the PWM mode is only allowed if {nameof(PinMode)} is set to {GpioPinDriveMode.PwmOutput}"); + $" Setting the PWM mode is only allowed if {nameof(this.PinMode)} is set to {GpioPinDriveMode.PwmOutput}");
} }
WiringPi.PwmSetMode((int)value); WiringPi.PwmSetMode((Int32)value);
m_PwmMode = value; this.m_PwmMode = value;
} }
} }
} }
@ -229,25 +226,21 @@
/// The PWM range. /// The PWM range.
/// </value> /// </value>
/// <exception cref="InvalidOperationException">When pin mode is not set to PWM output</exception> /// <exception cref="InvalidOperationException">When pin mode is not set to PWM output</exception>
public uint PwmRange public UInt32 PwmRange {
{ get => this.PinMode == GpioPinDriveMode.PwmOutput ? this.m_PwmRange : 0;
get => PinMode == GpioPinDriveMode.PwmOutput ? m_PwmRange : 0;
set set {
{ lock(this._syncLock) {
lock (_syncLock) if(this.PinMode != GpioPinDriveMode.PwmOutput) {
{ this.m_PwmRange = 1024;
if (PinMode != GpioPinDriveMode.PwmOutput)
{
m_PwmRange = 1024;
throw new InvalidOperationException( throw new InvalidOperationException(
$"Unable to set PWM range for pin {PinNumber} because operating mode is {PinMode}." $"Unable to set PWM range for pin {this.PinNumber} because operating mode is {this.PinMode}."
+ $" Setting the PWM range is only allowed if {nameof(PinMode)} is set to {GpioPinDriveMode.PwmOutput}"); + $" Setting the PWM range is only allowed if {nameof(this.PinMode)} is set to {GpioPinDriveMode.PwmOutput}");
} }
WiringPi.PwmSetRange(value); WiringPi.PwmSetRange(value);
m_PwmRange = value; this.m_PwmRange = value;
} }
} }
} }
@ -259,25 +252,21 @@
/// The PWM clock divisor. /// The PWM clock divisor.
/// </value> /// </value>
/// <exception cref="InvalidOperationException">When pin mode is not set to PWM output</exception> /// <exception cref="InvalidOperationException">When pin mode is not set to PWM output</exception>
public int PwmClockDivisor public Int32 PwmClockDivisor {
{ get => this.PinMode == GpioPinDriveMode.PwmOutput ? this.m_PwmClockDivisor : 0;
get => PinMode == GpioPinDriveMode.PwmOutput ? m_PwmClockDivisor : 0;
set set {
{ lock(this._syncLock) {
lock (_syncLock) if(this.PinMode != GpioPinDriveMode.PwmOutput) {
{ this.m_PwmClockDivisor = 1;
if (PinMode != GpioPinDriveMode.PwmOutput)
{
m_PwmClockDivisor = 1;
throw new InvalidOperationException( throw new InvalidOperationException(
$"Unable to set PWM range for pin {PinNumber} because operating mode is {PinMode}." $"Unable to set PWM range for pin {this.PinNumber} because operating mode is {this.PinMode}."
+ $" Setting the PWM range is only allowed if {nameof(PinMode)} is set to {GpioPinDriveMode.PwmOutput}"); + $" Setting the PWM range is only allowed if {nameof(this.PinMode)} is set to {GpioPinDriveMode.PwmOutput}");
} }
WiringPi.PwmSetClock(value); WiringPi.PwmSetClock(value);
m_PwmClockDivisor = value; this.m_PwmClockDivisor = value;
} }
} }
} }
@ -292,7 +281,7 @@
/// <value> /// <value>
/// <c>true</c> if this instance is in soft tone mode; otherwise, <c>false</c>. /// <c>true</c> if this instance is in soft tone mode; otherwise, <c>false</c>.
/// </value> /// </value>
public bool IsInSoftToneMode => m_SoftToneFrequency >= 0; public Boolean IsInSoftToneMode => this.m_SoftToneFrequency >= 0;
/// <summary> /// <summary>
/// Gets or sets the soft tone frequency. 0 to 5000 Hz is typical /// Gets or sets the soft tone frequency. 0 to 5000 Hz is typical
@ -301,26 +290,21 @@
/// The soft tone frequency. /// The soft tone frequency.
/// </value> /// </value>
/// <exception cref="InvalidOperationException">When soft tones cannot be initialized on the pin</exception> /// <exception cref="InvalidOperationException">When soft tones cannot be initialized on the pin</exception>
public int SoftToneFrequency public Int32 SoftToneFrequency {
{ get => this.m_SoftToneFrequency;
get => m_SoftToneFrequency;
set set {
{ lock(this._syncLock) {
lock (_syncLock) if(this.IsInSoftToneMode == false) {
{ Int32 setupResult = WiringPi.SoftToneCreate(this.PinNumber);
if (IsInSoftToneMode == false) if(setupResult != 0) {
{
var setupResult = WiringPi.SoftToneCreate(PinNumber);
if (setupResult != 0)
{
throw new InvalidOperationException( 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); WiringPi.SoftToneWrite(this.PinNumber, value);
m_SoftToneFrequency = value; this.m_SoftToneFrequency = value;
} }
} }
} }
@ -335,7 +319,7 @@
/// <value> /// <value>
/// <c>true</c> if this instance is in soft PWM mode; otherwise, <c>false</c>. /// <c>true</c> if this instance is in soft PWM mode; otherwise, <c>false</c>.
/// </value> /// </value>
public bool IsInSoftPwmMode => m_SoftPwmValue >= 0; public Boolean IsInSoftPwmMode => this.m_SoftPwmValue >= 0;
/// <summary> /// <summary>
/// Gets or sets the software PWM value on the pin. /// Gets or sets the software PWM value on the pin.
@ -344,21 +328,15 @@
/// The soft PWM value. /// The soft PWM value.
/// </value> /// </value>
/// <exception cref="InvalidOperationException">StartSoftPwm</exception> /// <exception cref="InvalidOperationException">StartSoftPwm</exception>
public int SoftPwmValue public Int32 SoftPwmValue {
{ get => this.m_SoftPwmValue;
get => m_SoftPwmValue;
set set {
{ lock(this._syncLock) {
lock (_syncLock) if(this.IsInSoftPwmMode && value >= 0) {
{ WiringPi.SoftPwmWrite(this.PinNumber, value);
if (IsInSoftPwmMode && value >= 0) this.m_SoftPwmValue = value;
{ } else {
WiringPi.SoftPwmWrite(PinNumber, value);
m_SoftPwmValue = value;
}
else
{
throw new InvalidOperationException($"Software PWM requires a call to {nameof(StartSoftPwm)}."); throw new InvalidOperationException($"Software PWM requires a call to {nameof(StartSoftPwm)}.");
} }
} }
@ -368,7 +346,7 @@
/// <summary> /// <summary>
/// Gets the software PWM range used upon starting the PWM. /// Gets the software PWM range used upon starting the PWM.
/// </summary> /// </summary>
public int SoftPwmRange { get; private set; } = -1; public Int32 SoftPwmRange { get; private set; } = -1;
/// <summary> /// <summary>
/// Starts the software based PWM on this pin. /// 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="NotSupportedException">When the pin does not suppoert PWM</exception>
/// <exception cref="InvalidOperationException">StartSoftPwm /// <exception cref="InvalidOperationException">StartSoftPwm
/// or</exception> /// or</exception>
public void StartSoftPwm(int value, int range) public void StartSoftPwm(Int32 value, Int32 range) {
{ lock(this._syncLock) {
lock (_syncLock) if(this.Capabilities.Contains(PinCapability.GP) == false) {
{ throw new NotSupportedException($"Pin {this.PinNumber} does not support software PWM");
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;
} }
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( 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 /// This method performs a digital write
/// </summary> /// </summary>
/// <param name="value">The value.</param> /// <param name="value">The value.</param>
public void Write(GpioPinValue value) public void Write(GpioPinValue value) {
{ lock(this._syncLock) {
lock (_syncLock) if(this.PinMode != GpioPinDriveMode.Output) {
{
if (PinMode != GpioPinDriveMode.Output)
{
throw new InvalidOperationException( throw new InvalidOperationException(
$"Unable to write to pin {PinNumber} because operating mode is {PinMode}." $"Unable to write to pin {this.PinNumber} because operating mode is {this.PinMode}."
+ $" Writes are only allowed if {nameof(PinMode)} is set to {GpioPinDriveMode.Output}"); + $" 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> /// </summary>
/// <param name="value">The value.</param> /// <param name="value">The value.</param>
/// <returns>The awaitable task</returns> /// <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> /// <summary>
/// Writes the specified bit value. /// Writes the specified bit value.
/// This method performs a digital write /// This method performs a digital write
/// </summary> /// </summary>
/// <param name="value">if set to <c>true</c> [value].</param> /// <param name="value">if set to <c>true</c> [value].</param>
public void Write(bool value) public void Write(Boolean value)
=> Write(value ? GpioPinValue.High : GpioPinValue.Low); => this.Write(value ? GpioPinValue.High : GpioPinValue.Low);
/// <summary> /// <summary>
/// Writes the specified bit value. /// Writes the specified bit value.
@ -450,14 +422,14 @@
/// <returns> /// <returns>
/// The awaitable task /// The awaitable task
/// </returns> /// </returns>
public Task WriteAsync(bool value) => Task.Run(() => { Write(value); }); public Task WriteAsync(Boolean value) => Task.Run(() => this.Write(value));
/// <summary> /// <summary>
/// Writes the specified value. 0 for low, any other value for high /// Writes the specified value. 0 for low, any other value for high
/// This method performs a digital write /// This method performs a digital write
/// </summary> /// </summary>
/// <param name="value">The value.</param> /// <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> /// <summary>
/// Writes the specified value. 0 for low, any other value for high /// Writes the specified value. 0 for low, any other value for high
@ -465,25 +437,22 @@
/// </summary> /// </summary>
/// <param name="value">The value.</param> /// <param name="value">The value.</param>
/// <returns>The awaitable task</returns> /// <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> /// <summary>
/// Writes the specified value as an analog level. /// 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. /// You will need to register additional analog modules to enable this function for devices such as the Gertboard.
/// </summary> /// </summary>
/// <param name="value">The value.</param> /// <param name="value">The value.</param>
public void WriteLevel(int value) public void WriteLevel(Int32 value) {
{ lock(this._syncLock) {
lock (_syncLock) if(this.PinMode != GpioPinDriveMode.Output) {
{
if (PinMode != GpioPinDriveMode.Output)
{
throw new InvalidOperationException( throw new InvalidOperationException(
$"Unable to write to pin {PinNumber} because operating mode is {PinMode}." $"Unable to write to pin {this.PinNumber} because operating mode is {this.PinMode}."
+ $" Writes are only allowed if {nameof(PinMode)} is set to {GpioPinDriveMode.Output}"); + $" 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> /// </summary>
/// <param name="value">The value.</param> /// <param name="value">The value.</param>
/// <returns>The awaitable task</returns> /// <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 #endregion
@ -505,21 +474,19 @@
/// <param name="status">status to check</param> /// <param name="status">status to check</param>
/// <param name="timeOutMillisecond">timeout to reach status</param> /// <param name="timeOutMillisecond">timeout to reach status</param>
/// <returns>true/false</returns> /// <returns>true/false</returns>
public bool WaitForValue(GpioPinValue status, int timeOutMillisecond) public Boolean WaitForValue(GpioPinValue status, Int32 timeOutMillisecond) {
{ if(this.PinMode != GpioPinDriveMode.Input) {
if (PinMode != GpioPinDriveMode.Input)
{
throw new InvalidOperationException( throw new InvalidOperationException(
$"Unable to read from pin {PinNumber} because operating mode is {PinMode}." $"Unable to read from pin {this.PinNumber} because operating mode is {this.PinMode}."
+ $" Reads are only allowed if {nameof(PinMode)} is set to {GpioPinDriveMode.Input}"); + $" Reads are only allowed if {nameof(this.PinMode)} is set to {GpioPinDriveMode.Input}");
} }
var hrt = new HighResolutionTimer(); HighResolutionTimer hrt = new HighResolutionTimer();
hrt.Start(); hrt.Start();
do do {
{ if(this.ReadValue() == status) {
if (ReadValue() == status)
return true; return true;
}
Pi.Timing.SleepMicroseconds(101); // 101 uses nanosleep as opposed to a loop. 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. /// Reads the digital value on the pin as a boolean value.
/// </summary> /// </summary>
/// <returns>The state of the pin</returns> /// <returns>The state of the pin</returns>
public bool Read() public Boolean Read() {
{ lock(this._syncLock) {
lock (_syncLock) if(this.PinMode != GpioPinDriveMode.Input && this.PinMode != GpioPinDriveMode.Output) {
{
if (PinMode != GpioPinDriveMode.Input && PinMode != GpioPinDriveMode.Output)
{
throw new InvalidOperationException( throw new InvalidOperationException(
$"Unable to read from pin {PinNumber} because operating mode is {PinMode}." $"Unable to read from pin {this.PinNumber} because operating mode is {this.PinMode}."
+ $" Reads are only allowed if {nameof(PinMode)} is set to {GpioPinDriveMode.Input} or {GpioPinDriveMode.Output}"); + $" 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. /// Reads the digital value on the pin as a boolean value.
/// </summary> /// </summary>
/// <returns>The state of the pin</returns> /// <returns>The state of the pin</returns>
public Task<bool> ReadAsync() => Task.Run(() => Read()); public Task<Boolean> ReadAsync() => Task.Run(() => this.Read());
/// <summary> /// <summary>
/// Reads the digital value on the pin as a High or Low value. /// Reads the digital value on the pin as a High or Low value.
/// </summary> /// </summary>
/// <returns>The state of the pin</returns> /// <returns>The state of the pin</returns>
public GpioPinValue ReadValue() public GpioPinValue ReadValue()
=> Read() ? GpioPinValue.High : GpioPinValue.Low; => this.Read() ? GpioPinValue.High : GpioPinValue.Low;
/// <summary> /// <summary>
/// Reads the digital value on the pin as a High or Low value. /// Reads the digital value on the pin as a High or Low value.
/// </summary> /// </summary>
/// <returns>The state of the pin</returns> /// <returns>The state of the pin</returns>
public Task<GpioPinValue> ReadValueAsync() => Task.Run(() => ReadValue()); public Task<GpioPinValue> ReadValueAsync() => Task.Run(() => this.ReadValue());
/// <summary> /// <summary>
/// Reads the analog value on the pin. /// Reads the analog value on the pin.
@ -574,18 +538,15 @@
/// </summary> /// </summary>
/// <returns>The analog level</returns> /// <returns>The analog level</returns>
/// <exception cref="InvalidOperationException">When the pin mode is not configured as an input.</exception> /// <exception cref="InvalidOperationException">When the pin mode is not configured as an input.</exception>
public int ReadLevel() public Int32 ReadLevel() {
{ lock(this._syncLock) {
lock (_syncLock) if(this.PinMode != GpioPinDriveMode.Input) {
{
if (PinMode != GpioPinDriveMode.Input)
{
throw new InvalidOperationException( throw new InvalidOperationException(
$"Unable to read from pin {PinNumber} because operating mode is {PinMode}." $"Unable to read from pin {this.PinNumber} because operating mode is {this.PinMode}."
+ $" Reads are only allowed if {nameof(PinMode)} is set to {GpioPinDriveMode.Input}"); + $" 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. /// quick2Wire analog board, etc.
/// </summary> /// </summary>
/// <returns>The analog level</returns> /// <returns>The analog level</returns>
public Task<int> ReadLevelAsync() => Task.Run(() => ReadLevel()); public Task<Int32> ReadLevelAsync() => Task.Run(() => this.ReadLevel());
#endregion #endregion
@ -613,31 +574,27 @@
/// or /// or
/// RegisterInterruptCallback /// RegisterInterruptCallback
/// </exception> /// </exception>
public void RegisterInterruptCallback(EdgeDetection edgeDetection, InterruptServiceRoutineCallback callback) public void RegisterInterruptCallback(EdgeDetection edgeDetection, InterruptServiceRoutineCallback callback) {
{ if(callback == null) {
if (callback == null)
throw new ArgumentException($"{nameof(callback)} cannot be 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."); throw new InvalidOperationException("An interrupt callback was already registered.");
}
if (PinMode != GpioPinDriveMode.Input) if(this.PinMode != GpioPinDriveMode.Input) {
{
throw new InvalidOperationException( throw new InvalidOperationException(
$"Unable to {nameof(RegisterInterruptCallback)} for pin {PinNumber} because operating mode is {PinMode}." $"Unable to {nameof(RegisterInterruptCallback)} for pin {this.PinNumber} because operating mode is {this.PinMode}."
+ $" Calling {nameof(RegisterInterruptCallback)} is only allowed if {nameof(PinMode)} is set to {GpioPinDriveMode.Input}"); + $" Calling {nameof(RegisterInterruptCallback)} is only allowed if {nameof(this.PinMode)} is set to {GpioPinDriveMode.Input}");
} }
lock (_syncLock) lock(this._syncLock) {
{ Int32 registerResult = WiringPi.WiringPiISR(this.PinNumber, (Int32)edgeDetection, callback);
var registerResult = WiringPi.WiringPiISR(PinNumber, (int)edgeDetection, callback); if(registerResult == 0) {
if (registerResult == 0) this.InterruptEdgeDetection = edgeDetection;
{ this.InterruptCallback = callback;
InterruptEdgeDetection = edgeDetection; } else {
InterruptCallback = callback;
}
else
{
HardwareException.Throw(nameof(GpioPin), nameof(RegisterInterruptCallback)); HardwareException.Throw(nameof(GpioPin), nameof(RegisterInterruptCallback));
} }
} }

View File

@ -1,32 +1,30 @@
namespace Unosquare.RaspberryIO.Gpio using Unosquare.RaspberryIO.Native;
{ using Unosquare.Swan.Abstractions;
using Native;
using Swan.Abstractions;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Linq; using System.Linq;
using System;
namespace Unosquare.RaspberryIO.Gpio {
/// <summary> /// <summary>
/// A simple wrapper for the I2c bus on the Raspberry Pi /// A simple wrapper for the I2c bus on the Raspberry Pi
/// </summary> /// </summary>
public class I2CBus : SingletonBase<I2CBus> public class I2CBus : SingletonBase<I2CBus> {
{
// TODO: It would be nice to integrate i2c device detection. // TODO: It would be nice to integrate i2c device detection.
private static readonly object SyncRoot = new object(); private static readonly Object SyncRoot = new Object();
private readonly Dictionary<int, I2CDevice> _devices = new Dictionary<int, I2CDevice>(); private readonly Dictionary<Int32, I2CDevice> _devices = new Dictionary<Int32, I2CDevice>();
/// <summary> /// <summary>
/// Prevents a default instance of the <see cref="I2CBus"/> class from being created. /// Prevents a default instance of the <see cref="I2CBus"/> class from being created.
/// </summary> /// </summary>
private I2CBus() private I2CBus() {
{
// placeholder // placeholder
} }
/// <summary> /// <summary>
/// Gets the registered devices as a read only collection. /// Gets the registered devices as a read only collection.
/// </summary> /// </summary>
public ReadOnlyCollection<I2CDevice> Devices => new ReadOnlyCollection<I2CDevice>(_devices.Values.ToArray()); public ReadOnlyCollection<I2CDevice> Devices => new ReadOnlyCollection<I2CDevice>(this._devices.Values.ToArray());
/// <summary> /// <summary>
/// Gets the <see cref="I2CDevice"/> with the specified device identifier. /// Gets the <see cref="I2CDevice"/> with the specified device identifier.
@ -36,18 +34,16 @@
/// </value> /// </value>
/// <param name="deviceId">The device identifier.</param> /// <param name="deviceId">The device identifier.</param>
/// <returns>A reference to an I2C device</returns> /// <returns>A reference to an I2C device</returns>
public I2CDevice this[int deviceId] => GetDeviceById(deviceId); public I2CDevice this[Int32 deviceId] => this.GetDeviceById(deviceId);
/// <summary> /// <summary>
/// Gets the device by identifier. /// Gets the device by identifier.
/// </summary> /// </summary>
/// <param name="deviceId">The device identifier.</param> /// <param name="deviceId">The device identifier.</param>
/// <returns>The device reference</returns> /// <returns>The device reference</returns>
public I2CDevice GetDeviceById(int deviceId) public I2CDevice GetDeviceById(Int32 deviceId) {
{ lock(SyncRoot) {
lock (SyncRoot) return this._devices[deviceId];
{
return _devices[deviceId];
} }
} }
@ -57,19 +53,19 @@
/// <param name="deviceId">The device identifier.</param> /// <param name="deviceId">The device identifier.</param>
/// <returns>The device reference</returns> /// <returns>The device reference</returns>
/// <exception cref="KeyNotFoundException">When the device file descriptor is not found</exception> /// <exception cref="KeyNotFoundException">When the device file descriptor is not found</exception>
public I2CDevice AddDevice(int deviceId) public I2CDevice AddDevice(Int32 deviceId) {
{ lock(SyncRoot) {
lock (SyncRoot) if(this._devices.ContainsKey(deviceId)) {
{ return this._devices[deviceId];
if (_devices.ContainsKey(deviceId)) }
return _devices[deviceId];
var fileDescriptor = SetupFileDescriptor(deviceId); Int32 fileDescriptor = SetupFileDescriptor(deviceId);
if (fileDescriptor < 0) if(fileDescriptor < 0) {
throw new KeyNotFoundException($"Device with id {deviceId} could not be registered with the I2C bus. Error Code: {fileDescriptor}."); throw new KeyNotFoundException($"Device with id {deviceId} could not be registered with the I2C bus. Error Code: {fileDescriptor}.");
}
var device = new I2CDevice(deviceId, fileDescriptor); I2CDevice device = new I2CDevice(deviceId, fileDescriptor);
_devices[deviceId] = device; this._devices[deviceId] = device;
return device; return device;
} }
} }
@ -82,10 +78,8 @@
/// </summary> /// </summary>
/// <param name="deviceId">The device identifier.</param> /// <param name="deviceId">The device identifier.</param>
/// <returns>The Linux file handle</returns> /// <returns>The Linux file handle</returns>
private static int SetupFileDescriptor(int deviceId) private static Int32 SetupFileDescriptor(Int32 deviceId) {
{ lock(SyncRoot) {
lock (SyncRoot)
{
return WiringPi.WiringPiI2CSetup(deviceId); return WiringPi.WiringPiI2CSetup(deviceId);
} }
} }

View File

@ -1,25 +1,22 @@
namespace Unosquare.RaspberryIO.Gpio using System;
{
using System;
using System.Threading.Tasks; using System.Threading.Tasks;
using Native; using Unosquare.RaspberryIO.Native;
namespace Unosquare.RaspberryIO.Gpio {
/// <summary> /// <summary>
/// Represents a device on the I2C Bus /// Represents a device on the I2C Bus
/// </summary> /// </summary>
public class I2CDevice public class I2CDevice {
{ private readonly Object _syncLock = new Object();
private readonly object _syncLock = new object();
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="I2CDevice"/> class. /// Initializes a new instance of the <see cref="I2CDevice"/> class.
/// </summary> /// </summary>
/// <param name="deviceId">The device identifier.</param> /// <param name="deviceId">The device identifier.</param>
/// <param name="fileDescriptor">The file descriptor.</param> /// <param name="fileDescriptor">The file descriptor.</param>
internal I2CDevice(int deviceId, int fileDescriptor) internal I2CDevice(Int32 deviceId, Int32 fileDescriptor) {
{ this.DeviceId = deviceId;
DeviceId = deviceId; this.FileDescriptor = fileDescriptor;
FileDescriptor = fileDescriptor;
} }
/// <summary> /// <summary>
@ -28,7 +25,9 @@
/// <value> /// <value>
/// The device identifier. /// The device identifier.
/// </value> /// </value>
public int DeviceId { get; } public Int32 DeviceId {
get;
}
/// <summary> /// <summary>
/// Gets the standard POSIX file descriptor. /// Gets the standard POSIX file descriptor.
@ -36,19 +35,22 @@
/// <value> /// <value>
/// The file descriptor. /// The file descriptor.
/// </value> /// </value>
public int FileDescriptor { get; } public Int32 FileDescriptor {
get;
}
/// <summary> /// <summary>
/// Reads a byte from the specified file descriptor /// Reads a byte from the specified file descriptor
/// </summary> /// </summary>
/// <returns>The byte from device</returns> /// <returns>The byte from device</returns>
public byte Read() public Byte Read() {
{ lock(this._syncLock) {
lock (_syncLock) Int32 result = WiringPi.WiringPiI2CRead(this.FileDescriptor);
{ if(result < 0) {
var result = WiringPi.WiringPiI2CRead(FileDescriptor); HardwareException.Throw(nameof(I2CDevice), nameof(Read));
if (result < 0) HardwareException.Throw(nameof(I2CDevice), nameof(Read)); }
return (byte)result;
return (Byte)result;
} }
} }
@ -56,23 +58,23 @@
/// Reads a byte from the specified file descriptor /// Reads a byte from the specified file descriptor
/// </summary> /// </summary>
/// <returns>The byte from device</returns> /// <returns>The byte from device</returns>
public Task<byte> ReadAsync() => Task.Run(() => Read()); public Task<Byte> ReadAsync() => Task.Run(() => this.Read());
/// <summary> /// <summary>
/// Reads a buffer of the specified length, one byte at a time /// Reads a buffer of the specified length, one byte at a time
/// </summary> /// </summary>
/// <param name="length">The length.</param> /// <param name="length">The length.</param>
/// <returns>The byte array from device</returns> /// <returns>The byte array from device</returns>
public byte[] Read(int length) public Byte[] Read(Int32 length) {
{ lock(this._syncLock) {
lock (_syncLock) Byte[] buffer = new Byte[length];
{ for(Int32 i = 0; i < length; i++) {
var buffer = new byte[length]; Int32 result = WiringPi.WiringPiI2CRead(this.FileDescriptor);
for (var i = 0; i < length; i++) if(result < 0) {
{ HardwareException.Throw(nameof(I2CDevice), nameof(Read));
var result = WiringPi.WiringPiI2CRead(FileDescriptor); }
if (result < 0) HardwareException.Throw(nameof(I2CDevice), nameof(Read));
buffer[i] = (byte)result; buffer[i] = (Byte)result;
} }
return buffer; return buffer;
@ -84,18 +86,18 @@
/// </summary> /// </summary>
/// <param name="length">The length.</param> /// <param name="length">The length.</param>
/// <returns>The byte array from device</returns> /// <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> /// <summary>
/// Writes a byte of data the specified file descriptor. /// Writes a byte of data the specified file descriptor.
/// </summary> /// </summary>
/// <param name="data">The data.</param> /// <param name="data">The data.</param>
public void Write(byte data) public void Write(Byte data) {
{ lock(this._syncLock) {
lock (_syncLock) Int32 result = WiringPi.WiringPiI2CWrite(this.FileDescriptor, data);
{ if(result < 0) {
var result = WiringPi.WiringPiI2CWrite(FileDescriptor, data); HardwareException.Throw(nameof(I2CDevice), nameof(Write));
if (result < 0) HardwareException.Throw(nameof(I2CDevice), nameof(Write)); }
} }
} }
@ -104,20 +106,19 @@
/// </summary> /// </summary>
/// <param name="data">The data.</param> /// <param name="data">The data.</param>
/// <returns>The awaitable task</returns> /// <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> /// <summary>
/// Writes a set of bytes to the specified file descriptor. /// Writes a set of bytes to the specified file descriptor.
/// </summary> /// </summary>
/// <param name="data">The data.</param> /// <param name="data">The data.</param>
public void Write(byte[] data) public void Write(Byte[] data) {
{ lock(this._syncLock) {
lock (_syncLock) foreach(Byte b in data) {
{ Int32 result = WiringPi.WiringPiI2CWrite(this.FileDescriptor, b);
foreach (var b in data) if(result < 0) {
{ HardwareException.Throw(nameof(I2CDevice), nameof(Write));
var result = WiringPi.WiringPiI2CWrite(FileDescriptor, b); }
if (result < 0) HardwareException.Throw(nameof(I2CDevice), nameof(Write));
} }
} }
} }
@ -127,22 +128,19 @@
/// </summary> /// </summary>
/// <param name="data">The data.</param> /// <param name="data">The data.</param>
/// <returns>The awaitable task</returns> /// <returns>The awaitable task</returns>
public Task WriteAsync(byte[] data) public Task WriteAsync(Byte[] data) => Task.Run(() => this.Write(data));
{
return Task.Run(() => { Write(data); });
}
/// <summary> /// <summary>
/// These write an 8 or 16-bit data value into the device register indicated. /// These write an 8 or 16-bit data value into the device register indicated.
/// </summary> /// </summary>
/// <param name="address">The register.</param> /// <param name="address">The register.</param>
/// <param name="data">The data.</param> /// <param name="data">The data.</param>
public void WriteAddressByte(int address, byte data) public void WriteAddressByte(Int32 address, Byte data) {
{ lock(this._syncLock) {
lock (_syncLock) Int32 result = WiringPi.WiringPiI2CWriteReg8(this.FileDescriptor, address, data);
{ if(result < 0) {
var result = WiringPi.WiringPiI2CWriteReg8(FileDescriptor, address, data); HardwareException.Throw(nameof(I2CDevice), nameof(WriteAddressByte));
if (result < 0) HardwareException.Throw(nameof(I2CDevice), nameof(WriteAddressByte)); }
} }
} }
@ -151,12 +149,12 @@
/// </summary> /// </summary>
/// <param name="address">The register.</param> /// <param name="address">The register.</param>
/// <param name="data">The data.</param> /// <param name="data">The data.</param>
public void WriteAddressWord(int address, ushort data) public void WriteAddressWord(Int32 address, UInt16 data) {
{ lock(this._syncLock) {
lock (_syncLock) Int32 result = WiringPi.WiringPiI2CWriteReg16(this.FileDescriptor, address, data);
{ if(result < 0) {
var result = WiringPi.WiringPiI2CWriteReg16(FileDescriptor, address, data); HardwareException.Throw(nameof(I2CDevice), nameof(WriteAddressWord));
if (result < 0) HardwareException.Throw(nameof(I2CDevice), nameof(WriteAddressWord)); }
} }
} }
@ -165,14 +163,14 @@
/// </summary> /// </summary>
/// <param name="address">The register.</param> /// <param name="address">The register.</param>
/// <returns>The address byte from device</returns> /// <returns>The address byte from device</returns>
public byte ReadAddressByte(int address) public Byte ReadAddressByte(Int32 address) {
{ lock(this._syncLock) {
lock (_syncLock) Int32 result = WiringPi.WiringPiI2CReadReg8(this.FileDescriptor, address);
{ if(result < 0) {
var result = WiringPi.WiringPiI2CReadReg8(FileDescriptor, address); HardwareException.Throw(nameof(I2CDevice), nameof(ReadAddressByte));
if (result < 0) HardwareException.Throw(nameof(I2CDevice), nameof(ReadAddressByte)); }
return (byte)result; return (Byte)result;
} }
} }
@ -181,12 +179,12 @@
/// </summary> /// </summary>
/// <param name="address">The register.</param> /// <param name="address">The register.</param>
/// <returns>The address word from device</returns> /// <returns>The address word from device</returns>
public ushort ReadAddressWord(int address) public UInt16 ReadAddressWord(Int32 address) {
{ lock(this._syncLock) {
lock (_syncLock) Int32 result = WiringPi.WiringPiI2CReadReg16(this.FileDescriptor, address);
{ if(result < 0) {
var result = WiringPi.WiringPiI2CReadReg16(FileDescriptor, address); HardwareException.Throw(nameof(I2CDevice), nameof(ReadAddressWord));
if (result < 0) HardwareException.Throw(nameof(I2CDevice), nameof(ReadAddressWord)); }
return Convert.ToUInt16(result); return Convert.ToUInt16(result);
} }

View File

@ -1,17 +1,15 @@
namespace Unosquare.RaspberryIO.Gpio using System;
{ using Unosquare.Swan.Abstractions;
using Swan.Abstractions;
namespace Unosquare.RaspberryIO.Gpio {
/// <summary> /// <summary>
/// The SPI Bus containing the 2 SPI channels /// The SPI Bus containing the 2 SPI channels
/// </summary> /// </summary>
public class SpiBus : SingletonBase<SpiBus> public class SpiBus : SingletonBase<SpiBus> {
{
/// <summary> /// <summary>
/// Prevents a default instance of the <see cref="SpiBus"/> class from being created. /// Prevents a default instance of the <see cref="SpiBus"/> class from being created.
/// </summary> /// </summary>
private SpiBus() private SpiBus() {
{
// placeholder // placeholder
} }
@ -23,7 +21,9 @@
/// <value> /// <value>
/// The channel0 frequency. /// The channel0 frequency.
/// </value> /// </value>
public int Channel0Frequency { get; set; } public Int32 Channel0Frequency {
get; set;
}
/// <summary> /// <summary>
/// Gets the SPI bus on channel 1. /// Gets the SPI bus on channel 1.
@ -31,14 +31,13 @@
/// <value> /// <value>
/// The channel0. /// The channel0.
/// </value> /// </value>
public SpiChannel Channel0 public SpiChannel Channel0 {
{ get {
get if(this.Channel0Frequency == 0) {
{ this.Channel0Frequency = SpiChannel.DefaultFrequency;
if (Channel0Frequency == 0) }
Channel0Frequency = SpiChannel.DefaultFrequency;
return SpiChannel.Retrieve(SpiChannelNumber.Channel0, Channel0Frequency); return SpiChannel.Retrieve(SpiChannelNumber.Channel0, this.Channel0Frequency);
} }
} }
@ -48,7 +47,9 @@
/// <value> /// <value>
/// The channel1 frequency. /// The channel1 frequency.
/// </value> /// </value>
public int Channel1Frequency { get; set; } public Int32 Channel1Frequency {
get; set;
}
/// <summary> /// <summary>
/// Gets the SPI bus on channel 1. /// Gets the SPI bus on channel 1.
@ -56,14 +57,13 @@
/// <value> /// <value>
/// The channel1. /// The channel1.
/// </value> /// </value>
public SpiChannel Channel1 public SpiChannel Channel1 {
{ get {
get if(this.Channel1Frequency == 0) {
{ this.Channel1Frequency = SpiChannel.DefaultFrequency;
if (Channel1Frequency == 0) }
Channel1Frequency = SpiChannel.DefaultFrequency;
return SpiChannel.Retrieve(SpiChannelNumber.Channel1, Channel1Frequency); return SpiChannel.Retrieve(SpiChannelNumber.Channel1, this.Channel1Frequency);
} }
} }

View File

@ -1,53 +1,48 @@
namespace Unosquare.RaspberryIO.Gpio using Unosquare.RaspberryIO.Native;
{ using Unosquare.Swan;
using Native;
using Swan;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace Unosquare.RaspberryIO.Gpio {
/// <summary> /// <summary>
/// Provides access to using the SPI buses on the GPIO. /// Provides access to using the SPI buses on the GPIO.
/// SPI is a bus that works like a ring shift register /// SPI is a bus that works like a ring shift register
/// The number of bytes pushed is equal to the number of bytes received. /// The number of bytes pushed is equal to the number of bytes received.
/// </summary> /// </summary>
public sealed class SpiChannel public sealed class SpiChannel {
{
/// <summary> /// <summary>
/// The minimum frequency of an SPI Channel /// The minimum frequency of an SPI Channel
/// </summary> /// </summary>
public const int MinFrequency = 500000; public const Int32 MinFrequency = 500000;
/// <summary> /// <summary>
/// The maximum frequency of an SPI channel /// The maximum frequency of an SPI channel
/// </summary> /// </summary>
public const int MaxFrequency = 32000000; public const Int32 MaxFrequency = 32000000;
/// <summary> /// <summary>
/// The default frequency of SPI channels /// The default frequency of SPI channels
/// This is set to 8 Mhz wich is typical in modern hardware. /// This is set to 8 Mhz wich is typical in modern hardware.
/// </summary> /// </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 static readonly Dictionary<SpiChannelNumber, SpiChannel> Buses = new Dictionary<SpiChannelNumber, SpiChannel>();
private readonly object _syncLock = new object(); private readonly Object _syncLock = new Object();
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="SpiChannel"/> class. /// Initializes a new instance of the <see cref="SpiChannel"/> class.
/// </summary> /// </summary>
/// <param name="channel">The channel.</param> /// <param name="channel">The channel.</param>
/// <param name="frequency">The frequency.</param> /// <param name="frequency">The frequency.</param>
private SpiChannel(SpiChannelNumber channel, int frequency) private SpiChannel(SpiChannelNumber channel, Int32 frequency) {
{ lock(SyncRoot) {
lock (SyncRoot) this.Frequency = frequency.Clamp(MinFrequency, MaxFrequency);
{ this.Channel = (Int32)channel;
Frequency = frequency.Clamp(MinFrequency, MaxFrequency); this.FileDescriptor = WiringPi.WiringPiSPISetup((Int32)channel, this.Frequency);
Channel = (int)channel;
FileDescriptor = WiringPi.WiringPiSPISetup((int)channel, Frequency);
if (FileDescriptor < 0) if(this.FileDescriptor < 0) {
{
HardwareException.Throw(nameof(SpiChannel), channel.ToString()); HardwareException.Throw(nameof(SpiChannel), channel.ToString());
} }
} }
@ -60,35 +55,42 @@
/// <value> /// <value>
/// The file descriptor. /// The file descriptor.
/// </value> /// </value>
public int FileDescriptor { get; } public Int32 FileDescriptor {
get;
}
/// <summary> /// <summary>
/// Gets the channel. /// Gets the channel.
/// </summary> /// </summary>
public int Channel { get; } public Int32 Channel {
get;
}
/// <summary> /// <summary>
/// Gets the frequency. /// Gets the frequency.
/// </summary> /// </summary>
public int Frequency { get; } public Int32 Frequency {
get;
}
/// <summary> /// <summary>
/// Sends data and simultaneously receives the data in the return buffer /// Sends data and simultaneously receives the data in the return buffer
/// </summary> /// </summary>
/// <param name="buffer">The buffer.</param> /// <param name="buffer">The buffer.</param>
/// <returns>The read bytes from the ring-style bus</returns> /// <returns>The read bytes from the ring-style bus</returns>
public byte[] SendReceive(byte[] buffer) public Byte[] SendReceive(Byte[] buffer) {
{ if(buffer == null || buffer.Length == 0) {
if (buffer == null || buffer.Length == 0)
return null; return null;
}
lock (_syncLock) lock(this._syncLock) {
{ Byte[] spiBuffer = new Byte[buffer.Length];
var spiBuffer = new byte[buffer.Length];
Array.Copy(buffer, spiBuffer, buffer.Length); Array.Copy(buffer, spiBuffer, buffer.Length);
var result = WiringPi.WiringPiSPIDataRW(Channel, spiBuffer, spiBuffer.Length); Int32 result = WiringPi.WiringPiSPIDataRW(this.Channel, spiBuffer, spiBuffer.Length);
if (result < 0) HardwareException.Throw(nameof(SpiChannel), nameof(SendReceive)); if(result < 0) {
HardwareException.Throw(nameof(SpiChannel), nameof(SendReceive));
}
return spiBuffer; return spiBuffer;
} }
@ -101,7 +103,7 @@
/// <returns> /// <returns>
/// The read bytes from the ring-style bus /// The read bytes from the ring-style bus
/// </returns> /// </returns>
public Task<byte[]> SendReceiveAsync(byte[] buffer) => Task.Run(() => SendReceive(buffer)); public Task<Byte[]> SendReceiveAsync(Byte[] buffer) => Task.Run(() => this.SendReceive(buffer));
/// <summary> /// <summary>
/// Writes the specified buffer the the underlying FileDescriptor. /// Writes the specified buffer the the underlying FileDescriptor.
@ -110,16 +112,15 @@
/// like sending data over to those long RGB LED strips /// like sending data over to those long RGB LED strips
/// </summary> /// </summary>
/// <param name="buffer">The buffer.</param> /// <param name="buffer">The buffer.</param>
public void Write(byte[] buffer) public void Write(Byte[] buffer) {
{ lock(this._syncLock) {
lock (_syncLock) Int32 result = Standard.Write(this.FileDescriptor, buffer, buffer.Length);
{
var result = Standard.Write(FileDescriptor, buffer, buffer.Length);
if (result < 0) if(result < 0) {
HardwareException.Throw(nameof(SpiChannel), nameof(Write)); HardwareException.Throw(nameof(SpiChannel), nameof(Write));
} }
} }
}
/// <summary> /// <summary>
/// Writes the specified buffer the the underlying FileDescriptor. /// Writes the specified buffer the the underlying FileDescriptor.
@ -129,7 +130,7 @@
/// </summary> /// </summary>
/// <param name="buffer">The buffer.</param> /// <param name="buffer">The buffer.</param>
/// <returns>The awaitable task</returns> /// <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> /// <summary>
/// Retrieves the spi bus. If the bus channel is not registered it sets it up automatically. /// 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="channel">The channel.</param>
/// <param name="frequency">The frequency.</param> /// <param name="frequency">The frequency.</param>
/// <returns>The usable SPI channel</returns> /// <returns>The usable SPI channel</returns>
internal static SpiChannel Retrieve(SpiChannelNumber channel, int frequency) internal static SpiChannel Retrieve(SpiChannelNumber channel, Int32 frequency) {
{ lock(SyncRoot) {
lock (SyncRoot) if(Buses.ContainsKey(channel)) {
{
if (Buses.ContainsKey(channel))
return Buses[channel]; return Buses[channel];
}
var newBus = new SpiChannel(channel, frequency); SpiChannel newBus = new SpiChannel(channel, frequency);
Buses[channel] = newBus; Buses[channel] = newBus;
return newBus; return newBus;
} }

View File

@ -1,5 +1,4 @@
namespace Unosquare.RaspberryIO.Native namespace Unosquare.RaspberryIO.Native {
{
/// <summary> /// <summary>
/// A delegate defining a callback for an Interrupt Service Routine /// A delegate defining a callback for an Interrupt Service Routine
/// </summary> /// </summary>

View File

@ -1,38 +1,32 @@
namespace Unosquare.RaspberryIO.Native using Unosquare.Swan;
{
using Swan;
using System; using System;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
namespace Unosquare.RaspberryIO.Native {
/// <summary> /// <summary>
/// Represents a low-level exception, typically thrown when return codes from a /// 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. /// low-level operation is non-zero or in some cases when it is less than zero.
/// </summary> /// </summary>
/// <seealso cref="Exception" /> /// <seealso cref="Exception" />
public class HardwareException : Exception public class HardwareException : Exception {
{
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="HardwareException" /> class. /// Initializes a new instance of the <see cref="HardwareException" /> class.
/// </summary> /// </summary>
/// <param name="errorCode">The error code.</param> /// <param name="errorCode">The error code.</param>
/// <param name="component">The component.</param> /// <param name="component">The component.</param>
public HardwareException(int errorCode, string component) public HardwareException(Int32 errorCode, String component)
: base($"A hardware exception occurred. Error Code: {errorCode}") : base($"A hardware exception occurred. Error Code: {errorCode}") {
{ this.ExtendedMessage = null;
ExtendedMessage = null;
try try {
{ this.ExtendedMessage = Standard.Strerror(errorCode);
ExtendedMessage = Standard.Strerror(errorCode); } catch {
}
catch
{
// TODO: strerror not working great... // TODO: strerror not working great...
$"Could not retrieve native error description using {nameof(Standard.Strerror)}".Error(Pi.LoggerSource); $"Could not retrieve native error description using {nameof(Standard.Strerror)}".Error(Pi.LoggerSource);
} }
ErrorCode = errorCode; this.ErrorCode = errorCode;
Component = component; this.Component = component;
} }
/// <summary> /// <summary>
@ -41,7 +35,9 @@
/// <value> /// <value>
/// The error code. /// The error code.
/// </value> /// </value>
public int ErrorCode { get; } public Int32 ErrorCode {
get;
}
/// <summary> /// <summary>
/// Gets the component. /// Gets the component.
@ -49,7 +45,9 @@
/// <value> /// <value>
/// The component. /// The component.
/// </value> /// </value>
public string Component { get; } public String Component {
get;
}
/// <summary> /// <summary>
/// Gets the extended message (could be null). /// Gets the extended message (could be null).
@ -57,7 +55,9 @@
/// <value> /// <value>
/// The extended message. /// The extended message.
/// </value> /// </value>
public string ExtendedMessage { get; } public String ExtendedMessage {
get;
}
/// <summary> /// <summary>
/// Throws a new instance of a hardware error by retrieving the last error number (errno). /// 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="className">Name of the class.</param>
/// <param name="methodName">Name of the method.</param> /// <param name="methodName">Name of the method.</param>
/// <exception cref="HardwareException">When an error thrown by an API call occurs</exception> /// <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 /> /// <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}";
} }
} }

View File

@ -1,32 +1,30 @@
namespace Unosquare.RaspberryIO.Native using System;
{
using System;
using System.Diagnostics; using System.Diagnostics;
namespace Unosquare.RaspberryIO.Native {
/// <summary> /// <summary>
/// Provides access to a high- esolution, time measuring device. /// Provides access to a high- esolution, time measuring device.
/// </summary> /// </summary>
/// <seealso cref="Stopwatch" /> /// <seealso cref="Stopwatch" />
public class HighResolutionTimer : Stopwatch public class HighResolutionTimer : Stopwatch {
{
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="HighResolutionTimer"/> class. /// Initializes a new instance of the <see cref="HighResolutionTimer"/> class.
/// </summary> /// </summary>
/// <exception cref="NotSupportedException">High-resolution timer not available</exception> /// <exception cref="NotSupportedException">High-resolution timer not available</exception>
public HighResolutionTimer() public HighResolutionTimer() {
{ if(!IsHighResolution) {
if (!IsHighResolution)
throw new NotSupportedException("High-resolution timer not available"); throw new NotSupportedException("High-resolution timer not available");
} }
}
/// <summary> /// <summary>
/// Gets the numer of microseconds per timer tick. /// Gets the numer of microseconds per timer tick.
/// </summary> /// </summary>
public static double MicrosecondsPerTick { get; } = 1000000d / Frequency; public static Double MicrosecondsPerTick { get; } = 1000000d / Frequency;
/// <summary> /// <summary>
/// Gets the elapsed microseconds. /// Gets the elapsed microseconds.
/// </summary> /// </summary>
public long ElapsedMicroseconds => (long)(ElapsedTicks * MicrosecondsPerTick); public Int64 ElapsedMicroseconds => (Int64)(this.ElapsedTicks * MicrosecondsPerTick);
} }
} }

View File

@ -1,16 +1,14 @@
namespace Unosquare.RaspberryIO.Native using Unosquare.Swan;
{
using Swan;
using System; using System;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text; using System.Text;
namespace Unosquare.RaspberryIO.Native {
/// <summary> /// <summary>
/// Provides standard libc calls using platform-invoke /// Provides standard libc calls using platform-invoke
/// </summary> /// </summary>
internal static class Standard internal static class Standard {
{ internal const String LibCLibrary = "libc";
internal const string LibCLibrary = "libc";
#region LibC Calls #region LibC Calls
@ -19,18 +17,16 @@
/// </summary> /// </summary>
/// <param name="error">The error.</param> /// <param name="error">The error.</param>
/// <returns></returns> /// <returns></returns>
public static string Strerror(int error) public static String Strerror(Int32 error) {
{ if(!Runtime.IsUsingMonoRuntime) {
if (!Runtime.IsUsingMonoRuntime) return StrError(error); return StrError(error);
try
{
var buffer = new StringBuilder(256);
var result = Strerror(error, buffer, (ulong)buffer.Capacity);
return (result != -1) ? buffer.ToString() : null;
} }
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; return null;
} }
} }
@ -42,7 +38,7 @@
/// <param name="mode">The mode.</param> /// <param name="mode">The mode.</param>
/// <returns>The result</returns> /// <returns>The result</returns>
[DllImport(LibCLibrary, EntryPoint = "chmod", SetLastError = true)] [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> /// <summary>
/// Converts a string to a 32 bit integer. Use endpointer as IntPtr.Zero /// Converts a string to a 32 bit integer. Use endpointer as IntPtr.Zero
@ -52,7 +48,7 @@
/// <param name="numberBase">The number base.</param> /// <param name="numberBase">The number base.</param>
/// <returns>The result</returns> /// <returns>The result</returns>
[DllImport(LibCLibrary, EntryPoint = "strtol", SetLastError = true)] [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> /// <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. /// 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> /// <param name="count">The count.</param>
/// <returns>The result</returns> /// <returns>The result</returns>
[DllImport(LibCLibrary, EntryPoint = "write", SetLastError = true)] [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> /// <summary>
/// Fills in the structure with information about the system. /// Fills in the structure with information about the system.
@ -71,13 +67,13 @@
/// <param name="name">The name.</param> /// <param name="name">The name.</param>
/// <returns>The result</returns> /// <returns>The result</returns>
[DllImport(LibCLibrary, EntryPoint = "uname", SetLastError = true)] [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)] [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)] [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 #endregion
} }

View File

@ -1,47 +1,46 @@
namespace Unosquare.RaspberryIO.Native using System;
{
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
namespace Unosquare.RaspberryIO.Native {
/// <summary> /// <summary>
/// OS uname structure /// OS uname structure
/// </summary> /// </summary>
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
internal struct SystemName internal struct SystemName {
{
/// <summary> /// <summary>
/// System name /// System name
/// </summary> /// </summary>
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 65)] [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 65)]
public string SysName; public String SysName;
/// <summary> /// <summary>
/// Node name /// Node name
/// </summary> /// </summary>
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 65)] [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 65)]
public string NodeName; public String NodeName;
/// <summary> /// <summary>
/// Release level /// Release level
/// </summary> /// </summary>
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 65)] [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 65)]
public string Release; public String Release;
/// <summary> /// <summary>
/// Version level /// Version level
/// </summary> /// </summary>
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 65)] [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 65)]
public string Version; public String Version;
/// <summary> /// <summary>
/// Hardware level /// Hardware level
/// </summary> /// </summary>
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 65)] [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 65)]
public string Machine; public String Machine;
/// <summary> /// <summary>
/// Domain name /// Domain name
/// </summary> /// </summary>
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 65)] [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 65)]
public string DomainName; public String DomainName;
} }
} }

View File

@ -1,10 +1,8 @@
namespace Unosquare.RaspberryIO.Native namespace Unosquare.RaspberryIO.Native {
{
/// <summary> /// <summary>
/// Defines the different threading locking keys /// Defines the different threading locking keys
/// </summary> /// </summary>
public enum ThreadLockKey public enum ThreadLockKey {
{
/// <summary> /// <summary>
/// The lock 0 /// The lock 0
/// </summary> /// </summary>

View File

@ -1,20 +1,17 @@
namespace Unosquare.RaspberryIO.Native using Unosquare.Swan;
{ using Unosquare.Swan.Abstractions;
using Swan;
using Swan.Abstractions;
using System; using System;
namespace Unosquare.RaspberryIO.Native {
/// <summary> /// <summary>
/// Provides access to timing and threading properties and methods /// Provides access to timing and threading properties and methods
/// </summary> /// </summary>
public class Timing : SingletonBase<Timing> public class Timing : SingletonBase<Timing> {
{
/// <summary> /// <summary>
/// Prevents a default instance of the <see cref="Timing"/> class from being created. /// Prevents a default instance of the <see cref="Timing"/> class from being created.
/// </summary> /// </summary>
/// <exception cref="NotSupportedException">Could not initialize the GPIO controller</exception> /// <exception cref="NotSupportedException">Could not initialize the GPIO controller</exception>
private Timing() private Timing() {
{
// placeholder // placeholder
} }
@ -26,7 +23,7 @@
/// <value> /// <value>
/// The milliseconds since setup. /// The milliseconds since setup.
/// </value> /// </value>
public uint MillisecondsSinceSetup => WiringPi.Millis(); public UInt32 MillisecondsSinceSetup => WiringPi.Millis();
/// <summary> /// <summary>
/// This returns a number representing the number of microseconds since your /// This returns a number representing the number of microseconds since your
@ -36,7 +33,7 @@
/// <value> /// <value>
/// The microseconds since setup. /// The microseconds since setup.
/// </value> /// </value>
public uint MicrosecondsSinceSetup => WiringPi.Micros(); public UInt32 MicrosecondsSinceSetup => WiringPi.Micros();
/// <summary> /// <summary>
/// This causes program execution to pause for at least howLong milliseconds. /// 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. /// Note that the maximum delay is an unsigned 32-bit integer or approximately 49 days.
/// </summary> /// </summary>
/// <param name="value">The value.</param> /// <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> /// <summary>
/// This causes program execution to pause for at least howLong microseconds. /// This causes program execution to pause for at least howLong microseconds.
@ -56,7 +53,7 @@
/// especially if using threads. /// especially if using threads.
/// </summary> /// </summary>
/// <param name="value">The value.</param> /// <param name="value">The value.</param>
public void SleepMicroseconds(uint value) => WiringPi.DelayMicroseconds(value); public void SleepMicroseconds(UInt32 value) => WiringPi.DelayMicroseconds(value);
/// <summary> /// <summary>
/// This attempts to shift your program (or thread in a multi-threaded program) to a higher priority and /// 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) /// (as long as no other programs are running with elevated priorities)
/// </summary> /// </summary>
/// <param name="priority">The priority.</param> /// <param name="priority">The priority.</param>
public void SetThreadPriority(int priority) public void SetThreadPriority(Int32 priority) {
{
priority = priority.Clamp(0, 99); priority = priority.Clamp(0, 99);
var result = WiringPi.PiHiPri(priority); Int32 result = WiringPi.PiHiPri(priority);
if (result < 0) HardwareException.Throw(nameof(Timing), nameof(SetThreadPriority)); if(result < 0) {
HardwareException.Throw(nameof(Timing), nameof(SetThreadPriority));
}
} }
/// <summary> /// <summary>
@ -80,13 +78,15 @@
/// </summary> /// </summary>
/// <param name="worker">The worker.</param> /// <param name="worker">The worker.</param>
/// <exception cref="ArgumentNullException">worker</exception> /// <exception cref="ArgumentNullException">worker</exception>
public void CreateThread(ThreadWorker worker) public void CreateThread(ThreadWorker worker) {
{ if(worker == null) {
if (worker == null)
throw new ArgumentNullException(nameof(worker)); throw new ArgumentNullException(nameof(worker));
}
var result = WiringPi.PiThreadCreate(worker); Int32 result = WiringPi.PiThreadCreate(worker);
if (result != 0) HardwareException.Throw(nameof(Timing), nameof(CreateThread)); if(result != 0) {
HardwareException.Throw(nameof(Timing), nameof(CreateThread));
}
} }
/// <summary> /// <summary>
@ -95,7 +95,7 @@
/// it will be stalled until the first process has unlocked the same key. /// it will be stalled until the first process has unlocked the same key.
/// </summary> /// </summary>
/// <param name="key">The key.</param> /// <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> /// <summary>
/// These allow you to synchronize variable updates from your main program to any threads running in your program. /// 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. /// it will be stalled until the first process has unlocked the same key.
/// </summary> /// </summary>
/// <param name="key">The key.</param> /// <param name="key">The key.</param>
public void Unlock(ThreadLockKey key) => WiringPi.PiUnlock((int)key); public void Unlock(ThreadLockKey key) => WiringPi.PiUnlock((Int32)key);
} }
} }

View File

@ -1,9 +1,8 @@
namespace Unosquare.RaspberryIO.Native using System;
{
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
public partial class WiringPi namespace Unosquare.RaspberryIO.Native {
{ public partial class WiringPi {
#region WiringPi - I2C Library Calls #region WiringPi - I2C Library Calls
/// <summary> /// <summary>
@ -12,7 +11,7 @@
/// <param name="fd">The fd.</param> /// <param name="fd">The fd.</param>
/// <returns>The result</returns> /// <returns>The result</returns>
[DllImport(WiringPiLibrary, EntryPoint = "wiringPiI2CRead", SetLastError = true)] [DllImport(WiringPiLibrary, EntryPoint = "wiringPiI2CRead", SetLastError = true)]
public static extern int WiringPiI2CRead(int fd); public static extern Int32 WiringPiI2CRead(Int32 fd);
/// <summary> /// <summary>
/// These read an 8-bit value from the device register indicated. /// These read an 8-bit value from the device register indicated.
@ -21,7 +20,7 @@
/// <param name="reg">The reg.</param> /// <param name="reg">The reg.</param>
/// <returns>The result</returns> /// <returns>The result</returns>
[DllImport(WiringPiLibrary, EntryPoint = "wiringPiI2CReadReg8", SetLastError = true)] [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> /// <summary>
/// These read a 16-bit value from the device register indicated. /// These read a 16-bit value from the device register indicated.
@ -30,7 +29,7 @@
/// <param name="reg">The reg.</param> /// <param name="reg">The reg.</param>
/// <returns>The result</returns> /// <returns>The result</returns>
[DllImport(WiringPiLibrary, EntryPoint = "wiringPiI2CReadReg16", SetLastError = true)] [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> /// <summary>
/// Simple device write. Some devices accept data this way without needing to access any internal registers. /// 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> /// <param name="data">The data.</param>
/// <returns>The result</returns> /// <returns>The result</returns>
[DllImport(WiringPiLibrary, EntryPoint = "wiringPiI2CWrite", SetLastError = true)] [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> /// <summary>
/// These write an 8-bit data value into the device register indicated. /// These write an 8-bit data value into the device register indicated.
@ -49,7 +48,7 @@
/// <param name="data">The data.</param> /// <param name="data">The data.</param>
/// <returns>The result</returns> /// <returns>The result</returns>
[DllImport(WiringPiLibrary, EntryPoint = "wiringPiI2CWriteReg8", SetLastError = true)] [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> /// <summary>
/// These write a 16-bit data value into the device register indicated. /// These write a 16-bit data value into the device register indicated.
@ -59,7 +58,7 @@
/// <param name="data">The data.</param> /// <param name="data">The data.</param>
/// <returns>The result</returns> /// <returns>The result</returns>
[DllImport(WiringPiLibrary, EntryPoint = "wiringPiI2CWriteReg16", SetLastError = true)] [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> /// <summary>
/// This initialises the I2C system with your given device identifier. /// This initialises the I2C system with your given device identifier.
@ -71,7 +70,7 @@
/// <param name="devId">The dev identifier.</param> /// <param name="devId">The dev identifier.</param>
/// <returns>The result</returns> /// <returns>The result</returns>
[DllImport(WiringPiLibrary, EntryPoint = "wiringPiI2CSetup", SetLastError = true)] [DllImport(WiringPiLibrary, EntryPoint = "wiringPiI2CSetup", SetLastError = true)]
public static extern int WiringPiI2CSetup(int devId); public static extern Int32 WiringPiI2CSetup(Int32 devId);
#endregion #endregion

View File

@ -1,9 +1,8 @@
namespace Unosquare.RaspberryIO.Native using System;
{
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
public partial class WiringPi namespace Unosquare.RaspberryIO.Native {
{ public partial class WiringPi {
#region WiringPi - Serial Port #region WiringPi - Serial Port
/// <summary> /// <summary>
@ -17,7 +16,7 @@
/// <param name="baud">The baud.</param> /// <param name="baud">The baud.</param>
/// <returns>The result</returns> /// <returns>The result</returns>
[DllImport(WiringPiLibrary, EntryPoint = "serialOpen", SetLastError = true)] [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> /// <summary>
/// Closes the device identified by the file descriptor given. /// Closes the device identified by the file descriptor given.
@ -25,7 +24,7 @@
/// <param name="fd">The fd.</param> /// <param name="fd">The fd.</param>
/// <returns>The result</returns> /// <returns>The result</returns>
[DllImport(WiringPiLibrary, EntryPoint = "serialClose", SetLastError = true)] [DllImport(WiringPiLibrary, EntryPoint = "serialClose", SetLastError = true)]
public static extern int SerialClose(int fd); public static extern Int32 SerialClose(Int32 fd);
/// <summary> /// <summary>
/// Sends the single byte to the serial device identified by the given file descriptor. /// 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="fd">The fd.</param>
/// <param name="c">The c.</param> /// <param name="c">The c.</param>
[DllImport(WiringPiLibrary, EntryPoint = "serialPutchar", SetLastError = true)] [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> /// <summary>
/// Sends the nul-terminated string to the serial device identified by the given file descriptor. /// 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="fd">The fd.</param>
/// <param name="s">The s.</param> /// <param name="s">The s.</param>
[DllImport(WiringPiLibrary, EntryPoint = "serialPuts", SetLastError = true)] [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> /// <summary>
/// Returns the number of characters available for reading, or -1 for any error condition, /// Returns the number of characters available for reading, or -1 for any error condition,
@ -50,7 +49,7 @@
/// <param name="fd">The fd.</param> /// <param name="fd">The fd.</param>
/// <returns>The result</returns> /// <returns>The result</returns>
[DllImport(WiringPiLibrary, EntryPoint = "serialDataAvail", SetLastError = true)] [DllImport(WiringPiLibrary, EntryPoint = "serialDataAvail", SetLastError = true)]
public static extern int SerialDataAvail(int fd); public static extern Int32 SerialDataAvail(Int32 fd);
/// <summary> /// <summary>
/// Returns the next character available on the serial device. /// Returns the next character available on the serial device.
@ -59,14 +58,14 @@
/// <param name="fd">The fd.</param> /// <param name="fd">The fd.</param>
/// <returns>The result</returns> /// <returns>The result</returns>
[DllImport(WiringPiLibrary, EntryPoint = "serialGetchar", SetLastError = true)] [DllImport(WiringPiLibrary, EntryPoint = "serialGetchar", SetLastError = true)]
public static extern int SerialGetchar(int fd); public static extern Int32 SerialGetchar(Int32 fd);
/// <summary> /// <summary>
/// This discards all data received, or waiting to be send down the given device. /// This discards all data received, or waiting to be send down the given device.
/// </summary> /// </summary>
/// <param name="fd">The fd.</param> /// <param name="fd">The fd.</param>
[DllImport(WiringPiLibrary, EntryPoint = "serialFlush", SetLastError = true)] [DllImport(WiringPiLibrary, EntryPoint = "serialFlush", SetLastError = true)]
public static extern void SerialFlush(int fd); public static extern void SerialFlush(Int32 fd);
#endregion #endregion
} }

View File

@ -1,9 +1,8 @@
namespace Unosquare.RaspberryIO.Native using System;
{
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
public partial class WiringPi namespace Unosquare.RaspberryIO.Native {
{ public partial class WiringPi {
#region WiringPi - Shift Library #region WiringPi - Shift Library
/// <summary> /// <summary>
@ -16,7 +15,7 @@
/// <param name="order">The order.</param> /// <param name="order">The order.</param>
/// <returns>The result</returns> /// <returns>The result</returns>
[DllImport(WiringPiLibrary, EntryPoint = "shiftIn", SetLastError = true)] [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> /// <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. /// 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="order">The order.</param>
/// <param name="val">The value.</param> /// <param name="val">The value.</param>
[DllImport(WiringPiLibrary, EntryPoint = "shiftOut", SetLastError = true)] [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 #endregion

View File

@ -1,9 +1,8 @@
namespace Unosquare.RaspberryIO.Native using System;
{
using System.Runtime.InteropServices; 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) #region WiringPi - Soft PWM (https://github.com/WiringPi/WiringPi/blob/master/wiringPi/softPwm.h)
/// <summary> /// <summary>
@ -16,7 +15,7 @@
/// <param name="pwmRange">The PWM range.</param> /// <param name="pwmRange">The PWM range.</param>
/// <returns>The result</returns> /// <returns>The result</returns>
[DllImport(WiringPiLibrary, EntryPoint = "softPwmCreate", SetLastError = true)] [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> /// <summary>
/// This updates the PWM value on the given pin. The value is checked to be in-range and pins that havent previously /// This updates the PWM value on the given pin. The value is checked to be in-range and pins that havent previously
@ -25,14 +24,14 @@
/// <param name="pin">The pin.</param> /// <param name="pin">The pin.</param>
/// <param name="value">The value.</param> /// <param name="value">The value.</param>
[DllImport(WiringPiLibrary, EntryPoint = "softPwmWrite", SetLastError = true)] [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> /// <summary>
/// This function is undocumented /// This function is undocumented
/// </summary> /// </summary>
/// <param name="pin">The pin.</param> /// <param name="pin">The pin.</param>
[DllImport(WiringPiLibrary, EntryPoint = "softPwmStop", SetLastError = true)] [DllImport(WiringPiLibrary, EntryPoint = "softPwmStop", SetLastError = true)]
public static extern void SoftPwmStop(int pin); public static extern void SoftPwmStop(Int32 pin);
/// <summary> /// <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. /// 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> /// <param name="pin">The pin.</param>
/// <returns>The result</returns> /// <returns>The result</returns>
[DllImport(WiringPiLibrary, EntryPoint = "softToneCreate", SetLastError = true)] [DllImport(WiringPiLibrary, EntryPoint = "softToneCreate", SetLastError = true)]
public static extern int SoftToneCreate(int pin); public static extern Int32 SoftToneCreate(Int32 pin);
/// <summary> /// <summary>
/// This function is undocumented /// This function is undocumented
/// </summary> /// </summary>
/// <param name="pin">The pin.</param> /// <param name="pin">The pin.</param>
[DllImport(WiringPiLibrary, EntryPoint = "softToneStop", SetLastError = true)] [DllImport(WiringPiLibrary, EntryPoint = "softToneStop", SetLastError = true)]
public static extern void SoftToneStop(int pin); public static extern void SoftToneStop(Int32 pin);
/// <summary> /// <summary>
/// This updates the tone frequency value on the given pin. The tone will be played until you set the frequency to 0. /// 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="pin">The pin.</param>
/// <param name="freq">The freq.</param> /// <param name="freq">The freq.</param>
[DllImport(WiringPiLibrary, EntryPoint = "softToneWrite", SetLastError = true)] [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 #endregion

View File

@ -1,9 +1,8 @@
namespace Unosquare.RaspberryIO.Native using System;
{
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
public partial class WiringPi namespace Unosquare.RaspberryIO.Native {
{ public partial class WiringPi {
#region WiringPi - SPI Library Calls #region WiringPi - SPI Library Calls
/// <summary> /// <summary>
@ -12,7 +11,7 @@
/// <param name="channel">The channel.</param> /// <param name="channel">The channel.</param>
/// <returns>Unknown</returns> /// <returns>Unknown</returns>
[DllImport(WiringPiLibrary, EntryPoint = "wiringPiSPIGetFd", SetLastError = true)] [DllImport(WiringPiLibrary, EntryPoint = "wiringPiSPIGetFd", SetLastError = true)]
public static extern int WiringPiSPIGetFd(int channel); public static extern Int32 WiringPiSPIGetFd(Int32 channel);
/// <summary> /// <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. /// 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> /// <param name="len">The length.</param>
/// <returns>The result</returns> /// <returns>The result</returns>
[DllImport(WiringPiLibrary, EntryPoint = "wiringPiSPIDataRW", SetLastError = true)] [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> /// <summary>
/// This function is undocumented /// This function is undocumented
@ -35,7 +34,7 @@
/// <param name="mode">The mode.</param> /// <param name="mode">The mode.</param>
/// <returns>Unkown</returns> /// <returns>Unkown</returns>
[DllImport(WiringPiLibrary, EntryPoint = "wiringPiSPISetupMode", SetLastError = true)] [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> /// <summary>
/// This is the way to initialize a channel (The Pi has 2 channels; 0 and 1). The speed parameter is an integer /// 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> /// <param name="speed">The speed.</param>
/// <returns>The Linux file descriptor for the device or -1 for error</returns> /// <returns>The Linux file descriptor for the device or -1 for error</returns>
[DllImport(WiringPiLibrary, EntryPoint = "wiringPiSPISetup", SetLastError = true)] [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 #endregion
} }

View File

@ -1,16 +1,14 @@
namespace Unosquare.RaspberryIO.Native using System;
{
using System;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
namespace Unosquare.RaspberryIO.Native {
/// <summary> /// <summary>
/// Provides native C WiringPi Library function call wrappers /// Provides native C WiringPi Library function call wrappers
/// All credit for the native library goes to the author of http://wiringpi.com/ /// 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 /// The wrappers were written based on https://github.com/WiringPi/WiringPi/blob/master/wiringPi/wiringPi.h
/// </summary> /// </summary>
public partial class WiringPi public partial class WiringPi {
{ internal const String WiringPiLibrary = "libwiringPi.so.2.46";
internal const string WiringPiLibrary = "libwiringPi.so.2.46";
#region WiringPi - Core Functions (https://github.com/WiringPi/WiringPi/blob/master/wiringPi/wiringPi.h) #region WiringPi - Core Functions (https://github.com/WiringPi/WiringPi/blob/master/wiringPi/wiringPi.h)
@ -22,7 +20,7 @@
/// </summary> /// </summary>
/// <returns>The result code</returns> /// <returns>The result code</returns>
[DllImport(WiringPiLibrary, EntryPoint = "wiringPiSetup", SetLastError = true)] [DllImport(WiringPiLibrary, EntryPoint = "wiringPiSetup", SetLastError = true)]
public static extern int WiringPiSetup(); public static extern Int32 WiringPiSetup();
/// <summary> /// <summary>
/// This initialises wiringPi but uses the /sys/class/gpio interface rather than accessing the hardware directly. /// This initialises wiringPi but uses the /sys/class/gpio interface rather than accessing the hardware directly.
@ -37,7 +35,7 @@
/// </summary> /// </summary>
/// <returns>The result code</returns> /// <returns>The result code</returns>
[DllImport(WiringPiLibrary, EntryPoint = "wiringPiSetupSys", SetLastError = true)] [DllImport(WiringPiLibrary, EntryPoint = "wiringPiSetupSys", SetLastError = true)]
public static extern int WiringPiSetupSys(); public static extern Int32 WiringPiSetupSys();
/// <summary> /// <summary>
/// This is identical to wiringPiSetup, however it allows the calling programs to use the Broadcom GPIO /// This is identical to wiringPiSetup, however it allows the calling programs to use the Broadcom GPIO
@ -47,7 +45,7 @@
/// </summary> /// </summary>
/// <returns>The result code</returns> /// <returns>The result code</returns>
[DllImport(WiringPiLibrary, EntryPoint = "wiringPiSetupGpio", SetLastError = true)] [DllImport(WiringPiLibrary, EntryPoint = "wiringPiSetupGpio", SetLastError = true)]
public static extern int WiringPiSetupGpio(); public static extern Int32 WiringPiSetupGpio();
/// <summary> /// <summary>
/// Identical to wiringPiSetup, however it allows the calling programs to use the physical pin numbers on the P1 connector only. /// 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> /// </summary>
/// <returns>The result code</returns> /// <returns>The result code</returns>
[DllImport(WiringPiLibrary, EntryPoint = "wiringPiSetupPhys", SetLastError = true)] [DllImport(WiringPiLibrary, EntryPoint = "wiringPiSetupPhys", SetLastError = true)]
public static extern int WiringPiSetupPhys(); public static extern Int32 WiringPiSetupPhys();
/// <summary> /// <summary>
/// This function is undocumented /// This function is undocumented
@ -63,7 +61,7 @@
/// <param name="pin">The pin.</param> /// <param name="pin">The pin.</param>
/// <param name="mode">The mode.</param> /// <param name="mode">The mode.</param>
[DllImport(WiringPiLibrary, EntryPoint = "pinModeAlt", SetLastError = true)] [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> /// <summary>
/// This sets the mode of a pin to either INPUT, OUTPUT, PWM_OUTPUT or GPIO_CLOCK. /// 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="pin">The pin.</param>
/// <param name="mode">The mode.</param> /// <param name="mode">The mode.</param>
[DllImport(WiringPiLibrary, EntryPoint = "pinMode", SetLastError = true)] [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> /// <summary>
/// This sets the pull-up or pull-down resistor mode on the given pin, which should be set as an input. /// 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="pin">The pin.</param>
/// <param name="pud">The pud.</param> /// <param name="pud">The pud.</param>
[DllImport(WiringPiLibrary, EntryPoint = "pullUpDnControl", SetLastError = true)] [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> /// <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. /// 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> /// <param name="pin">The pin.</param>
/// <returns>The result code</returns> /// <returns>The result code</returns>
[DllImport(WiringPiLibrary, EntryPoint = "digitalRead", SetLastError = true)] [DllImport(WiringPiLibrary, EntryPoint = "digitalRead", SetLastError = true)]
public static extern int DigitalRead(int pin); public static extern Int32 DigitalRead(Int32 pin);
/// <summary> /// <summary>
/// Writes the value HIGH or LOW (1 or 0) to the given pin which must have been previously set as an output. /// 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="pin">The pin.</param>
/// <param name="value">The value.</param> /// <param name="value">The value.</param>
[DllImport(WiringPiLibrary, EntryPoint = "digitalWrite", SetLastError = true)] [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> /// <summary>
/// Writes the value to the PWM register for the given pin. The Raspberry Pi has one /// 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="pin">The pin.</param>
/// <param name="value">The value.</param> /// <param name="value">The value.</param>
[DllImport(WiringPiLibrary, EntryPoint = "pwmWrite", SetLastError = true)] [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> /// <summary>
/// This returns the value read on the supplied analog input pin. You will need to /// 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> /// <param name="pin">The pin.</param>
/// <returns>The result code</returns> /// <returns>The result code</returns>
[DllImport(WiringPiLibrary, EntryPoint = "analogRead", SetLastError = true)] [DllImport(WiringPiLibrary, EntryPoint = "analogRead", SetLastError = true)]
public static extern int AnalogRead(int pin); public static extern Int32 AnalogRead(Int32 pin);
/// <summary> /// <summary>
/// This writes the given value to the supplied analog pin. You will need to register additional /// 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="pin">The pin.</param>
/// <param name="value">The value.</param> /// <param name="value">The value.</param>
[DllImport(WiringPiLibrary, EntryPoint = "analogWrite", SetLastError = true)] [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> /// <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 /// 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> /// </summary>
/// <returns>The result code</returns> /// <returns>The result code</returns>
[DllImport(WiringPiLibrary, EntryPoint = "piBoardRev", SetLastError = true)] [DllImport(WiringPiLibrary, EntryPoint = "piBoardRev", SetLastError = true)]
public static extern int PiBoardRev(); public static extern Int32 PiBoardRev();
/// <summary> /// <summary>
/// This function is undocumented /// This function is undocumented
@ -155,7 +153,7 @@
/// <param name="overVolted">The over volted.</param> /// <param name="overVolted">The over volted.</param>
/// <returns>The result code</returns> /// <returns>The result code</returns>
[DllImport(WiringPiLibrary, EntryPoint = "piBoardId", SetLastError = true)] [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> /// <summary>
/// This returns the BCM_GPIO pin number of the supplied wiringPi pin. It takes the board revision into account. /// 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> /// <param name="wPiPin">The w pi pin.</param>
/// <returns>The result code</returns> /// <returns>The result code</returns>
[DllImport(WiringPiLibrary, EntryPoint = "wpiPinToGpio", SetLastError = true)] [DllImport(WiringPiLibrary, EntryPoint = "wpiPinToGpio", SetLastError = true)]
public static extern int WpiPinToGpio(int wPiPin); public static extern Int32 WpiPinToGpio(Int32 wPiPin);
/// <summary> /// <summary>
/// This returns the BCM_GPIO pin number of the supplied physical pin on the P1 connector. /// 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> /// <param name="physPin">The physical pin.</param>
/// <returns>The result code</returns> /// <returns>The result code</returns>
[DllImport(WiringPiLibrary, EntryPoint = "physPinToGpio", SetLastError = true)] [DllImport(WiringPiLibrary, EntryPoint = "physPinToGpio", SetLastError = true)]
public static extern int PhysPinToGpio(int physPin); public static extern Int32 PhysPinToGpio(Int32 physPin);
/// <summary> /// <summary>
/// This sets the “strength” of the pad drivers for a particular group of pins. /// This sets the “strength” of the pad drivers for a particular group of pins.
@ -181,7 +179,7 @@
/// <param name="value">The value.</param> /// <param name="value">The value.</param>
/// <returns>The result code</returns> /// <returns>The result code</returns>
[DllImport(WiringPiLibrary, EntryPoint = "setPadDrive", SetLastError = true)] [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> /// <summary>
/// Undocumented function /// Undocumented function
@ -189,7 +187,7 @@
/// <param name="pin">The pin.</param> /// <param name="pin">The pin.</param>
/// <returns>The result code</returns> /// <returns>The result code</returns>
[DllImport(WiringPiLibrary, EntryPoint = "getAlt", SetLastError = true)] [DllImport(WiringPiLibrary, EntryPoint = "getAlt", SetLastError = true)]
public static extern int GetAlt(int pin); public static extern Int32 GetAlt(Int32 pin);
/// <summary> /// <summary>
/// Undocumented function /// Undocumented function
@ -198,7 +196,7 @@
/// <param name="freq">The freq.</param> /// <param name="freq">The freq.</param>
/// <returns>The result code</returns> /// <returns>The result code</returns>
[DllImport(WiringPiLibrary, EntryPoint = "pwmToneWrite", SetLastError = true)] [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> /// <summary>
/// This writes the 8-bit byte supplied to the first 8 GPIO pins. /// This writes the 8-bit byte supplied to the first 8 GPIO pins.
@ -206,7 +204,7 @@
/// </summary> /// </summary>
/// <param name="value">The value.</param> /// <param name="value">The value.</param>
[DllImport(WiringPiLibrary, EntryPoint = "digitalWriteByte", SetLastError = true)] [DllImport(WiringPiLibrary, EntryPoint = "digitalWriteByte", SetLastError = true)]
public static extern void DigitalWriteByte(int value); public static extern void DigitalWriteByte(Int32 value);
/// <summary> /// <summary>
/// This writes the 8-bit byte supplied to the first 8 GPIO pins. /// This writes the 8-bit byte supplied to the first 8 GPIO pins.
@ -214,7 +212,7 @@
/// </summary> /// </summary>
/// <param name="value">The value.</param> /// <param name="value">The value.</param>
[DllImport(WiringPiLibrary, EntryPoint = "digitalWriteByte2", SetLastError = true)] [DllImport(WiringPiLibrary, EntryPoint = "digitalWriteByte2", SetLastError = true)]
public static extern void DigitalWriteByte2(int value); public static extern void DigitalWriteByte2(Int32 value);
/// <summary> /// <summary>
/// Undocumented function /// Undocumented function
@ -223,7 +221,7 @@
/// </summary> /// </summary>
/// <returns>The result code</returns> /// <returns>The result code</returns>
[DllImport(WiringPiLibrary, EntryPoint = "digitalReadByte", SetLastError = true)] [DllImport(WiringPiLibrary, EntryPoint = "digitalReadByte", SetLastError = true)]
public static extern uint DigitalReadByte(); public static extern UInt32 DigitalReadByte();
/// <summary> /// <summary>
/// Undocumented function /// Undocumented function
@ -232,7 +230,7 @@
/// </summary> /// </summary>
/// <returns>The result code</returns> /// <returns>The result code</returns>
[DllImport(WiringPiLibrary, EntryPoint = "digitalReadByte2", SetLastError = true)] [DllImport(WiringPiLibrary, EntryPoint = "digitalReadByte2", SetLastError = true)]
public static extern uint DigitalReadByte2(); public static extern UInt32 DigitalReadByte2();
/// <summary> /// <summary>
/// The PWM generator can run in 2 modes “balanced” and “mark:space”. The mark:space mode is traditional, /// The PWM generator can run in 2 modes “balanced” and “mark:space”. The mark:space mode is traditional,
@ -240,14 +238,14 @@
/// </summary> /// </summary>
/// <param name="mode">The mode.</param> /// <param name="mode">The mode.</param>
[DllImport(WiringPiLibrary, EntryPoint = "pwmSetMode", SetLastError = true)] [DllImport(WiringPiLibrary, EntryPoint = "pwmSetMode", SetLastError = true)]
public static extern void PwmSetMode(int mode); public static extern void PwmSetMode(Int32 mode);
/// <summary> /// <summary>
/// This sets the range register in the PWM generator. The default is 1024. /// This sets the range register in the PWM generator. The default is 1024.
/// </summary> /// </summary>
/// <param name="range">The range.</param> /// <param name="range">The range.</param>
[DllImport(WiringPiLibrary, EntryPoint = "pwmSetRange", SetLastError = true)] [DllImport(WiringPiLibrary, EntryPoint = "pwmSetRange", SetLastError = true)]
public static extern void PwmSetRange(uint range); public static extern void PwmSetRange(UInt32 range);
/// <summary> /// <summary>
/// This sets the divisor for the PWM clock. /// This sets the divisor for the PWM clock.
@ -256,7 +254,7 @@
/// </summary> /// </summary>
/// <param name="divisor">The divisor.</param> /// <param name="divisor">The divisor.</param>
[DllImport(WiringPiLibrary, EntryPoint = "pwmSetClock", SetLastError = true)] [DllImport(WiringPiLibrary, EntryPoint = "pwmSetClock", SetLastError = true)]
public static extern void PwmSetClock(int divisor); public static extern void PwmSetClock(Int32 divisor);
/// <summary> /// <summary>
/// Undocumented function /// Undocumented function
@ -264,7 +262,7 @@
/// <param name="pin">The pin.</param> /// <param name="pin">The pin.</param>
/// <param name="freq">The freq.</param> /// <param name="freq">The freq.</param>
[DllImport(WiringPiLibrary, EntryPoint = "gpioClockSet", SetLastError = true)] [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> /// <summary>
/// Note: Jan 2013: The waitForInterrupt() function is deprecated you should use the newer and easier to use wiringPiISR() function below. /// 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> /// <returns>The result code</returns>
[Obsolete] [Obsolete]
[DllImport(WiringPiLibrary, EntryPoint = "waitForInterrupt", SetLastError = true)] [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> /// <summary>
/// This function registers a function to received interrupts on the specified pin. /// This function registers a function to received interrupts on the specified pin.
@ -302,7 +300,7 @@
/// <param name="method">The method.</param> /// <param name="method">The method.</param>
/// <returns>The result code</returns> /// <returns>The result code</returns>
[DllImport(WiringPiLibrary, EntryPoint = "wiringPiISR", SetLastError = true)] [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> /// <summary>
/// This function creates a thread which is another function in your program previously declared using the PI_THREAD declaration. /// 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> /// <param name="method">The method.</param>
/// <returns>The result code</returns> /// <returns>The result code</returns>
[DllImport(WiringPiLibrary, EntryPoint = "piThreadCreate", SetLastError = true)] [DllImport(WiringPiLibrary, EntryPoint = "piThreadCreate", SetLastError = true)]
public static extern int PiThreadCreate(ThreadWorker method); public static extern Int32 PiThreadCreate(ThreadWorker method);
/// <summary> /// <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. /// 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> /// </summary>
/// <param name="key">The key.</param> /// <param name="key">The key.</param>
[DllImport(WiringPiLibrary, EntryPoint = "piLock", SetLastError = true)] [DllImport(WiringPiLibrary, EntryPoint = "piLock", SetLastError = true)]
public static extern void PiLock(int key); public static extern void PiLock(Int32 key);
/// <summary> /// <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. /// 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> /// </summary>
/// <param name="key">The key.</param> /// <param name="key">The key.</param>
[DllImport(WiringPiLibrary, EntryPoint = "piUnlock", SetLastError = true)] [DllImport(WiringPiLibrary, EntryPoint = "piUnlock", SetLastError = true)]
public static extern void PiUnlock(int key); public static extern void PiUnlock(Int32 key);
/// <summary> /// <summary>
/// This attempts to shift your program (or thread in a multi-threaded program) to a higher priority /// 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> /// <param name="priority">The priority.</param>
/// <returns>The result code</returns> /// <returns>The result code</returns>
[DllImport(WiringPiLibrary, EntryPoint = "piHiPri", SetLastError = true)] [DllImport(WiringPiLibrary, EntryPoint = "piHiPri", SetLastError = true)]
public static extern int PiHiPri(int priority); public static extern Int32 PiHiPri(Int32 priority);
/// <summary> /// <summary>
/// This causes program execution to pause for at least howLong milliseconds. /// This causes program execution to pause for at least howLong milliseconds.
@ -359,7 +357,7 @@
/// </summary> /// </summary>
/// <param name="howLong">The how long.</param> /// <param name="howLong">The how long.</param>
[DllImport(WiringPiLibrary, EntryPoint = "delay", SetLastError = true)] [DllImport(WiringPiLibrary, EntryPoint = "delay", SetLastError = true)]
public static extern void Delay(uint howLong); public static extern void Delay(UInt32 howLong);
/// <summary> /// <summary>
/// This causes program execution to pause for at least howLong microseconds. /// This causes program execution to pause for at least howLong microseconds.
@ -371,7 +369,7 @@
/// </summary> /// </summary>
/// <param name="howLong">The how long.</param> /// <param name="howLong">The how long.</param>
[DllImport(WiringPiLibrary, EntryPoint = "delayMicroseconds", SetLastError = true)] [DllImport(WiringPiLibrary, EntryPoint = "delayMicroseconds", SetLastError = true)]
public static extern void DelayMicroseconds(uint howLong); public static extern void DelayMicroseconds(UInt32 howLong);
/// <summary> /// <summary>
/// This returns a number representing the number of milliseconds since your program called one of the wiringPiSetup functions. /// This returns a number representing the number of milliseconds since your program called one of the wiringPiSetup functions.
@ -379,7 +377,7 @@
/// </summary> /// </summary>
/// <returns>The result code</returns> /// <returns>The result code</returns>
[DllImport(WiringPiLibrary, EntryPoint = "millis", SetLastError = true)] [DllImport(WiringPiLibrary, EntryPoint = "millis", SetLastError = true)]
public static extern uint Millis(); public static extern UInt32 Millis();
/// <summary> /// <summary>
/// This returns a number representing the number of microseconds since your program called one of /// This returns a number representing the number of microseconds since your program called one of
@ -387,7 +385,7 @@
/// </summary> /// </summary>
/// <returns>The result code</returns> /// <returns>The result code</returns>
[DllImport(WiringPiLibrary, EntryPoint = "micros", SetLastError = true)] [DllImport(WiringPiLibrary, EntryPoint = "micros", SetLastError = true)]
public static extern uint Micros(); public static extern UInt32 Micros();
#endregion #endregion
} }

View File

@ -1,26 +1,23 @@
namespace Unosquare.RaspberryIO using Unosquare.RaspberryIO.Camera;
{ using Unosquare.RaspberryIO.Computer;
using Camera; using Unosquare.RaspberryIO.Gpio;
using Computer; using Unosquare.RaspberryIO.Native;
using Gpio;
using Native;
using System.Threading.Tasks; using System.Threading.Tasks;
using Swan.Components; using Unosquare.Swan.Components;
using System;
namespace Unosquare.RaspberryIO {
/// <summary> /// <summary>
/// Our main character. Provides access to the Raspberry Pi's GPIO, system and board information and Camera /// Our main character. Provides access to the Raspberry Pi's GPIO, system and board information and Camera
/// </summary> /// </summary>
public static class Pi public static class Pi {
{ private static readonly Object SyncLock = new Object();
private static readonly object SyncLock = new object();
/// <summary> /// <summary>
/// Initializes static members of the <see cref="Pi" /> class. /// Initializes static members of the <see cref="Pi" /> class.
/// </summary> /// </summary>
static Pi() static Pi() {
{ lock(SyncLock) {
lock (SyncLock)
{
// Extraction of embedded resources // Extraction of embedded resources
Resources.EmbeddedResources.ExtractAll(); Resources.EmbeddedResources.ExtractAll();
@ -40,42 +37,56 @@
/// <summary> /// <summary>
/// Provides access to the Raspberry Pi's GPIO as a collection of GPIO Pins. /// Provides access to the Raspberry Pi's GPIO as a collection of GPIO Pins.
/// </summary> /// </summary>
public static GpioController Gpio { get; } public static GpioController Gpio {
get;
}
/// <summary> /// <summary>
/// Provides information on this Raspberry Pi's CPU and form factor. /// Provides information on this Raspberry Pi's CPU and form factor.
/// </summary> /// </summary>
public static SystemInfo Info { get; } public static SystemInfo Info {
get;
}
/// <summary> /// <summary>
/// Provides access to The PI's Timing and threading API /// Provides access to The PI's Timing and threading API
/// </summary> /// </summary>
public static Timing Timing { get; } public static Timing Timing {
get;
}
/// <summary> /// <summary>
/// Provides access to the 2-channel SPI bus /// Provides access to the 2-channel SPI bus
/// </summary> /// </summary>
public static SpiBus Spi { get; } public static SpiBus Spi {
get;
}
/// <summary> /// <summary>
/// Provides access to the functionality of the i2c bus. /// Provides access to the functionality of the i2c bus.
/// </summary> /// </summary>
public static I2CBus I2C { get; } public static I2CBus I2C {
get;
}
/// <summary> /// <summary>
/// Provides access to the official Raspberry Pi Camera /// Provides access to the official Raspberry Pi Camera
/// </summary> /// </summary>
public static CameraController Camera { get; } public static CameraController Camera {
get;
}
/// <summary> /// <summary>
/// Provides access to the official Raspberry Pi 7-inch DSI Display /// Provides access to the official Raspberry Pi 7-inch DSI Display
/// </summary> /// </summary>
public static DsiDisplay PiDisplay { get; } public static DsiDisplay PiDisplay {
get;
}
/// <summary> /// <summary>
/// Gets the logger source name. /// Gets the logger source name.
/// </summary> /// </summary>
internal static string LoggerSource => typeof(Pi).Namespace; internal static String LoggerSource => typeof(Pi).Namespace;
#endregion #endregion

View File

@ -1,24 +1,18 @@
namespace Unosquare.RaspberryIO.Resources using Unosquare.RaspberryIO.Native;
{ using Unosquare.Swan;
using Native;
using Swan;
using System; using System;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.IO; using System.IO;
namespace Unosquare.RaspberryIO.Resources {
/// <summary> /// <summary>
/// Provides access to embedded assembly files /// Provides access to embedded assembly files
/// </summary> /// </summary>
internal static class EmbeddedResources internal static class EmbeddedResources {
{
/// <summary> /// <summary>
/// Initializes static members of the <see cref="EmbeddedResources"/> class. /// Initializes static members of the <see cref="EmbeddedResources"/> class.
/// </summary> /// </summary>
static EmbeddedResources() static EmbeddedResources() => ResourceNames = new ReadOnlyCollection<String>(typeof(EmbeddedResources).Assembly().GetManifestResourceNames());
{
ResourceNames =
new ReadOnlyCollection<string>(typeof(EmbeddedResources).Assembly().GetManifestResourceNames());
}
/// <summary> /// <summary>
/// Gets the resource names. /// Gets the resource names.
@ -26,36 +20,32 @@
/// <value> /// <value>
/// The resource names. /// The resource names.
/// </value> /// </value>
public static ReadOnlyCollection<string> ResourceNames { get; } public static ReadOnlyCollection<String> ResourceNames {
get;
}
/// <summary> /// <summary>
/// Extracts all the file resources to the specified base path. /// Extracts all the file resources to the specified base path.
/// </summary> /// </summary>
public static void ExtractAll() public static void ExtractAll() {
{ String basePath = Runtime.EntryAssemblyDirectory;
var basePath = Runtime.EntryAssemblyDirectory; Int32 executablePermissions = Standard.StringToInteger("0777", IntPtr.Zero, 8);
var executablePermissions = Standard.StringToInteger("0777", IntPtr.Zero, 8);
foreach (var resourceName in ResourceNames) foreach(String resourceName in ResourceNames) {
{ String filename = resourceName.Substring($"{typeof(EmbeddedResources).Namespace}.".Length);
var filename = resourceName.Substring($"{typeof(EmbeddedResources).Namespace}.".Length); String targetPath = Path.Combine(basePath, filename);
var targetPath = Path.Combine(basePath, filename); if(File.Exists(targetPath)) {
if (File.Exists(targetPath)) return; return;
}
using (var stream = typeof(EmbeddedResources).Assembly() using(Stream stream = typeof(EmbeddedResources).Assembly().GetManifestResourceStream($"{typeof(EmbeddedResources).Namespace}.{filename}")) {
.GetManifestResourceStream($"{typeof(EmbeddedResources).Namespace}.{filename}")) using(FileStream outputStream = File.OpenWrite(targetPath)) {
{
using (var outputStream = File.OpenWrite(targetPath))
{
stream?.CopyTo(outputStream); stream?.CopyTo(outputStream);
} }
try try {
{ _ = Standard.Chmod(targetPath, (UInt32)executablePermissions);
Standard.Chmod(targetPath, (uint)executablePermissions); } catch {
}
catch
{
/* Ignore */ /* Ignore */
} }
} }