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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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
internal static readonly Lazy<GpioPin> Pin08 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin08, 3)
{
internal static readonly Lazy<GpioPin> Pin08 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin08, 3) {
Capabilities = new[] { PinCapability.GP, PinCapability.I2CSDA },
Name = "BCM 2 (SDA)"
});
internal static readonly Lazy<GpioPin> Pin09 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin09, 5)
{
internal static readonly Lazy<GpioPin> Pin09 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin09, 5) {
Capabilities = new[] { PinCapability.GP, PinCapability.I2CSCL },
Name = "BCM 3 (SCL)"
});
internal static readonly Lazy<GpioPin> Pin07 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin07, 7)
{
internal static readonly Lazy<GpioPin> Pin07 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin07, 7) {
Capabilities = new[] { PinCapability.GP, PinCapability.GPCLK },
Name = "BCM 4 (GPCLK0)"
});
internal static readonly Lazy<GpioPin> Pin00 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin00, 11)
{
internal static readonly Lazy<GpioPin> Pin00 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin00, 11) {
Capabilities = new[] { PinCapability.GP, PinCapability.UARTRTS },
Name = "BCM 17"
});
internal static readonly Lazy<GpioPin> Pin02 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin02, 13)
{
internal static readonly Lazy<GpioPin> Pin02 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin02, 13) {
Capabilities = new[] { PinCapability.GP },
Name = "BCM 27"
});
internal static readonly Lazy<GpioPin> Pin03 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin03, 15)
{
internal static readonly Lazy<GpioPin> Pin03 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin03, 15) {
Capabilities = new[] { PinCapability.GP },
Name = "BCM 22"
});
internal static readonly Lazy<GpioPin> Pin12 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin12, 19)
{
internal static readonly Lazy<GpioPin> Pin12 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin12, 19) {
Capabilities = new[] { PinCapability.GP, PinCapability.SPIMOSI },
Name = "BCM 10 (MOSI)"
});
internal static readonly Lazy<GpioPin> Pin13 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin13, 21)
{
internal static readonly Lazy<GpioPin> Pin13 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin13, 21) {
Capabilities = new[] { PinCapability.GP, PinCapability.SPIMISO },
Name = "BCM 9 (MISO)"
});
internal static readonly Lazy<GpioPin> Pin14 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin14, 23)
{
internal static readonly Lazy<GpioPin> Pin14 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin14, 23) {
Capabilities = new[] { PinCapability.GP, PinCapability.SPICLK },
Name = "BCM 11 (SCLCK)"
});
internal static readonly Lazy<GpioPin> Pin30 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin30, 27)
{
internal static readonly Lazy<GpioPin> Pin30 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin30, 27) {
Capabilities = new[] { PinCapability.I2CSDA },
Name = "BCM 0 (ID_SD)"
});
internal static readonly Lazy<GpioPin> Pin31 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin31, 28)
{
internal static readonly Lazy<GpioPin> Pin31 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin31, 28) {
Capabilities = new[] { PinCapability.I2CSCL },
Name = "BCM 1 (ID_SC)"
});
internal static readonly Lazy<GpioPin> Pin11 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin11, 26)
{
internal static readonly Lazy<GpioPin> Pin11 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin11, 26) {
Capabilities = new[] { PinCapability.GP, PinCapability.SPICS },
Name = "BCM 7 (CE1)"
});
internal static readonly Lazy<GpioPin> Pin10 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin10, 24)
{
internal static readonly Lazy<GpioPin> Pin10 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin10, 24) {
Capabilities = new[] { PinCapability.GP, PinCapability.SPICS },
Name = "BCM 8 (CE0)"
});
internal static readonly Lazy<GpioPin> Pin06 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin06, 22)
{
internal static readonly Lazy<GpioPin> Pin06 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin06, 22) {
Capabilities = new[] { PinCapability.GP },
Name = "BCM 25"
});
internal static readonly Lazy<GpioPin> Pin05 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin05, 18)
{
internal static readonly Lazy<GpioPin> Pin05 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin05, 18) {
Capabilities = new[] { PinCapability.GP },
Name = "BCM 24"
});
internal static readonly Lazy<GpioPin> Pin04 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin04, 16)
{
internal static readonly Lazy<GpioPin> Pin04 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin04, 16) {
Capabilities = new[] { PinCapability.GP },
Name = "BCM 23"
});
internal static readonly Lazy<GpioPin> Pin01 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin01, 12)
{
internal static readonly Lazy<GpioPin> Pin01 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin01, 12) {
Capabilities = new[] { PinCapability.GP, PinCapability.PWM },
Name = "BCM 18 (PWM0)"
});
internal static readonly Lazy<GpioPin> Pin16 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin16, 10)
{
internal static readonly Lazy<GpioPin> Pin16 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin16, 10) {
Capabilities = new[] { PinCapability.UARTRXD },
Name = "BCM 15 (RXD)"
});
internal static readonly Lazy<GpioPin> Pin15 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin15, 8)
{
internal static readonly Lazy<GpioPin> Pin15 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin15, 8) {
Capabilities = new[] { PinCapability.UARTTXD },
Name = "BCM 14 (TXD)"
});
internal static readonly Lazy<GpioPin> Pin21 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin21, 29)
{
internal static readonly Lazy<GpioPin> Pin21 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin21, 29) {
Capabilities = new[] { PinCapability.GP },
Name = "BCM 5"
});
internal static readonly Lazy<GpioPin> Pin22 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin22, 31)
{
internal static readonly Lazy<GpioPin> Pin22 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin22, 31) {
Capabilities = new[] { PinCapability.GP },
Name = "BCM 6"
});
internal static readonly Lazy<GpioPin> Pin23 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin23, 33)
{
internal static readonly Lazy<GpioPin> Pin23 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin23, 33) {
Capabilities = new[] { PinCapability.GP, PinCapability.PWM },
Name = "BCM 13 (PWM1)"
});
internal static readonly Lazy<GpioPin> Pin24 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin24, 35)
{
internal static readonly Lazy<GpioPin> Pin24 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin24, 35) {
Capabilities = new[] { PinCapability.GP, PinCapability.SPIMISO },
Name = "BCM 19 (MISO)"
});
internal static readonly Lazy<GpioPin> Pin25 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin25, 37)
{
internal static readonly Lazy<GpioPin> Pin25 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin25, 37) {
Capabilities = new[] { PinCapability.GP },
Name = "BCM 26"
});
internal static readonly Lazy<GpioPin> Pin29 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin29, 40)
{
internal static readonly Lazy<GpioPin> Pin29 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin29, 40) {
Capabilities = new[] { PinCapability.GP, PinCapability.SPICLK },
Name = "BCM 21 (SCLK)"
});
internal static readonly Lazy<GpioPin> Pin28 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin28, 38)
{
internal static readonly Lazy<GpioPin> Pin28 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin28, 38) {
Capabilities = new[] { PinCapability.GP, PinCapability.SPIMOSI },
Name = "BCM 20 (MOSI)"
});
internal static readonly Lazy<GpioPin> Pin27 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin27, 36)
{
internal static readonly Lazy<GpioPin> Pin27 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin27, 36) {
Capabilities = new[] { PinCapability.GP },
Name = "BCM 16"
});
internal static readonly Lazy<GpioPin> Pin26 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin26, 32)
{
internal static readonly Lazy<GpioPin> Pin26 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin26, 32) {
Capabilities = new[] { PinCapability.GP },
Name = "BCM 12 (PWM0)"
});
internal static readonly Lazy<GpioPin> Pin17 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin17, 3)
{
internal static readonly Lazy<GpioPin> Pin17 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin17, 3) {
Capabilities = new[] { PinCapability.GP, PinCapability.I2CSDA },
Name = "BCM 28 (SDA)"
});
internal static readonly Lazy<GpioPin> Pin18 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin18, 4)
{
internal static readonly Lazy<GpioPin> Pin18 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin18, 4) {
Capabilities = new[] { PinCapability.GP, PinCapability.I2CSCL },
Name = "BCM 29 (SCL)"
});
internal static readonly Lazy<GpioPin> Pin19 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin19, 5)
{
internal static readonly Lazy<GpioPin> Pin19 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin19, 5) {
Capabilities = new[] { PinCapability.GP },
Name = "BCM 30"
});
internal static readonly Lazy<GpioPin> Pin20 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin20, 6)
{
internal static readonly Lazy<GpioPin> Pin20 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin20, 6) {
Capabilities = new[] { PinCapability.GP },
Name = "BCM 31"
});

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,16 +1,14 @@
namespace Unosquare.RaspberryIO.Native
{
using Swan;
using Unosquare.Swan;
using System;
using System.Runtime.InteropServices;
using System.Text;
namespace Unosquare.RaspberryIO.Native {
/// <summary>
/// Provides standard libc calls using platform-invoke
/// </summary>
internal static class Standard
{
internal const string LibCLibrary = "libc";
internal static class Standard {
internal const String LibCLibrary = "libc";
#region LibC Calls
@ -19,18 +17,16 @@
/// </summary>
/// <param name="error">The error.</param>
/// <returns></returns>
public static string Strerror(int error)
{
if (!Runtime.IsUsingMonoRuntime) return StrError(error);
try
{
var buffer = new StringBuilder(256);
var result = Strerror(error, buffer, (ulong)buffer.Capacity);
return (result != -1) ? buffer.ToString() : null;
public static String Strerror(Int32 error) {
if(!Runtime.IsUsingMonoRuntime) {
return StrError(error);
}
catch (EntryPointNotFoundException)
{
try {
StringBuilder buffer = new StringBuilder(256);
Int32 result = Strerror(error, buffer, (UInt64)buffer.Capacity);
return (result != -1) ? buffer.ToString() : null;
} catch(EntryPointNotFoundException) {
return null;
}
}
@ -42,7 +38,7 @@
/// <param name="mode">The mode.</param>
/// <returns>The result</returns>
[DllImport(LibCLibrary, EntryPoint = "chmod", SetLastError = true)]
public static extern int Chmod(string filename, uint mode);
public static extern Int32 Chmod(String filename, UInt32 mode);
/// <summary>
/// Converts a string to a 32 bit integer. Use endpointer as IntPtr.Zero
@ -52,7 +48,7 @@
/// <param name="numberBase">The number base.</param>
/// <returns>The result</returns>
[DllImport(LibCLibrary, EntryPoint = "strtol", SetLastError = true)]
public static extern int StringToInteger(string numberString, IntPtr endPointer, int numberBase);
public static extern Int32 StringToInteger(String numberString, IntPtr endPointer, Int32 numberBase);
/// <summary>
/// The write() function attempts to write nbytes from buffer to the file associated with handle. On text files, it expands each LF to a CR/LF.
@ -63,7 +59,7 @@
/// <param name="count">The count.</param>
/// <returns>The result</returns>
[DllImport(LibCLibrary, EntryPoint = "write", SetLastError = true)]
public static extern int Write(int fd, byte[] buffer, int count);
public static extern Int32 Write(Int32 fd, Byte[] buffer, Int32 count);
/// <summary>
/// Fills in the structure with information about the system.
@ -71,13 +67,13 @@
/// <param name="name">The name.</param>
/// <returns>The result</returns>
[DllImport(LibCLibrary, EntryPoint = "uname", SetLastError = true)]
public static extern int Uname(out SystemName name);
public static extern Int32 Uname(out SystemName name);
[DllImport(LibCLibrary, EntryPoint = "strerror", SetLastError = true)]
private static extern string StrError(int errnum);
private static extern String StrError(Int32 errnum);
[DllImport("MonoPosixHelper", EntryPoint = "Mono_Posix_Syscall_strerror_r", SetLastError = true)]
private static extern int Strerror(int error, [Out] StringBuilder buffer, ulong length);
private static extern Int32 Strerror(Int32 error, [Out] StringBuilder buffer, UInt64 length);
#endregion
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,9 +1,8 @@
namespace Unosquare.RaspberryIO.Native
{
using System;
using System.Runtime.InteropServices;
public partial class WiringPi
{
namespace Unosquare.RaspberryIO.Native {
public partial class WiringPi {
#region WiringPi - Shift Library
/// <summary>
@ -16,7 +15,7 @@
/// <param name="order">The order.</param>
/// <returns>The result</returns>
[DllImport(WiringPiLibrary, EntryPoint = "shiftIn", SetLastError = true)]
public static extern byte ShiftIn(byte dPin, byte cPin, byte order);
public static extern Byte ShiftIn(Byte dPin, Byte cPin, Byte order);
/// <summary>
/// The shifts an 8-bit data value val out with the data being sent out on dPin and the clock being sent out on the cPin.
@ -28,7 +27,7 @@
/// <param name="order">The order.</param>
/// <param name="val">The value.</param>
[DllImport(WiringPiLibrary, EntryPoint = "shiftOut", SetLastError = true)]
public static extern void ShiftOut(byte dPin, byte cPin, byte order, byte val);
public static extern void ShiftOut(Byte dPin, Byte cPin, Byte order, Byte val);
#endregion

View File

@ -1,9 +1,8 @@
namespace Unosquare.RaspberryIO.Native
{
using System;
using System.Runtime.InteropServices;
public partial class WiringPi
{
namespace Unosquare.RaspberryIO.Native {
public partial class WiringPi {
#region WiringPi - Soft PWM (https://github.com/WiringPi/WiringPi/blob/master/wiringPi/softPwm.h)
/// <summary>
@ -16,7 +15,7 @@
/// <param name="pwmRange">The PWM range.</param>
/// <returns>The result</returns>
[DllImport(WiringPiLibrary, EntryPoint = "softPwmCreate", SetLastError = true)]
public static extern int SoftPwmCreate(int pin, int initialValue, int pwmRange);
public static extern Int32 SoftPwmCreate(Int32 pin, Int32 initialValue, Int32 pwmRange);
/// <summary>
/// This updates the PWM value on the given pin. The value is checked to be in-range and pins that havent previously
@ -25,14 +24,14 @@
/// <param name="pin">The pin.</param>
/// <param name="value">The value.</param>
[DllImport(WiringPiLibrary, EntryPoint = "softPwmWrite", SetLastError = true)]
public static extern void SoftPwmWrite(int pin, int value);
public static extern void SoftPwmWrite(Int32 pin, Int32 value);
/// <summary>
/// This function is undocumented
/// </summary>
/// <param name="pin">The pin.</param>
[DllImport(WiringPiLibrary, EntryPoint = "softPwmStop", SetLastError = true)]
public static extern void SoftPwmStop(int pin);
public static extern void SoftPwmStop(Int32 pin);
/// <summary>
/// This creates a software controlled tone pin. You can use any GPIO pin and the pin numbering will be that of the wiringPiSetup() function you used.
@ -41,14 +40,14 @@
/// <param name="pin">The pin.</param>
/// <returns>The result</returns>
[DllImport(WiringPiLibrary, EntryPoint = "softToneCreate", SetLastError = true)]
public static extern int SoftToneCreate(int pin);
public static extern Int32 SoftToneCreate(Int32 pin);
/// <summary>
/// This function is undocumented
/// </summary>
/// <param name="pin">The pin.</param>
[DllImport(WiringPiLibrary, EntryPoint = "softToneStop", SetLastError = true)]
public static extern void SoftToneStop(int pin);
public static extern void SoftToneStop(Int32 pin);
/// <summary>
/// This updates the tone frequency value on the given pin. The tone will be played until you set the frequency to 0.
@ -56,7 +55,7 @@
/// <param name="pin">The pin.</param>
/// <param name="freq">The freq.</param>
[DllImport(WiringPiLibrary, EntryPoint = "softToneWrite", SetLastError = true)]
public static extern void SoftToneWrite(int pin, int freq);
public static extern void SoftToneWrite(Int32 pin, Int32 freq);
#endregion

View File

@ -1,9 +1,8 @@
namespace Unosquare.RaspberryIO.Native
{
using System;
using System.Runtime.InteropServices;
public partial class WiringPi
{
namespace Unosquare.RaspberryIO.Native {
public partial class WiringPi {
#region WiringPi - SPI Library Calls
/// <summary>
@ -12,7 +11,7 @@
/// <param name="channel">The channel.</param>
/// <returns>Unknown</returns>
[DllImport(WiringPiLibrary, EntryPoint = "wiringPiSPIGetFd", SetLastError = true)]
public static extern int WiringPiSPIGetFd(int channel);
public static extern Int32 WiringPiSPIGetFd(Int32 channel);
/// <summary>
/// This performs a simultaneous write/read transaction over the selected SPI bus. Data that was in your buffer is overwritten by data returned from the SPI bus.
@ -25,7 +24,7 @@
/// <param name="len">The length.</param>
/// <returns>The result</returns>
[DllImport(WiringPiLibrary, EntryPoint = "wiringPiSPIDataRW", SetLastError = true)]
public static extern int WiringPiSPIDataRW(int channel, byte[] data, int len);
public static extern Int32 WiringPiSPIDataRW(Int32 channel, Byte[] data, Int32 len);
/// <summary>
/// This function is undocumented
@ -35,7 +34,7 @@
/// <param name="mode">The mode.</param>
/// <returns>Unkown</returns>
[DllImport(WiringPiLibrary, EntryPoint = "wiringPiSPISetupMode", SetLastError = true)]
public static extern int WiringPiSPISetupMode(int channel, int speed, int mode);
public static extern Int32 WiringPiSPISetupMode(Int32 channel, Int32 speed, Int32 mode);
/// <summary>
/// This is the way to initialize a channel (The Pi has 2 channels; 0 and 1). The speed parameter is an integer
@ -46,7 +45,7 @@
/// <param name="speed">The speed.</param>
/// <returns>The Linux file descriptor for the device or -1 for error</returns>
[DllImport(WiringPiLibrary, EntryPoint = "wiringPiSPISetup", SetLastError = true)]
public static extern int WiringPiSPISetup(int channel, int speed);
public static extern Int32 WiringPiSPISetup(Int32 channel, Int32 speed);
#endregion
}

View File

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

View File

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

View File

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