Coding styles
This commit is contained in:
parent
d75c3bc73f
commit
186792fde8
@ -1,134 +1,140 @@
|
|||||||
namespace Unosquare.RaspberryIO.Camera
|
using Unosquare.Swan;
|
||||||
{
|
using System;
|
||||||
using Swan;
|
using System.Linq;
|
||||||
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 {
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A simple RGB color class to represent colors in RGB and YUV colorspaces.
|
/// Initializes a new instance of the <see cref="CameraColor"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class CameraColor
|
/// <param name="r">The red.</param>
|
||||||
{
|
/// <param name="g">The green.</param>
|
||||||
/// <summary>
|
/// <param name="b">The blue.</param>
|
||||||
/// Initializes a new instance of the <see cref="CameraColor"/> class.
|
public CameraColor(Int32 r, Int32 g, Int32 b)
|
||||||
/// </summary>
|
: this(r, g, b, String.Empty) {
|
||||||
/// <param name="r">The red.</param>
|
}
|
||||||
/// <param name="g">The green.</param>
|
|
||||||
/// <param name="b">The blue.</param>
|
/// <summary>
|
||||||
public CameraColor(int r, int g, int b)
|
/// Initializes a new instance of the <see cref="CameraColor"/> class.
|
||||||
: this(r, g, b, string.Empty)
|
/// </summary>
|
||||||
{
|
/// <param name="r">The red.</param>
|
||||||
}
|
/// <param name="g">The green.</param>
|
||||||
|
/// <param name="b">The blue.</param>
|
||||||
/// <summary>
|
/// <param name="name">The well-known color name.</param>
|
||||||
/// Initializes a new instance of the <see cref="CameraColor"/> class.
|
public CameraColor(Int32 r, Int32 g, Int32 b, String name) {
|
||||||
/// </summary>
|
this.RGB = new[] { Convert.ToByte(r.Clamp(0, 255)), Convert.ToByte(g.Clamp(0, 255)), Convert.ToByte(b.Clamp(0, 255)) };
|
||||||
/// <param name="r">The red.</param>
|
|
||||||
/// <param name="g">The green.</param>
|
Single y = this.R * .299000f + this.G * .587000f + this.B * .114000f;
|
||||||
/// <param name="b">The blue.</param>
|
Single u = this.R * -.168736f + this.G * -.331264f + this.B * .500000f + 128f;
|
||||||
/// <param name="name">The well-known color name.</param>
|
Single v = this.R * .500000f + this.G * -.418688f + this.B * -.081312f + 128f;
|
||||||
public CameraColor(int r, int g, int b, string name)
|
|
||||||
{
|
this.YUV = new Byte[] { (Byte)y.Clamp(0, 255), (Byte)u.Clamp(0, 255), (Byte)v.Clamp(0, 255) };
|
||||||
RGB = new[] { Convert.ToByte(r.Clamp(0, 255)), Convert.ToByte(g.Clamp(0, 255)), Convert.ToByte(b.Clamp(0, 255)) };
|
this.Name = name;
|
||||||
|
}
|
||||||
var y = (R * .299000f) + (G * .587000f) + (B * .114000f);
|
|
||||||
var u = (R * -.168736f) + (G * -.331264f) + (B * .500000f) + 128f;
|
#region Static Definitions
|
||||||
var v = (R * .500000f) + (G * -.418688f) + (B * -.081312f) + 128f;
|
|
||||||
|
/// <summary>
|
||||||
YUV = new byte[] { (byte)y.Clamp(0, 255), (byte)u.Clamp(0, 255), (byte)v.Clamp(0, 255) };
|
/// Gets the predefined white color.
|
||||||
Name = name;
|
/// </summary>
|
||||||
}
|
public static CameraColor White => new CameraColor(255, 255, 255, nameof(White));
|
||||||
|
|
||||||
#region Static Definitions
|
/// <summary>
|
||||||
|
/// Gets the predefined red color.
|
||||||
/// <summary>
|
/// </summary>
|
||||||
/// Gets the predefined white color.
|
public static CameraColor Red => new CameraColor(255, 0, 0, nameof(Red));
|
||||||
/// </summary>
|
|
||||||
public static CameraColor White => new CameraColor(255, 255, 255, nameof(White));
|
/// <summary>
|
||||||
|
/// Gets the predefined green color.
|
||||||
/// <summary>
|
/// </summary>
|
||||||
/// Gets the predefined red color.
|
public static CameraColor Green => new CameraColor(0, 255, 0, nameof(Green));
|
||||||
/// </summary>
|
|
||||||
public static CameraColor Red => new CameraColor(255, 0, 0, nameof(Red));
|
/// <summary>
|
||||||
|
/// Gets the predefined blue color.
|
||||||
/// <summary>
|
/// </summary>
|
||||||
/// Gets the predefined green color.
|
public static CameraColor Blue => new CameraColor(0, 0, 255, nameof(Blue));
|
||||||
/// </summary>
|
|
||||||
public static CameraColor Green => new CameraColor(0, 255, 0, nameof(Green));
|
/// <summary>
|
||||||
|
/// Gets the predefined black color.
|
||||||
/// <summary>
|
/// </summary>
|
||||||
/// Gets the predefined blue color.
|
public static CameraColor Black => new CameraColor(0, 0, 0, nameof(Black));
|
||||||
/// </summary>
|
|
||||||
public static CameraColor Blue => new CameraColor(0, 0, 255, nameof(Blue));
|
#endregion
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the predefined black color.
|
/// Gets the well-known color name.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static CameraColor Black => new CameraColor(0, 0, 0, nameof(Black));
|
public String Name {
|
||||||
|
get;
|
||||||
#endregion
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the well-known color name.
|
/// Gets the red byte.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Name { get; }
|
public Byte R => this.RGB[0];
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the red byte.
|
/// Gets the green byte.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public byte R => RGB[0];
|
public Byte G => this.RGB[1];
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the green byte.
|
/// Gets the blue byte.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public byte G => RGB[1];
|
public Byte B => this.RGB[2];
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the blue byte.
|
/// Gets the RGB byte array (3 bytes).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public byte B => RGB[2];
|
public Byte[] RGB {
|
||||||
|
get;
|
||||||
/// <summary>
|
}
|
||||||
/// Gets the RGB byte array (3 bytes).
|
|
||||||
/// </summary>
|
/// <summary>
|
||||||
public byte[] RGB { get; }
|
/// Gets the YUV byte array (3 bytes).
|
||||||
|
/// </summary>
|
||||||
/// <summary>
|
public Byte[] YUV {
|
||||||
/// Gets the YUV byte array (3 bytes).
|
get;
|
||||||
/// </summary>
|
}
|
||||||
public byte[] YUV { get; }
|
|
||||||
|
/// <summary>
|
||||||
/// <summary>
|
/// Returns a hexadecimal representation of the RGB byte array.
|
||||||
/// Returns a hexadecimal representation of the RGB byte array.
|
/// Preceded by 0x and all in lowercase
|
||||||
/// Preceded by 0x and all in lowercase
|
/// </summary>
|
||||||
/// </summary>
|
/// <param name="reverse">if set to <c>true</c> [reverse].</param>
|
||||||
/// <param name="reverse">if set to <c>true</c> [reverse].</param>
|
/// <returns>A string</returns>
|
||||||
/// <returns>A string</returns>
|
public String ToRgbHex(Boolean reverse) {
|
||||||
public string ToRgbHex(bool reverse)
|
Byte[] data = this.RGB.ToArray();
|
||||||
{
|
if(reverse) {
|
||||||
var data = RGB.ToArray();
|
Array.Reverse(data);
|
||||||
if (reverse) Array.Reverse(data);
|
}
|
||||||
return ToHex(data);
|
|
||||||
}
|
return ToHex(data);
|
||||||
|
}
|
||||||
/// <summary>
|
|
||||||
/// Returns a hexadecimal representation of the YUV byte array.
|
/// <summary>
|
||||||
/// Preceded by 0x and all in lowercase
|
/// Returns a hexadecimal representation of the YUV byte array.
|
||||||
/// </summary>
|
/// Preceded by 0x and all in lowercase
|
||||||
/// <param name="reverse">if set to <c>true</c> [reverse].</param>
|
/// </summary>
|
||||||
/// <returns>A string</returns>
|
/// <param name="reverse">if set to <c>true</c> [reverse].</param>
|
||||||
public string ToYuvHex(bool reverse)
|
/// <returns>A string</returns>
|
||||||
{
|
public String ToYuvHex(Boolean reverse) {
|
||||||
var data = YUV.ToArray();
|
Byte[] data = this.YUV.ToArray();
|
||||||
if (reverse) Array.Reverse(data);
|
if(reverse) {
|
||||||
return ToHex(data);
|
Array.Reverse(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
return ToHex(data);
|
||||||
/// Returns a hexadecimal representation of the data byte array
|
}
|
||||||
/// </summary>
|
|
||||||
/// <param name="data">The data.</param>
|
/// <summary>
|
||||||
/// <returns>A string</returns>
|
/// Returns a hexadecimal representation of the data byte array
|
||||||
private static string ToHex(byte[] data) => $"0x{BitConverter.ToString(data).Replace("-", string.Empty).ToLowerInvariant()}";
|
/// </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()}";
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,216 +1,190 @@
|
|||||||
namespace Unosquare.RaspberryIO.Camera
|
using Unosquare.Swan.Abstractions;
|
||||||
{
|
using System;
|
||||||
using Swan.Abstractions;
|
using Unosquare.Swan.Components;
|
||||||
using System;
|
using System.IO;
|
||||||
using Swan.Components;
|
using System.Threading;
|
||||||
using System.IO;
|
using System.Threading.Tasks;
|
||||||
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> {
|
||||||
|
#region Private Declarations
|
||||||
|
|
||||||
|
private static readonly ManualResetEventSlim OperationDone = new ManualResetEventSlim(true);
|
||||||
|
private static readonly Object SyncRoot = new Object();
|
||||||
|
private static CancellationTokenSource _videoTokenSource = new CancellationTokenSource();
|
||||||
|
private static Task<Task> _videoStreamTask;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The Raspberry Pi's camera controller wrapping raspistill and raspivid programs.
|
/// Gets a value indicating whether the camera module is busy.
|
||||||
/// This class is a singleton
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class CameraController : SingletonBase<CameraController>
|
/// <value>
|
||||||
{
|
/// <c>true</c> if this instance is busy; otherwise, <c>false</c>.
|
||||||
#region Private Declarations
|
/// </value>
|
||||||
|
public Boolean IsBusy => OperationDone.IsSet == false;
|
||||||
private static readonly ManualResetEventSlim OperationDone = new ManualResetEventSlim(true);
|
|
||||||
private static readonly object SyncRoot = new object();
|
#endregion
|
||||||
private static CancellationTokenSource _videoTokenSource = new CancellationTokenSource();
|
|
||||||
private static Task<Task> _videoStreamTask;
|
#region Image Capture Methods
|
||||||
|
|
||||||
#endregion
|
/// <summary>
|
||||||
|
/// Captures an image asynchronously.
|
||||||
#region Properties
|
/// </summary>
|
||||||
|
/// <param name="settings">The settings.</param>
|
||||||
/// <summary>
|
/// <param name="ct">The ct.</param>
|
||||||
/// Gets a value indicating whether the camera module is busy.
|
/// <returns>The image bytes</returns>
|
||||||
/// </summary>
|
/// <exception cref="InvalidOperationException">Cannot use camera module because it is currently busy.</exception>
|
||||||
/// <value>
|
[System.Diagnostics.CodeAnalysis.SuppressMessage("Codequalität", "IDE0067:Objekte verwerfen, bevor Bereich verloren geht", Justification = "<Ausstehend>")]
|
||||||
/// <c>true</c> if this instance is busy; otherwise, <c>false</c>.
|
public async Task<Byte[]> CaptureImageAsync(CameraStillSettings settings, CancellationToken ct = default) {
|
||||||
/// </value>
|
if(Instance.IsBusy) {
|
||||||
public bool IsBusy => OperationDone.IsSet == false;
|
throw new InvalidOperationException("Cannot use camera module because it is currently busy.");
|
||||||
|
}
|
||||||
#endregion
|
|
||||||
|
if(settings.CaptureTimeoutMilliseconds <= 0) {
|
||||||
#region Image Capture Methods
|
throw new ArgumentException($"{nameof(settings.CaptureTimeoutMilliseconds)} needs to be greater than 0");
|
||||||
|
}
|
||||||
/// <summary>
|
|
||||||
/// Captures an image asynchronously.
|
try {
|
||||||
/// </summary>
|
OperationDone.Reset();
|
||||||
/// <param name="settings">The settings.</param>
|
|
||||||
/// <param name="ct">The ct.</param>
|
MemoryStream output = new MemoryStream();
|
||||||
/// <returns>The image bytes</returns>
|
Int32 exitCode = await ProcessRunner.RunProcessAsync(
|
||||||
/// <exception cref="InvalidOperationException">Cannot use camera module because it is currently busy.</exception>
|
settings.CommandName,
|
||||||
public async Task<byte[]> CaptureImageAsync(CameraStillSettings settings, CancellationToken ct = default)
|
settings.CreateProcessArguments(),
|
||||||
{
|
(data, proc) => output.Write(data, 0, data.Length),
|
||||||
if (Instance.IsBusy)
|
null,
|
||||||
throw new InvalidOperationException("Cannot use camera module because it is currently busy.");
|
true,
|
||||||
|
ct);
|
||||||
if (settings.CaptureTimeoutMilliseconds <= 0)
|
|
||||||
throw new ArgumentException($"{nameof(settings.CaptureTimeoutMilliseconds)} needs to be greater than 0");
|
return exitCode != 0 ? new Byte[] { } : output.ToArray();
|
||||||
|
} finally {
|
||||||
try
|
OperationDone.Set();
|
||||||
{
|
}
|
||||||
OperationDone.Reset();
|
}
|
||||||
|
|
||||||
var output = new MemoryStream();
|
/// <summary>
|
||||||
var exitCode = await ProcessRunner.RunProcessAsync(
|
/// Captures an image.
|
||||||
settings.CommandName,
|
/// </summary>
|
||||||
settings.CreateProcessArguments(),
|
/// <param name="settings">The settings.</param>
|
||||||
(data, proc) =>
|
/// <returns>The image bytes</returns>
|
||||||
{
|
public Byte[] CaptureImage(CameraStillSettings settings) => this.CaptureImageAsync(settings).GetAwaiter().GetResult();
|
||||||
output.Write(data, 0, data.Length);
|
|
||||||
},
|
/// <summary>
|
||||||
null,
|
/// Captures a JPEG encoded image asynchronously at 90% quality.
|
||||||
true,
|
/// </summary>
|
||||||
ct);
|
/// <param name="width">The width.</param>
|
||||||
|
/// <param name="height">The height.</param>
|
||||||
return exitCode != 0 ? new byte[] { } : output.ToArray();
|
/// <param name="ct">The ct.</param>
|
||||||
}
|
/// <returns>The image bytes</returns>
|
||||||
finally
|
public Task<Byte[]> CaptureImageJpegAsync(Int32 width, Int32 height, CancellationToken ct = default) {
|
||||||
{
|
CameraStillSettings settings = new CameraStillSettings {
|
||||||
OperationDone.Set();
|
CaptureWidth = width,
|
||||||
}
|
CaptureHeight = height,
|
||||||
}
|
CaptureJpegQuality = 90,
|
||||||
|
CaptureTimeoutMilliseconds = 300,
|
||||||
/// <summary>
|
};
|
||||||
/// Captures an image.
|
|
||||||
/// </summary>
|
return this.CaptureImageAsync(settings, ct);
|
||||||
/// <param name="settings">The settings.</param>
|
}
|
||||||
/// <returns>The image bytes</returns>
|
|
||||||
public byte[] CaptureImage(CameraStillSettings settings)
|
/// <summary>
|
||||||
{
|
/// Captures a JPEG encoded image at 90% quality.
|
||||||
return CaptureImageAsync(settings).GetAwaiter().GetResult();
|
/// </summary>
|
||||||
}
|
/// <param name="width">The width.</param>
|
||||||
|
/// <param name="height">The height.</param>
|
||||||
/// <summary>
|
/// <returns>The image bytes</returns>
|
||||||
/// Captures a JPEG encoded image asynchronously at 90% quality.
|
public Byte[] CaptureImageJpeg(Int32 width, Int32 height) => this.CaptureImageJpegAsync(width, height).GetAwaiter().GetResult();
|
||||||
/// </summary>
|
|
||||||
/// <param name="width">The width.</param>
|
#endregion
|
||||||
/// <param name="height">The height.</param>
|
|
||||||
/// <param name="ct">The ct.</param>
|
#region Video Capture Methods
|
||||||
/// <returns>The image bytes</returns>
|
|
||||||
public Task<byte[]> CaptureImageJpegAsync(int width, int height, CancellationToken ct = default)
|
/// <summary>
|
||||||
{
|
/// Opens the video stream with a timeout of 0 (running indefinitely) at 1080p resolution, variable bitrate and 25 FPS.
|
||||||
var settings = new CameraStillSettings
|
/// No preview is shown
|
||||||
{
|
/// </summary>
|
||||||
CaptureWidth = width,
|
/// <param name="onDataCallback">The on data callback.</param>
|
||||||
CaptureHeight = height,
|
/// <param name="onExitCallback">The on exit callback.</param>
|
||||||
CaptureJpegQuality = 90,
|
public void OpenVideoStream(Action<Byte[]> onDataCallback, Action onExitCallback = null) {
|
||||||
CaptureTimeoutMilliseconds = 300,
|
CameraVideoSettings settings = new CameraVideoSettings {
|
||||||
};
|
CaptureTimeoutMilliseconds = 0,
|
||||||
|
CaptureDisplayPreview = false,
|
||||||
return CaptureImageAsync(settings, ct);
|
CaptureWidth = 1920,
|
||||||
}
|
CaptureHeight = 1080
|
||||||
|
};
|
||||||
/// <summary>
|
|
||||||
/// Captures a JPEG encoded image at 90% quality.
|
this.OpenVideoStream(settings, onDataCallback, onExitCallback);
|
||||||
/// </summary>
|
}
|
||||||
/// <param name="width">The width.</param>
|
|
||||||
/// <param name="height">The height.</param>
|
/// <summary>
|
||||||
/// <returns>The image bytes</returns>
|
/// Opens the video stream with the supplied settings. Capture Timeout Milliseconds has to be 0 or greater
|
||||||
public byte[] CaptureImageJpeg(int width, int height) => CaptureImageJpegAsync(width, height).GetAwaiter().GetResult();
|
/// </summary>
|
||||||
|
/// <param name="settings">The settings.</param>
|
||||||
#endregion
|
/// <param name="onDataCallback">The on data callback.</param>
|
||||||
|
/// <param name="onExitCallback">The on exit callback.</param>
|
||||||
#region Video Capture Methods
|
/// <exception cref="InvalidOperationException">Cannot use camera module because it is currently busy.</exception>
|
||||||
|
/// <exception cref="ArgumentException">CaptureTimeoutMilliseconds</exception>
|
||||||
/// <summary>
|
public void OpenVideoStream(CameraVideoSettings settings, Action<Byte[]> onDataCallback, Action onExitCallback) {
|
||||||
/// Opens the video stream with a timeout of 0 (running indefinitely) at 1080p resolution, variable bitrate and 25 FPS.
|
if(Instance.IsBusy) {
|
||||||
/// No preview is shown
|
throw new InvalidOperationException("Cannot use camera module because it is currently busy.");
|
||||||
/// </summary>
|
}
|
||||||
/// <param name="onDataCallback">The on data callback.</param>
|
|
||||||
/// <param name="onExitCallback">The on exit callback.</param>
|
if(settings.CaptureTimeoutMilliseconds < 0) {
|
||||||
public void OpenVideoStream(Action<byte[]> onDataCallback, Action onExitCallback = null)
|
throw new ArgumentException($"{nameof(settings.CaptureTimeoutMilliseconds)} needs to be greater than or equal to 0");
|
||||||
{
|
}
|
||||||
var settings = new CameraVideoSettings
|
|
||||||
{
|
try {
|
||||||
CaptureTimeoutMilliseconds = 0,
|
OperationDone.Reset();
|
||||||
CaptureDisplayPreview = false,
|
_videoStreamTask = Task.Factory.StartNew(() => VideoWorkerDoWork(settings, onDataCallback, onExitCallback), _videoTokenSource.Token);
|
||||||
CaptureWidth = 1920,
|
} catch {
|
||||||
CaptureHeight = 1080
|
OperationDone.Set();
|
||||||
};
|
throw;
|
||||||
|
}
|
||||||
OpenVideoStream(settings, onDataCallback, onExitCallback);
|
}
|
||||||
}
|
|
||||||
|
/// <summary>
|
||||||
/// <summary>
|
/// Closes the video stream of a video stream is open.
|
||||||
/// Opens the video stream with the supplied settings. Capture Timeout Milliseconds has to be 0 or greater
|
/// </summary>
|
||||||
/// </summary>
|
public void CloseVideoStream() {
|
||||||
/// <param name="settings">The settings.</param>
|
lock(SyncRoot) {
|
||||||
/// <param name="onDataCallback">The on data callback.</param>
|
if(this.IsBusy == false) {
|
||||||
/// <param name="onExitCallback">The on exit callback.</param>
|
return;
|
||||||
/// <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(_videoTokenSource.IsCancellationRequested == false) {
|
||||||
if (Instance.IsBusy)
|
_videoTokenSource.Cancel();
|
||||||
throw new InvalidOperationException("Cannot use camera module because it is currently busy.");
|
_videoStreamTask.Wait();
|
||||||
|
}
|
||||||
if (settings.CaptureTimeoutMilliseconds < 0)
|
|
||||||
throw new ArgumentException($"{nameof(settings.CaptureTimeoutMilliseconds)} needs to be greater than or equal to 0");
|
_videoTokenSource = new CancellationTokenSource();
|
||||||
|
}
|
||||||
try
|
|
||||||
{
|
private static async Task VideoWorkerDoWork(CameraVideoSettings settings, Action<Byte[]> onDataCallback, Action onExitCallback) {
|
||||||
OperationDone.Reset();
|
try {
|
||||||
_videoStreamTask = Task.Factory.StartNew(() => VideoWorkerDoWork(settings, onDataCallback, onExitCallback), _videoTokenSource.Token);
|
await ProcessRunner.RunProcessAsync(
|
||||||
}
|
settings.CommandName,
|
||||||
catch
|
settings.CreateProcessArguments(),
|
||||||
{
|
(data, proc) => onDataCallback?.Invoke(data),
|
||||||
OperationDone.Set();
|
null,
|
||||||
throw;
|
true,
|
||||||
}
|
_videoTokenSource.Token);
|
||||||
}
|
|
||||||
|
onExitCallback?.Invoke();
|
||||||
/// <summary>
|
} catch {
|
||||||
/// Closes the video stream of a video stream is open.
|
// swallow
|
||||||
/// </summary>
|
} finally {
|
||||||
public void CloseVideoStream()
|
Instance.CloseVideoStream();
|
||||||
{
|
OperationDone.Set();
|
||||||
lock (SyncRoot)
|
}
|
||||||
{
|
}
|
||||||
if (IsBusy == false)
|
#endregion
|
||||||
return;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (_videoTokenSource.IsCancellationRequested == false)
|
|
||||||
{
|
|
||||||
_videoTokenSource.Cancel();
|
|
||||||
_videoStreamTask.Wait();
|
|
||||||
}
|
|
||||||
|
|
||||||
_videoTokenSource = new CancellationTokenSource();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static async Task VideoWorkerDoWork(
|
|
||||||
CameraVideoSettings settings,
|
|
||||||
Action<byte[]> onDataCallback,
|
|
||||||
Action onExitCallback)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await ProcessRunner.RunProcessAsync(
|
|
||||||
settings.CommandName,
|
|
||||||
settings.CreateProcessArguments(),
|
|
||||||
(data, proc) => onDataCallback?.Invoke(data),
|
|
||||||
null,
|
|
||||||
true,
|
|
||||||
_videoTokenSource.Token);
|
|
||||||
|
|
||||||
onExitCallback?.Invoke();
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
// swallow
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
Instance.CloseVideoStream();
|
|
||||||
OperationDone.Set();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -1,82 +1,86 @@
|
|||||||
namespace Unosquare.RaspberryIO.Camera
|
using Unosquare.Swan;
|
||||||
{
|
using System;
|
||||||
using Swan;
|
using System.Globalization;
|
||||||
using System.Globalization;
|
|
||||||
|
namespace Unosquare.RaspberryIO.Camera {
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the Raspberry Pi camera's sensor ROI (Region of Interest)
|
||||||
|
/// </summary>
|
||||||
|
public struct CameraRect {
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Defines the Raspberry Pi camera's sensor ROI (Region of Interest)
|
/// The default ROI which is the entire area.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public struct CameraRect
|
public static readonly CameraRect Default = new CameraRect { X = 0M, Y = 0M, W = 1.0M, H = 1.0M };
|
||||||
{
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The default ROI which is the entire area.
|
/// Gets or sets the x in relative coordinates. (0.0 to 1.0)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static readonly CameraRect Default = new CameraRect { X = 0M, Y = 0M, W = 1.0M, H = 1.0M };
|
/// <value>
|
||||||
|
/// The x.
|
||||||
/// <summary>
|
/// </value>
|
||||||
/// Gets or sets the x in relative coordinates. (0.0 to 1.0)
|
public Decimal X {
|
||||||
/// </summary>
|
get; set;
|
||||||
/// <value>
|
}
|
||||||
/// The x.
|
|
||||||
/// </value>
|
/// <summary>
|
||||||
public decimal X { get; set; }
|
/// Gets or sets the y location in relative coordinates. (0.0 to 1.0)
|
||||||
|
/// </summary>
|
||||||
/// <summary>
|
/// <value>
|
||||||
/// Gets or sets the y location in relative coordinates. (0.0 to 1.0)
|
/// The y.
|
||||||
/// </summary>
|
/// </value>
|
||||||
/// <value>
|
public Decimal Y {
|
||||||
/// The y.
|
get; set;
|
||||||
/// </value>
|
}
|
||||||
public decimal Y { get; set; }
|
|
||||||
|
/// <summary>
|
||||||
/// <summary>
|
/// Gets or sets the width in relative coordinates. (0.0 to 1.0)
|
||||||
/// Gets or sets the width in relative coordinates. (0.0 to 1.0)
|
/// </summary>
|
||||||
/// </summary>
|
/// <value>
|
||||||
/// <value>
|
/// The w.
|
||||||
/// The w.
|
/// </value>
|
||||||
/// </value>
|
public Decimal W {
|
||||||
public decimal W { get; set; }
|
get; set;
|
||||||
|
}
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the height in relative coordinates. (0.0 to 1.0)
|
/// <summary>
|
||||||
/// </summary>
|
/// Gets or sets the height in relative coordinates. (0.0 to 1.0)
|
||||||
/// <value>
|
/// </summary>
|
||||||
/// The h.
|
/// <value>
|
||||||
/// </value>
|
/// The h.
|
||||||
public decimal H { get; set; }
|
/// </value>
|
||||||
|
public Decimal H {
|
||||||
/// <summary>
|
get; set;
|
||||||
/// Gets a value indicating whether this instance is equal to the default (The entire area).
|
}
|
||||||
/// </summary>
|
|
||||||
/// <value>
|
/// <summary>
|
||||||
/// <c>true</c> if this instance is default; otherwise, <c>false</c>.
|
/// Gets a value indicating whether this instance is equal to the default (The entire area).
|
||||||
/// </value>
|
/// </summary>
|
||||||
public bool IsDefault
|
/// <value>
|
||||||
{
|
/// <c>true</c> if this instance is default; otherwise, <c>false</c>.
|
||||||
get
|
/// </value>
|
||||||
{
|
public Boolean IsDefault {
|
||||||
Clamp();
|
get {
|
||||||
return X == Default.X && Y == Default.Y && W == Default.W && H == Default.H;
|
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>
|
||||||
/// </summary>
|
/// Clamps the members of this ROI to their minimum and maximum values
|
||||||
public void Clamp()
|
/// </summary>
|
||||||
{
|
public void Clamp() {
|
||||||
X = X.Clamp(0M, 1M);
|
this.X = this.X.Clamp(0M, 1M);
|
||||||
Y = Y.Clamp(0M, 1M);
|
this.Y = this.Y.Clamp(0M, 1M);
|
||||||
W = W.Clamp(0M, 1M - X);
|
this.W = this.W.Clamp(0M, 1M - this.X);
|
||||||
H = H.Clamp(0M, 1M - Y);
|
this.H = this.H.Clamp(0M, 1M - this.Y);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns a <see cref="string" /> that represents this instance.
|
/// Returns a <see cref="String" /> that represents this instance.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>
|
/// <returns>
|
||||||
/// A <see cref="string" /> that represents this instance.
|
/// A <see cref="String" /> that represents this instance.
|
||||||
/// </returns>
|
/// </returns>
|
||||||
public override string ToString() => $"{X.ToString(CultureInfo.InvariantCulture)},{Y.ToString(CultureInfo.InvariantCulture)},{W.ToString(CultureInfo.InvariantCulture)},{H.ToString(CultureInfo.InvariantCulture)}";
|
public override String ToString() => $"{this.X.ToString(CultureInfo.InvariantCulture)},{this.Y.ToString(CultureInfo.InvariantCulture)},{this.W.ToString(CultureInfo.InvariantCulture)},{this.H.ToString(CultureInfo.InvariantCulture)}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,340 +1,361 @@
|
|||||||
namespace Unosquare.RaspberryIO.Camera
|
using Unosquare.Swan;
|
||||||
{
|
using System.Globalization;
|
||||||
using Swan;
|
using System.Text;
|
||||||
using System.Globalization;
|
using System;
|
||||||
using System.Text;
|
|
||||||
|
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 {
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A base class to implement raspistill and raspivid wrappers
|
/// The Invariant Culture shorthand
|
||||||
/// Full documentation available at
|
|
||||||
/// https://www.raspberrypi.org/documentation/raspbian/applications/camera.md
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class CameraSettingsBase
|
protected static readonly CultureInfo Ci = CultureInfo.InvariantCulture;
|
||||||
{
|
|
||||||
/// <summary>
|
#region Capture Settings
|
||||||
/// The Invariant Culture shorthand
|
|
||||||
/// </summary>
|
/// <summary>
|
||||||
protected static readonly CultureInfo Ci = CultureInfo.InvariantCulture;
|
/// Gets or sets the timeout milliseconds.
|
||||||
|
/// Default value is 5000
|
||||||
#region Capture Settings
|
/// Recommended value is at least 300 in order to let the light collectors open
|
||||||
|
/// </summary>
|
||||||
/// <summary>
|
public Int32 CaptureTimeoutMilliseconds { get; set; } = 5000;
|
||||||
/// Gets or sets the timeout milliseconds.
|
|
||||||
/// Default value is 5000
|
/// <summary>
|
||||||
/// Recommended value is at least 300 in order to let the light collectors open
|
/// Gets or sets a value indicating whether or not to show a preview window on the screen
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int CaptureTimeoutMilliseconds { get; set; } = 5000;
|
public Boolean CaptureDisplayPreview { get; set; } = false;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets a value indicating whether or not to show a preview window on the screen
|
/// Gets or sets a value indicating whether a preview window is shown in full screen mode if enabled
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool CaptureDisplayPreview { get; set; } = false;
|
public Boolean CaptureDisplayPreviewInFullScreen { get; set; } = true;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets a value indicating whether a preview window is shown in full screen mode if enabled
|
/// Gets or sets a value indicating whether video stabilization should be enabled.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool CaptureDisplayPreviewInFullScreen { get; set; } = true;
|
public Boolean CaptureVideoStabilizationEnabled { get; set; } = false;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets a value indicating whether video stabilization should be enabled.
|
/// Gets or sets the display preview opacity only if the display preview property is enabled.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool CaptureVideoStabilizationEnabled { get; set; } = false;
|
public Byte CaptureDisplayPreviewOpacity { get; set; } = 255;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the display preview opacity only if the display preview property is enabled.
|
/// Gets or sets the capture sensor region of interest in relative coordinates.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public byte CaptureDisplayPreviewOpacity { get; set; } = 255;
|
public CameraRect CaptureSensorRoi { get; set; } = CameraRect.Default;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the capture sensor region of interest in relative coordinates.
|
/// Gets or sets the capture shutter speed in microseconds.
|
||||||
/// </summary>
|
/// Default -1, Range 0 to 6000000 (equivalent to 6 seconds)
|
||||||
public CameraRect CaptureSensorRoi { get; set; } = CameraRect.Default;
|
/// </summary>
|
||||||
|
public Int32 CaptureShutterSpeedMicroseconds { get; set; } = -1;
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the capture shutter speed in microseconds.
|
/// <summary>
|
||||||
/// Default -1, Range 0 to 6000000 (equivalent to 6 seconds)
|
/// Gets or sets the exposure mode.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int CaptureShutterSpeedMicroseconds { get; set; } = -1;
|
public CameraExposureMode CaptureExposure { get; set; } = CameraExposureMode.Auto;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the exposure mode.
|
/// Gets or sets the picture EV compensation. Default is 0, Range is -10 to 10
|
||||||
/// </summary>
|
/// Camera exposure compensation is commonly stated in terms of EV units;
|
||||||
public CameraExposureMode CaptureExposure { get; set; } = CameraExposureMode.Auto;
|
/// 1 EV is equal to one exposure step (or stop), corresponding to a doubling of exposure.
|
||||||
|
/// Exposure can be adjusted by changing either the lens f-number or the exposure time;
|
||||||
/// <summary>
|
/// which one is changed usually depends on the camera's exposure mode.
|
||||||
/// Gets or sets the picture EV compensation. Default is 0, Range is -10 to 10
|
/// </summary>
|
||||||
/// Camera exposure compensation is commonly stated in terms of EV units;
|
public Int32 CaptureExposureCompensation { get; set; } = 0;
|
||||||
/// 1 EV is equal to one exposure step (or stop), corresponding to a doubling of exposure.
|
|
||||||
/// Exposure can be adjusted by changing either the lens f-number or the exposure time;
|
/// <summary>
|
||||||
/// which one is changed usually depends on the camera's exposure mode.
|
/// Gets or sets the capture metering mode.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public int CaptureExposureCompensation { get; set; } = 0;
|
public CameraMeteringMode CaptureMeteringMode { get; set; } = CameraMeteringMode.Average;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the capture metering mode.
|
/// Gets or sets the automatic white balance mode. By default it is set to Auto
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public CameraMeteringMode CaptureMeteringMode { get; set; } = CameraMeteringMode.Average;
|
public CameraWhiteBalanceMode CaptureWhiteBalanceControl { get; set; } = CameraWhiteBalanceMode.Auto;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the automatic white balance mode. By default it is set to Auto
|
/// Gets or sets the capture white balance gain on the blue channel. Example: 1.25
|
||||||
/// </summary>
|
/// Only takes effect if White balance control is set to off.
|
||||||
public CameraWhiteBalanceMode CaptureWhiteBalanceControl { get; set; } = CameraWhiteBalanceMode.Auto;
|
/// Default is 0
|
||||||
|
/// </summary>
|
||||||
/// <summary>
|
public Decimal CaptureWhiteBalanceGainBlue { get; set; } = 0M;
|
||||||
/// Gets or sets the capture white balance gain on the blue channel. Example: 1.25
|
|
||||||
/// Only takes effect if White balance control is set to off.
|
/// <summary>
|
||||||
/// Default is 0
|
/// Gets or sets the capture white balance gain on the red channel. Example: 1.75
|
||||||
/// </summary>
|
/// Only takes effect if White balance control is set to off.
|
||||||
public decimal CaptureWhiteBalanceGainBlue { get; set; } = 0M;
|
/// Default is 0
|
||||||
|
/// </summary>
|
||||||
/// <summary>
|
public Decimal CaptureWhiteBalanceGainRed { get; set; } = 0M;
|
||||||
/// 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.
|
/// <summary>
|
||||||
/// Default is 0
|
/// Gets or sets the dynamic range compensation.
|
||||||
/// </summary>
|
/// 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.
|
||||||
public decimal CaptureWhiteBalanceGainRed { get; set; } = 0M;
|
/// </summary>
|
||||||
|
public CameraDynamicRangeCompensation CaptureDynamicRangeCompensation {
|
||||||
/// <summary>
|
get; set;
|
||||||
/// 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.
|
CameraDynamicRangeCompensation.Off;
|
||||||
/// </summary>
|
|
||||||
public CameraDynamicRangeCompensation CaptureDynamicRangeCompensation { get; set; } =
|
#endregion
|
||||||
CameraDynamicRangeCompensation.Off;
|
|
||||||
|
#region Image Properties
|
||||||
#endregion
|
|
||||||
|
/// <summary>
|
||||||
#region Image Properties
|
/// 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>
|
/// </summary>
|
||||||
/// Gets or sets the width of the picture to take.
|
public Int32 CaptureWidth { get; set; } = 640;
|
||||||
/// Less than or equal to 0 in either width or height means maximum resolution available.
|
|
||||||
/// </summary>
|
/// <summary>
|
||||||
public int CaptureWidth { get; set; } = 640;
|
/// 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>
|
/// </summary>
|
||||||
/// Gets or sets the height of the picture to take.
|
public Int32 CaptureHeight { get; set; } = 480;
|
||||||
/// Less than or equal to 0 in either width or height means maximum resolution available.
|
|
||||||
/// </summary>
|
/// <summary>
|
||||||
public int CaptureHeight { get; set; } = 480;
|
/// Gets or sets the picture sharpness. Default is 0, Range form -100 to 100
|
||||||
|
/// </summary>
|
||||||
/// <summary>
|
public Int32 ImageSharpness { get; set; } = 0;
|
||||||
/// Gets or sets the picture sharpness. Default is 0, Range form -100 to 100
|
|
||||||
/// </summary>
|
/// <summary>
|
||||||
public int ImageSharpness { get; set; } = 0;
|
/// Gets or sets the picture contrast. Default is 0, Range form -100 to 100
|
||||||
|
/// </summary>
|
||||||
/// <summary>
|
public Int32 ImageContrast { get; set; } = 0;
|
||||||
/// Gets or sets the picture contrast. Default is 0, Range form -100 to 100
|
|
||||||
/// </summary>
|
/// <summary>
|
||||||
public int ImageContrast { get; set; } = 0;
|
/// Gets or sets the picture brightness. Default is 50, Range form 0 to 100
|
||||||
|
/// </summary>
|
||||||
/// <summary>
|
public Int32 ImageBrightness { get; set; } = 50; // from 0 to 100
|
||||||
/// Gets or sets the picture brightness. Default is 50, Range form 0 to 100
|
|
||||||
/// </summary>
|
/// <summary>
|
||||||
public int ImageBrightness { get; set; } = 50; // from 0 to 100
|
/// Gets or sets the picture saturation. Default is 0, Range form -100 to 100
|
||||||
|
/// </summary>
|
||||||
/// <summary>
|
public Int32 ImageSaturation { get; set; } = 0;
|
||||||
/// Gets or sets the picture saturation. Default is 0, Range form -100 to 100
|
|
||||||
/// </summary>
|
/// <summary>
|
||||||
public int ImageSaturation { get; set; } = 0;
|
/// 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>
|
/// </summary>
|
||||||
/// Gets or sets the picture ISO. Default is -1 Range is 100 to 800
|
public Int32 ImageIso { get; set; } = -1;
|
||||||
/// The higher the value, the more light the sensor absorbs
|
|
||||||
/// </summary>
|
/// <summary>
|
||||||
public int ImageIso { get; set; } = -1;
|
/// Gets or sets the image capture effect to be applied.
|
||||||
|
/// </summary>
|
||||||
/// <summary>
|
public CameraImageEffect ImageEffect { get; set; } = CameraImageEffect.None;
|
||||||
/// Gets or sets the image capture effect to be applied.
|
|
||||||
/// </summary>
|
/// <summary>
|
||||||
public CameraImageEffect ImageEffect { get; set; } = CameraImageEffect.None;
|
/// Gets or sets the color effect U coordinates.
|
||||||
|
/// Default is -1, Range is 0 to 255
|
||||||
/// <summary>
|
/// 128:128 should be effectively a monochrome image.
|
||||||
/// Gets or sets the color effect U coordinates.
|
/// </summary>
|
||||||
/// Default is -1, Range is 0 to 255
|
public Int32 ImageColorEffectU { get; set; } = -1; // 0 to 255
|
||||||
/// 128:128 should be effectively a monochrome image.
|
|
||||||
/// </summary>
|
/// <summary>
|
||||||
public int ImageColorEffectU { get; set; } = -1; // 0 to 255
|
/// Gets or sets the color effect V coordinates.
|
||||||
|
/// Default is -1, Range is 0 to 255
|
||||||
/// <summary>
|
/// 128:128 should be effectively a monochrome image.
|
||||||
/// Gets or sets the color effect V coordinates.
|
/// </summary>
|
||||||
/// Default is -1, Range is 0 to 255
|
public Int32 ImageColorEffectV { get; set; } = -1; // 0 to 255
|
||||||
/// 128:128 should be effectively a monochrome image.
|
|
||||||
/// </summary>
|
/// <summary>
|
||||||
public int ImageColorEffectV { get; set; } = -1; // 0 to 255
|
/// Gets or sets the image rotation. Default is no rotation
|
||||||
|
/// </summary>
|
||||||
/// <summary>
|
public CameraImageRotation ImageRotation { get; set; } = CameraImageRotation.None;
|
||||||
/// Gets or sets the image rotation. Default is no rotation
|
|
||||||
/// </summary>
|
/// <summary>
|
||||||
public CameraImageRotation ImageRotation { get; set; } = CameraImageRotation.None;
|
/// Gets or sets a value indicating whether the image should be flipped horizontally.
|
||||||
|
/// </summary>
|
||||||
/// <summary>
|
public Boolean ImageFlipHorizontally {
|
||||||
/// Gets or sets a value indicating whether the image should be flipped horizontally.
|
get; set;
|
||||||
/// </summary>
|
}
|
||||||
public bool ImageFlipHorizontally { get; set; }
|
|
||||||
|
/// <summary>
|
||||||
/// <summary>
|
/// Gets or sets a value indicating whether the image should be flipped vertically.
|
||||||
/// Gets or sets a value indicating whether the image should be flipped vertically.
|
/// </summary>
|
||||||
/// </summary>
|
public Boolean ImageFlipVertically {
|
||||||
public bool ImageFlipVertically { get; set; }
|
get; set;
|
||||||
|
}
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the image annotations using a bitmask (or flags) notation.
|
/// <summary>
|
||||||
/// Apply a bitwise OR to the enumeration to include multiple annotations
|
/// Gets or sets the image annotations using a bitmask (or flags) notation.
|
||||||
/// </summary>
|
/// Apply a bitwise OR to the enumeration to include multiple annotations
|
||||||
public CameraAnnotation ImageAnnotations { get; set; } = CameraAnnotation.None;
|
/// </summary>
|
||||||
|
public CameraAnnotation ImageAnnotations { get; set; } = CameraAnnotation.None;
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the image annotations text.
|
/// <summary>
|
||||||
/// Text may include date/time placeholders by using the '%' character, as used by strftime.
|
/// Gets or sets the image annotations text.
|
||||||
/// Example: ABC %Y-%m-%d %X will output ABC 2015-10-28 20:09:33
|
/// Text may include date/time placeholders by using the '%' character, as used by strftime.
|
||||||
/// </summary>
|
/// Example: ABC %Y-%m-%d %X will output ABC 2015-10-28 20:09:33
|
||||||
public string ImageAnnotationsText { get; set; } = string.Empty;
|
/// </summary>
|
||||||
|
public String ImageAnnotationsText { get; set; } = String.Empty;
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the font size of the text annotations
|
/// <summary>
|
||||||
/// Default is -1, range is 6 to 160
|
/// Gets or sets the font size of the text annotations
|
||||||
/// </summary>
|
/// Default is -1, range is 6 to 160
|
||||||
public int ImageAnnotationFontSize { get; set; } = -1;
|
/// </summary>
|
||||||
|
public Int32 ImageAnnotationFontSize { get; set; } = -1;
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the color of the text annotations.
|
/// <summary>
|
||||||
/// </summary>
|
/// Gets or sets the color of the text annotations.
|
||||||
/// <value>
|
/// </summary>
|
||||||
/// The color of the image annotation font.
|
/// <value>
|
||||||
/// </value>
|
/// The color of the image annotation font.
|
||||||
public CameraColor ImageAnnotationFontColor { get; set; } = null;
|
/// </value>
|
||||||
|
public CameraColor ImageAnnotationFontColor { get; set; } = null;
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the background color for text annotations.
|
/// <summary>
|
||||||
/// </summary>
|
/// Gets or sets the background color for text annotations.
|
||||||
/// <value>
|
/// </summary>
|
||||||
/// The image annotation background.
|
/// <value>
|
||||||
/// </value>
|
/// The image annotation background.
|
||||||
public CameraColor ImageAnnotationBackground { get; set; } = null;
|
/// </value>
|
||||||
|
public CameraColor ImageAnnotationBackground { get; set; } = null;
|
||||||
#endregion
|
|
||||||
|
#endregion
|
||||||
#region Interface
|
|
||||||
|
#region Interface
|
||||||
/// <summary>
|
|
||||||
/// Gets the command file executable.
|
/// <summary>
|
||||||
/// </summary>
|
/// Gets the command file executable.
|
||||||
public abstract string CommandName { get; }
|
/// </summary>
|
||||||
|
public abstract String CommandName {
|
||||||
/// <summary>
|
get;
|
||||||
/// Creates the process arguments.
|
}
|
||||||
/// </summary>
|
|
||||||
/// <returns>The string that represents the process arguments</returns>
|
/// <summary>
|
||||||
public virtual string CreateProcessArguments()
|
/// Creates the process arguments.
|
||||||
{
|
/// </summary>
|
||||||
var sb = new StringBuilder();
|
/// <returns>The string that represents the process arguments</returns>
|
||||||
sb.Append("-o -"); // output to standard output as opposed to a file.
|
public virtual String CreateProcessArguments() {
|
||||||
sb.Append($" -t {(CaptureTimeoutMilliseconds < 0 ? "0" : CaptureTimeoutMilliseconds.ToString(Ci))}");
|
StringBuilder sb = new StringBuilder();
|
||||||
|
_ = sb.Append("-o -"); // output to standard output as opposed to a file.
|
||||||
// Basic Width and height
|
_ = sb.Append($" -t {(this.CaptureTimeoutMilliseconds < 0 ? "0" : this.CaptureTimeoutMilliseconds.ToString(Ci))}");
|
||||||
if (CaptureWidth > 0 && CaptureHeight > 0)
|
|
||||||
{
|
// Basic Width and height
|
||||||
sb.Append($" -w {CaptureWidth.ToString(Ci)}");
|
if(this.CaptureWidth > 0 && this.CaptureHeight > 0) {
|
||||||
sb.Append($" -h {CaptureHeight.ToString(Ci)}");
|
_ = sb.Append($" -w {this.CaptureWidth.ToString(Ci)}");
|
||||||
}
|
_ = sb.Append($" -h {this.CaptureHeight.ToString(Ci)}");
|
||||||
|
}
|
||||||
// Display Preview
|
|
||||||
if (CaptureDisplayPreview)
|
// Display Preview
|
||||||
{
|
if(this.CaptureDisplayPreview) {
|
||||||
if (CaptureDisplayPreviewInFullScreen)
|
if(this.CaptureDisplayPreviewInFullScreen) {
|
||||||
sb.Append(" -f");
|
_ = sb.Append(" -f");
|
||||||
|
}
|
||||||
if (CaptureDisplayPreviewOpacity != byte.MaxValue)
|
|
||||||
sb.Append($" -op {CaptureDisplayPreviewOpacity.ToString(Ci)}");
|
if(this.CaptureDisplayPreviewOpacity != Byte.MaxValue) {
|
||||||
}
|
_ = sb.Append($" -op {this.CaptureDisplayPreviewOpacity.ToString(Ci)}");
|
||||||
else
|
}
|
||||||
{
|
} else {
|
||||||
sb.Append(" -n"); // no preview
|
_ = sb.Append(" -n"); // no preview
|
||||||
}
|
}
|
||||||
|
|
||||||
// Picture Settings
|
// Picture Settings
|
||||||
if (ImageSharpness != 0)
|
if(this.ImageSharpness != 0) {
|
||||||
sb.Append($" -sh {ImageSharpness.Clamp(-100, 100).ToString(Ci)}");
|
_ = sb.Append($" -sh {this.ImageSharpness.Clamp(-100, 100).ToString(Ci)}");
|
||||||
|
}
|
||||||
if (ImageContrast != 0)
|
|
||||||
sb.Append($" -co {ImageContrast.Clamp(-100, 100).ToString(Ci)}");
|
if(this.ImageContrast != 0) {
|
||||||
|
_ = sb.Append($" -co {this.ImageContrast.Clamp(-100, 100).ToString(Ci)}");
|
||||||
if (ImageBrightness != 50)
|
}
|
||||||
sb.Append($" -br {ImageBrightness.Clamp(0, 100).ToString(Ci)}");
|
|
||||||
|
if(this.ImageBrightness != 50) {
|
||||||
if (ImageSaturation != 0)
|
_ = sb.Append($" -br {this.ImageBrightness.Clamp(0, 100).ToString(Ci)}");
|
||||||
sb.Append($" -sa {ImageSaturation.Clamp(-100, 100).ToString(Ci)}");
|
}
|
||||||
|
|
||||||
if (ImageIso >= 100)
|
if(this.ImageSaturation != 0) {
|
||||||
sb.Append($" -ISO {ImageIso.Clamp(100, 800).ToString(Ci)}");
|
_ = sb.Append($" -sa {this.ImageSaturation.Clamp(-100, 100).ToString(Ci)}");
|
||||||
|
}
|
||||||
if (CaptureVideoStabilizationEnabled)
|
|
||||||
sb.Append(" -vs");
|
if(this.ImageIso >= 100) {
|
||||||
|
_ = sb.Append($" -ISO {this.ImageIso.Clamp(100, 800).ToString(Ci)}");
|
||||||
if (CaptureExposureCompensation != 0)
|
}
|
||||||
sb.Append($" -ev {CaptureExposureCompensation.Clamp(-10, 10).ToString(Ci)}");
|
|
||||||
|
if(this.CaptureVideoStabilizationEnabled) {
|
||||||
if (CaptureExposure != CameraExposureMode.Auto)
|
_ = sb.Append(" -vs");
|
||||||
sb.Append($" -ex {CaptureExposure.ToString().ToLowerInvariant()}");
|
}
|
||||||
|
|
||||||
if (CaptureWhiteBalanceControl != CameraWhiteBalanceMode.Auto)
|
if(this.CaptureExposureCompensation != 0) {
|
||||||
sb.Append($" -awb {CaptureWhiteBalanceControl.ToString().ToLowerInvariant()}");
|
_ = sb.Append($" -ev {this.CaptureExposureCompensation.Clamp(-10, 10).ToString(Ci)}");
|
||||||
|
}
|
||||||
if (ImageEffect != CameraImageEffect.None)
|
|
||||||
sb.Append($" -ifx {ImageEffect.ToString().ToLowerInvariant()}");
|
if(this.CaptureExposure != CameraExposureMode.Auto) {
|
||||||
|
_ = sb.Append($" -ex {this.CaptureExposure.ToString().ToLowerInvariant()}");
|
||||||
if (ImageColorEffectU >= 0 && ImageColorEffectV >= 0)
|
}
|
||||||
{
|
|
||||||
sb.Append(
|
if(this.CaptureWhiteBalanceControl != CameraWhiteBalanceMode.Auto) {
|
||||||
$" -cfx {ImageColorEffectU.Clamp(0, 255).ToString(Ci)}:{ImageColorEffectV.Clamp(0, 255).ToString(Ci)}");
|
_ = sb.Append($" -awb {this.CaptureWhiteBalanceControl.ToString().ToLowerInvariant()}");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CaptureMeteringMode != CameraMeteringMode.Average)
|
if(this.ImageEffect != CameraImageEffect.None) {
|
||||||
sb.Append($" -mm {CaptureMeteringMode.ToString().ToLowerInvariant()}");
|
_ = sb.Append($" -ifx {this.ImageEffect.ToString().ToLowerInvariant()}");
|
||||||
|
}
|
||||||
if (ImageRotation != CameraImageRotation.None)
|
|
||||||
sb.Append($" -rot {((int)ImageRotation).ToString(Ci)}");
|
if(this.ImageColorEffectU >= 0 && this.ImageColorEffectV >= 0) {
|
||||||
|
_ = sb.Append(
|
||||||
if (ImageFlipHorizontally)
|
$" -cfx {this.ImageColorEffectU.Clamp(0, 255).ToString(Ci)}:{this.ImageColorEffectV.Clamp(0, 255).ToString(Ci)}");
|
||||||
sb.Append(" -hf");
|
}
|
||||||
|
|
||||||
if (ImageFlipVertically)
|
if(this.CaptureMeteringMode != CameraMeteringMode.Average) {
|
||||||
sb.Append(" -vf");
|
_ = sb.Append($" -mm {this.CaptureMeteringMode.ToString().ToLowerInvariant()}");
|
||||||
|
}
|
||||||
if (CaptureSensorRoi.IsDefault == false)
|
|
||||||
sb.Append($" -roi {CaptureSensorRoi}");
|
if(this.ImageRotation != CameraImageRotation.None) {
|
||||||
|
_ = sb.Append($" -rot {((Int32)this.ImageRotation).ToString(Ci)}");
|
||||||
if (CaptureShutterSpeedMicroseconds > 0)
|
}
|
||||||
sb.Append($" -ss {CaptureShutterSpeedMicroseconds.Clamp(0, 6000000).ToString(Ci)}");
|
|
||||||
|
if(this.ImageFlipHorizontally) {
|
||||||
if (CaptureDynamicRangeCompensation != CameraDynamicRangeCompensation.Off)
|
_ = sb.Append(" -hf");
|
||||||
sb.Append($" -drc {CaptureDynamicRangeCompensation.ToString().ToLowerInvariant()}");
|
}
|
||||||
|
|
||||||
if (CaptureWhiteBalanceControl == CameraWhiteBalanceMode.Off &&
|
if(this.ImageFlipVertically) {
|
||||||
(CaptureWhiteBalanceGainBlue != 0M || CaptureWhiteBalanceGainRed != 0M))
|
_ = sb.Append(" -vf");
|
||||||
sb.Append($" -awbg {CaptureWhiteBalanceGainBlue.ToString(Ci)},{CaptureWhiteBalanceGainRed.ToString(Ci)}");
|
}
|
||||||
|
|
||||||
if (ImageAnnotationFontSize > 0)
|
if(this.CaptureSensorRoi.IsDefault == false) {
|
||||||
{
|
_ = sb.Append($" -roi {this.CaptureSensorRoi}");
|
||||||
sb.Append($" -ae {ImageAnnotationFontSize.Clamp(6, 160).ToString(Ci)}");
|
}
|
||||||
sb.Append($",{(ImageAnnotationFontColor == null ? "0xff" : ImageAnnotationFontColor.ToYuvHex(true))}");
|
|
||||||
|
if(this.CaptureShutterSpeedMicroseconds > 0) {
|
||||||
if (ImageAnnotationBackground != null)
|
_ = sb.Append($" -ss {this.CaptureShutterSpeedMicroseconds.Clamp(0, 6000000).ToString(Ci)}");
|
||||||
{
|
}
|
||||||
ImageAnnotations |= CameraAnnotation.SolidBackground;
|
|
||||||
sb.Append($",{ImageAnnotationBackground.ToYuvHex(true)}");
|
if(this.CaptureDynamicRangeCompensation != CameraDynamicRangeCompensation.Off) {
|
||||||
}
|
_ = sb.Append($" -drc {this.CaptureDynamicRangeCompensation.ToString().ToLowerInvariant()}");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ImageAnnotations != CameraAnnotation.None)
|
if(this.CaptureWhiteBalanceControl == CameraWhiteBalanceMode.Off &&
|
||||||
sb.Append($" -a {((int)ImageAnnotations).ToString(Ci)}");
|
(this.CaptureWhiteBalanceGainBlue != 0M || this.CaptureWhiteBalanceGainRed != 0M)) {
|
||||||
|
_ = sb.Append($" -awbg {this.CaptureWhiteBalanceGainBlue.ToString(Ci)},{this.CaptureWhiteBalanceGainRed.ToString(Ci)}");
|
||||||
if (string.IsNullOrWhiteSpace(ImageAnnotationsText) == false)
|
}
|
||||||
sb.Append($" -a \"{ImageAnnotationsText.Replace("\"", "'")}\"");
|
|
||||||
|
if(this.ImageAnnotationFontSize > 0) {
|
||||||
return sb.ToString();
|
_ = sb.Append($" -ae {this.ImageAnnotationFontSize.Clamp(6, 160).ToString(Ci)}");
|
||||||
}
|
_ = sb.Append($",{(this.ImageAnnotationFontColor == null ? "0xff" : this.ImageAnnotationFontColor.ToYuvHex(true))}");
|
||||||
|
|
||||||
#endregion
|
if(this.ImageAnnotationBackground != null) {
|
||||||
}
|
this.ImageAnnotations |= CameraAnnotation.SolidBackground;
|
||||||
|
_ = sb.Append($",{this.ImageAnnotationBackground.ToYuvHex(true)}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(this.ImageAnnotations != CameraAnnotation.None) {
|
||||||
|
_ = sb.Append($" -a {((Int32)this.ImageAnnotations).ToString(Ci)}");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(String.IsNullOrWhiteSpace(this.ImageAnnotationsText) == false) {
|
||||||
|
_ = sb.Append($" -a \"{this.ImageAnnotationsText.Replace("\"", "'")}\"");
|
||||||
|
}
|
||||||
|
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,120 +1,121 @@
|
|||||||
namespace Unosquare.RaspberryIO.Camera
|
using Unosquare.Swan;
|
||||||
{
|
using System;
|
||||||
using Swan;
|
using System.Collections.Generic;
|
||||||
using System;
|
using System.Text;
|
||||||
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 Int32 _rotate;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override String CommandName => "raspistill";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Defines a wrapper for the raspistill program and its settings (command-line arguments)
|
/// Gets or sets a value indicating whether the preview window (if enabled) uses native capture resolution
|
||||||
|
/// This may slow down preview FPS
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <seealso cref="CameraSettingsBase" />
|
public Boolean CaptureDisplayPreviewAtResolution { get; set; } = false;
|
||||||
public class CameraStillSettings : CameraSettingsBase
|
|
||||||
{
|
/// <summary>
|
||||||
private int _rotate;
|
/// Gets or sets the encoding format the hardware will use for the output.
|
||||||
|
/// </summary>
|
||||||
/// <inheritdoc />
|
public CameraImageEncodingFormat CaptureEncoding { get; set; } = CameraImageEncodingFormat.Jpg;
|
||||||
public override string CommandName => "raspistill";
|
|
||||||
|
/// <summary>
|
||||||
/// <summary>
|
/// Gets or sets the quality for JPEG only encoding mode.
|
||||||
/// Gets or sets a value indicating whether the preview window (if enabled) uses native capture resolution
|
/// Value ranges from 0 to 100
|
||||||
/// This may slow down preview FPS
|
/// </summary>
|
||||||
/// </summary>
|
public Int32 CaptureJpegQuality { get; set; } = 90;
|
||||||
public bool CaptureDisplayPreviewAtResolution { get; set; } = false;
|
|
||||||
|
/// <summary>
|
||||||
/// <summary>
|
/// Gets or sets a value indicating whether the JPEG encoder should add raw bayer metadata.
|
||||||
/// Gets or sets the encoding format the hardware will use for the output.
|
/// </summary>
|
||||||
/// </summary>
|
public Boolean CaptureJpegIncludeRawBayerMetadata { get; set; } = false;
|
||||||
public CameraImageEncodingFormat CaptureEncoding { get; set; } = CameraImageEncodingFormat.Jpg;
|
|
||||||
|
/// <summary>
|
||||||
/// <summary>
|
/// JPEG EXIF data
|
||||||
/// Gets or sets the quality for JPEG only encoding mode.
|
/// Keys and values must be already properly escaped. Otherwise the command will fail.
|
||||||
/// Value ranges from 0 to 100
|
/// </summary>
|
||||||
/// </summary>
|
public Dictionary<String, String> CaptureJpegExtendedInfo { get; } = new Dictionary<String, String>();
|
||||||
public int CaptureJpegQuality { get; set; } = 90;
|
|
||||||
|
/// <summary>
|
||||||
/// <summary>
|
/// Gets or sets a value indicating whether [horizontal flip].
|
||||||
/// Gets or sets a value indicating whether the JPEG encoder should add raw bayer metadata.
|
/// </summary>
|
||||||
/// </summary>
|
/// <value>
|
||||||
public bool CaptureJpegIncludeRawBayerMetadata { get; set; } = false;
|
/// <c>true</c> if [horizontal flip]; otherwise, <c>false</c>.
|
||||||
|
/// </value>
|
||||||
/// <summary>
|
public Boolean HorizontalFlip { get; set; } = false;
|
||||||
/// JPEG EXIF data
|
|
||||||
/// Keys and values must be already properly escaped. Otherwise the command will fail.
|
/// <summary>
|
||||||
/// </summary>
|
/// Gets or sets a value indicating whether [vertical flip].
|
||||||
public Dictionary<string, string> CaptureJpegExtendedInfo { get; } = new Dictionary<string, string>();
|
/// </summary>
|
||||||
|
/// <value>
|
||||||
/// <summary>
|
/// <c>true</c> if [vertical flip]; otherwise, <c>false</c>.
|
||||||
/// Gets or sets a value indicating whether [horizontal flip].
|
/// </value>
|
||||||
/// </summary>
|
public Boolean VerticalFlip { get; set; } = false;
|
||||||
/// <value>
|
|
||||||
/// <c>true</c> if [horizontal flip]; otherwise, <c>false</c>.
|
/// <summary>
|
||||||
/// </value>
|
/// Gets or sets the rotation.
|
||||||
public bool HorizontalFlip { get; set; } = false;
|
/// </summary>
|
||||||
|
/// <exception cref="ArgumentOutOfRangeException">Valid range 0-359</exception>
|
||||||
/// <summary>
|
public Int32 Rotation {
|
||||||
/// Gets or sets a value indicating whether [vertical flip].
|
get => this._rotate;
|
||||||
/// </summary>
|
set {
|
||||||
/// <value>
|
if(value < 0 || value > 359) {
|
||||||
/// <c>true</c> if [vertical flip]; otherwise, <c>false</c>.
|
throw new ArgumentOutOfRangeException(nameof(value), "Valid range 0-359");
|
||||||
/// </value>
|
}
|
||||||
public bool VerticalFlip { get; set; } = false;
|
|
||||||
|
this._rotate = value;
|
||||||
/// <summary>
|
}
|
||||||
/// Gets or sets the rotation.
|
}
|
||||||
/// </summary>
|
|
||||||
/// <exception cref="ArgumentOutOfRangeException">Valid range 0-359</exception>
|
/// <inheritdoc />
|
||||||
public int Rotation
|
public override String CreateProcessArguments() {
|
||||||
{
|
StringBuilder sb = new StringBuilder(base.CreateProcessArguments());
|
||||||
get => _rotate;
|
_ = sb.Append($" -e {this.CaptureEncoding.ToString().ToLowerInvariant()}");
|
||||||
set
|
|
||||||
{
|
// JPEG Encoder specific arguments
|
||||||
if (value < 0 || value > 359)
|
if(this.CaptureEncoding == CameraImageEncodingFormat.Jpg) {
|
||||||
{
|
_ = sb.Append($" -q {this.CaptureJpegQuality.Clamp(0, 100).ToString(Ci)}");
|
||||||
throw new ArgumentOutOfRangeException(nameof(value), "Valid range 0-359");
|
|
||||||
}
|
if(this.CaptureJpegIncludeRawBayerMetadata) {
|
||||||
|
_ = sb.Append(" -r");
|
||||||
_rotate = value;
|
}
|
||||||
}
|
|
||||||
}
|
// JPEG EXIF data
|
||||||
|
if(this.CaptureJpegExtendedInfo.Count > 0) {
|
||||||
/// <inheritdoc />
|
foreach(KeyValuePair<String, String> kvp in this.CaptureJpegExtendedInfo) {
|
||||||
public override string CreateProcessArguments()
|
if(String.IsNullOrWhiteSpace(kvp.Key) || String.IsNullOrWhiteSpace(kvp.Value)) {
|
||||||
{
|
continue;
|
||||||
var sb = new StringBuilder(base.CreateProcessArguments());
|
}
|
||||||
sb.Append($" -e {CaptureEncoding.ToString().ToLowerInvariant()}");
|
|
||||||
|
_ = sb.Append($" -x \"{kvp.Key.Replace("\"", "'")}={kvp.Value.Replace("\"", "'")}\"");
|
||||||
// JPEG Encoder specific arguments
|
}
|
||||||
if (CaptureEncoding == CameraImageEncodingFormat.Jpg)
|
}
|
||||||
{
|
}
|
||||||
sb.Append($" -q {CaptureJpegQuality.Clamp(0, 100).ToString(Ci)}");
|
|
||||||
|
// Display preview settings
|
||||||
if (CaptureJpegIncludeRawBayerMetadata)
|
if(this.CaptureDisplayPreview && this.CaptureDisplayPreviewAtResolution) {
|
||||||
sb.Append(" -r");
|
_ = sb.Append(" -fp");
|
||||||
|
}
|
||||||
// JPEG EXIF data
|
|
||||||
if (CaptureJpegExtendedInfo.Count > 0)
|
if(this.Rotation != 0) {
|
||||||
{
|
_ = sb.Append($" -rot {this.Rotation}");
|
||||||
foreach (var kvp in CaptureJpegExtendedInfo)
|
}
|
||||||
{
|
|
||||||
if (string.IsNullOrWhiteSpace(kvp.Key) || string.IsNullOrWhiteSpace(kvp.Value))
|
if(this.HorizontalFlip) {
|
||||||
continue;
|
_ = sb.Append(" -hf");
|
||||||
|
}
|
||||||
sb.Append($" -x \"{kvp.Key.Replace("\"", "'")}={kvp.Value.Replace("\"", "'")}\"");
|
|
||||||
}
|
if(this.VerticalFlip) {
|
||||||
}
|
_ = sb.Append(" -vf");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Display preview settings
|
return sb.ToString();
|
||||||
if (CaptureDisplayPreview && CaptureDisplayPreviewAtResolution) sb.Append(" -fp");
|
}
|
||||||
|
}
|
||||||
if (Rotation != 0) sb.Append($" -rot {Rotation}");
|
|
||||||
|
|
||||||
if (HorizontalFlip) sb.Append(" -hf");
|
|
||||||
|
|
||||||
if (VerticalFlip) sb.Append(" -vf");
|
|
||||||
|
|
||||||
return sb.ToString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -1,94 +1,98 @@
|
|||||||
namespace Unosquare.RaspberryIO.Camera
|
using Unosquare.Swan;
|
||||||
{
|
using System;
|
||||||
using Swan;
|
using System.Text;
|
||||||
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 {
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override String CommandName => "raspivid";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents the raspivid camera settings for video capture functionality
|
/// 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>
|
/// </summary>
|
||||||
/// <seealso cref="CameraSettingsBase" />
|
public Int32 CaptureBitrate { get; set; } = -1;
|
||||||
public class CameraVideoSettings : CameraSettingsBase
|
|
||||||
{
|
/// <summary>
|
||||||
/// <inheritdoc />
|
/// Gets or sets the framerate.
|
||||||
public override string CommandName => "raspivid";
|
/// Default 25, range 2 to 30
|
||||||
|
/// </summary>
|
||||||
/// <summary>
|
public Int32 CaptureFramerate { get; set; } = 25;
|
||||||
/// 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.
|
/// <summary>
|
||||||
/// Default -1
|
/// Sets the intra refresh period (GoP) rate for the recorded video. H264 video uses a complete frame (I-frame) every intra
|
||||||
/// </summary>
|
/// refresh period, from which subsequent frames are based. This option specifies the number of frames between each I-frame.
|
||||||
public int CaptureBitrate { get; set; } = -1;
|
/// Larger numbers here will reduce the size of the resulting video, and smaller numbers make the stream less error-prone.
|
||||||
|
/// </summary>
|
||||||
/// <summary>
|
public Int32 CaptureKeyframeRate { get; set; } = 25;
|
||||||
/// Gets or sets the framerate.
|
|
||||||
/// Default 25, range 2 to 30
|
/// <summary>
|
||||||
/// </summary>
|
/// Sets the initial quantisation parameter for the stream. Varies from approximately 10 to 40, and will greatly affect
|
||||||
public int CaptureFramerate { get; set; } = 25;
|
/// 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>
|
/// </summary>
|
||||||
/// Sets the intra refresh period (GoP) rate for the recorded video. H264 video uses a complete frame (I-frame) every intra
|
public Int32 CaptureQuantisation { get; set; } = 23;
|
||||||
/// 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>
|
||||||
/// </summary>
|
/// Gets or sets the profile.
|
||||||
public int CaptureKeyframeRate { get; set; } = 25;
|
/// Sets the H264 profile to be used for the encoding.
|
||||||
|
/// Default is Main mode
|
||||||
/// <summary>
|
/// </summary>
|
||||||
/// Sets the initial quantisation parameter for the stream. Varies from approximately 10 to 40, and will greatly affect
|
public CameraH264Profile CaptureProfile { get; set; } = CameraH264Profile.Main;
|
||||||
/// 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>
|
||||||
/// </summary>
|
/// Forces the stream to include PPS and SPS headers on every I-frame. Needed for certain streaming cases
|
||||||
public int CaptureQuantisation { get; set; } = 23;
|
/// e.g. Apple HLS. These headers are small, so don't greatly increase the file size.
|
||||||
|
/// </summary>
|
||||||
/// <summary>
|
/// <value>
|
||||||
/// Gets or sets the profile.
|
/// <c>true</c> if [interleave headers]; otherwise, <c>false</c>.
|
||||||
/// Sets the H264 profile to be used for the encoding.
|
/// </value>
|
||||||
/// Default is Main mode
|
public Boolean CaptureInterleaveHeaders { get; set; } = true;
|
||||||
/// </summary>
|
|
||||||
public CameraH264Profile CaptureProfile { get; set; } = CameraH264Profile.Main;
|
/// <summary>
|
||||||
|
/// Switch on an option to display the preview after compression. This will show any compression artefacts in the preview window. In normal operation,
|
||||||
/// <summary>
|
/// the preview will show the camera output prior to being compressed. This option is not guaranteed to work in future releases.
|
||||||
/// Forces the stream to include PPS and SPS headers on every I-frame. Needed for certain streaming cases
|
/// </summary>
|
||||||
/// e.g. Apple HLS. These headers are small, so don't greatly increase the file size.
|
/// <value>
|
||||||
/// </summary>
|
/// <c>true</c> if [capture display preview encoded]; otherwise, <c>false</c>.
|
||||||
/// <value>
|
/// </value>
|
||||||
/// <c>true</c> if [interleave headers]; otherwise, <c>false</c>.
|
public Boolean CaptureDisplayPreviewEncoded { get; set; } = false;
|
||||||
/// </value>
|
|
||||||
public bool CaptureInterleaveHeaders { get; set; } = true;
|
/// <inheritdoc />
|
||||||
|
public override String CreateProcessArguments() {
|
||||||
/// <summary>
|
StringBuilder sb = new StringBuilder(base.CreateProcessArguments());
|
||||||
/// Switch on an option to display the preview after compression. This will show any compression artefacts in the preview window. In normal operation,
|
|
||||||
/// the preview will show the camera output prior to being compressed. This option is not guaranteed to work in future releases.
|
_ = sb.Append($" -pf {this.CaptureProfile.ToString().ToLowerInvariant()}");
|
||||||
/// </summary>
|
if(this.CaptureBitrate < 0) {
|
||||||
/// <value>
|
_ = sb.Append($" -b {this.CaptureBitrate.Clamp(0, 25000000).ToString(Ci)}");
|
||||||
/// <c>true</c> if [capture display preview encoded]; otherwise, <c>false</c>.
|
}
|
||||||
/// </value>
|
|
||||||
public bool CaptureDisplayPreviewEncoded { get; set; } = false;
|
if(this.CaptureFramerate >= 2) {
|
||||||
|
_ = sb.Append($" -fps {this.CaptureFramerate.Clamp(2, 30).ToString(Ci)}");
|
||||||
/// <inheritdoc />
|
}
|
||||||
public override string CreateProcessArguments()
|
|
||||||
{
|
if(this.CaptureDisplayPreview && this.CaptureDisplayPreviewEncoded) {
|
||||||
var sb = new StringBuilder(base.CreateProcessArguments());
|
_ = sb.Append(" -e");
|
||||||
|
}
|
||||||
sb.Append($" -pf {CaptureProfile.ToString().ToLowerInvariant()}");
|
|
||||||
if (CaptureBitrate < 0)
|
if(this.CaptureKeyframeRate > 0) {
|
||||||
sb.Append($" -b {CaptureBitrate.Clamp(0, 25000000).ToString(Ci)}");
|
_ = sb.Append($" -g {this.CaptureKeyframeRate.ToString(Ci)}");
|
||||||
|
}
|
||||||
if (CaptureFramerate >= 2)
|
|
||||||
sb.Append($" -fps {CaptureFramerate.Clamp(2, 30).ToString(Ci)}");
|
if(this.CaptureQuantisation >= 0) {
|
||||||
|
_ = sb.Append($" -qp {this.CaptureQuantisation.Clamp(0, 40).ToString(Ci)}");
|
||||||
if (CaptureDisplayPreview && CaptureDisplayPreviewEncoded)
|
}
|
||||||
sb.Append(" -e");
|
|
||||||
|
if(this.CaptureInterleaveHeaders) {
|
||||||
if (CaptureKeyframeRate > 0)
|
_ = sb.Append(" -ih");
|
||||||
sb.Append($" -g {CaptureKeyframeRate.ToString(Ci)}");
|
}
|
||||||
|
|
||||||
if (CaptureQuantisation >= 0)
|
return sb.ToString();
|
||||||
sb.Append($" -qp {CaptureQuantisation.Clamp(0, 40).ToString(Ci)}");
|
}
|
||||||
|
}
|
||||||
if (CaptureInterleaveHeaders)
|
|
||||||
sb.Append(" -ih");
|
|
||||||
|
|
||||||
return sb.ToString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -1,423 +1,413 @@
|
|||||||
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 {
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Defines the available encoding formats for the Raspberry Pi camera module
|
/// The JPG
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public enum CameraImageEncodingFormat
|
Jpg,
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The JPG
|
|
||||||
/// </summary>
|
|
||||||
Jpg,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The BMP
|
|
||||||
/// </summary>
|
|
||||||
Bmp,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The GIF
|
|
||||||
/// </summary>
|
|
||||||
Gif,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The PNG
|
|
||||||
/// </summary>
|
|
||||||
Png,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Defines the different exposure modes for the Raspberry Pi's camera module
|
/// The BMP
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public enum CameraExposureMode
|
Bmp,
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The automatic
|
|
||||||
/// </summary>
|
|
||||||
Auto,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The night
|
|
||||||
/// </summary>
|
|
||||||
Night,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The night preview
|
|
||||||
/// </summary>
|
|
||||||
NightPreview,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The backlight
|
|
||||||
/// </summary>
|
|
||||||
Backlight,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The spotlight
|
|
||||||
/// </summary>
|
|
||||||
Spotlight,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The sports
|
|
||||||
/// </summary>
|
|
||||||
Sports,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The snow
|
|
||||||
/// </summary>
|
|
||||||
Snow,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The beach
|
|
||||||
/// </summary>
|
|
||||||
Beach,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The very long
|
|
||||||
/// </summary>
|
|
||||||
VeryLong,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The fixed FPS
|
|
||||||
/// </summary>
|
|
||||||
FixedFps,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The anti shake
|
|
||||||
/// </summary>
|
|
||||||
AntiShake,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The fireworks
|
|
||||||
/// </summary>
|
|
||||||
Fireworks
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Defines the different AWB (Auto White Balance) modes for the Raspberry Pi's camera module
|
/// The GIF
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public enum CameraWhiteBalanceMode
|
Gif,
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// No white balance
|
|
||||||
/// </summary>
|
|
||||||
Off,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The automatic
|
|
||||||
/// </summary>
|
|
||||||
Auto,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The sun
|
|
||||||
/// </summary>
|
|
||||||
Sun,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The cloud
|
|
||||||
/// </summary>
|
|
||||||
Cloud,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The shade
|
|
||||||
/// </summary>
|
|
||||||
Shade,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The tungsten
|
|
||||||
/// </summary>
|
|
||||||
Tungsten,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The fluorescent
|
|
||||||
/// </summary>
|
|
||||||
Fluorescent,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The incandescent
|
|
||||||
/// </summary>
|
|
||||||
Incandescent,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The flash
|
|
||||||
/// </summary>
|
|
||||||
Flash,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The horizon
|
|
||||||
/// </summary>
|
|
||||||
Horizon
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Defines the available image effects for the Raspberry Pi's camera module
|
/// The PNG
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public enum CameraImageEffect
|
Png,
|
||||||
{
|
}
|
||||||
/// <summary>
|
|
||||||
/// No effect
|
/// <summary>
|
||||||
/// </summary>
|
/// Defines the different exposure modes for the Raspberry Pi's camera module
|
||||||
None,
|
/// </summary>
|
||||||
|
public enum CameraExposureMode {
|
||||||
/// <summary>
|
|
||||||
/// The negative
|
|
||||||
/// </summary>
|
|
||||||
Negative,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The solarise
|
|
||||||
/// </summary>
|
|
||||||
Solarise,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The whiteboard
|
|
||||||
/// </summary>
|
|
||||||
Whiteboard,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The blackboard
|
|
||||||
/// </summary>
|
|
||||||
Blackboard,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The sketch
|
|
||||||
/// </summary>
|
|
||||||
Sketch,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The denoise
|
|
||||||
/// </summary>
|
|
||||||
Denoise,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The emboss
|
|
||||||
/// </summary>
|
|
||||||
Emboss,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The oil paint
|
|
||||||
/// </summary>
|
|
||||||
OilPaint,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The hatch
|
|
||||||
/// </summary>
|
|
||||||
Hatch,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Graphite Pen
|
|
||||||
/// </summary>
|
|
||||||
GPen,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The pastel
|
|
||||||
/// </summary>
|
|
||||||
Pastel,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The water colour
|
|
||||||
/// </summary>
|
|
||||||
WaterColour,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The film
|
|
||||||
/// </summary>
|
|
||||||
Film,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The blur
|
|
||||||
/// </summary>
|
|
||||||
Blur,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The saturation
|
|
||||||
/// </summary>
|
|
||||||
Saturation,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The solour swap
|
|
||||||
/// </summary>
|
|
||||||
SolourSwap,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The washed out
|
|
||||||
/// </summary>
|
|
||||||
WashedOut,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The colour point
|
|
||||||
/// </summary>
|
|
||||||
ColourPoint,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The colour balance
|
|
||||||
/// </summary>
|
|
||||||
ColourBalance,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The cartoon
|
|
||||||
/// </summary>
|
|
||||||
Cartoon
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Defines the different metering modes for the Raspberry Pi's camera module
|
/// The automatic
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public enum CameraMeteringMode
|
Auto,
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The average
|
|
||||||
/// </summary>
|
|
||||||
Average,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The spot
|
|
||||||
/// </summary>
|
|
||||||
Spot,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The backlit
|
|
||||||
/// </summary>
|
|
||||||
Backlit,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The matrix
|
|
||||||
/// </summary>
|
|
||||||
Matrix,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Defines the different image rotation modes for the Raspberry Pi's camera module
|
/// The night
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public enum CameraImageRotation
|
Night,
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// No rerotation
|
|
||||||
/// </summary>
|
|
||||||
None = 0,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 90 Degrees
|
|
||||||
/// </summary>
|
|
||||||
Degrees90 = 90,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 180 Degrees
|
|
||||||
/// </summary>
|
|
||||||
Degrees180 = 180,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 270 degrees
|
|
||||||
/// </summary>
|
|
||||||
Degrees270 = 270
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Defines the different DRC (Dynamic Range Compensation) modes for the Raspberry Pi's camera module
|
/// The night preview
|
||||||
/// Helpful for low light photos
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public enum CameraDynamicRangeCompensation
|
NightPreview,
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The off setting
|
|
||||||
/// </summary>
|
|
||||||
Off,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The low
|
|
||||||
/// </summary>
|
|
||||||
Low,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The medium
|
|
||||||
/// </summary>
|
|
||||||
Medium,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The high
|
|
||||||
/// </summary>
|
|
||||||
High
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Defines the bit-wise mask flags for the available annotation elements for the Raspberry Pi's camera module
|
/// The backlight
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[Flags]
|
Backlight,
|
||||||
public enum CameraAnnotation
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The none
|
|
||||||
/// </summary>
|
|
||||||
None = 0,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The time
|
|
||||||
/// </summary>
|
|
||||||
Time = 4,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The date
|
|
||||||
/// </summary>
|
|
||||||
Date = 8,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The shutter settings
|
|
||||||
/// </summary>
|
|
||||||
ShutterSettings = 16,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The caf settings
|
|
||||||
/// </summary>
|
|
||||||
CafSettings = 32,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The gain settings
|
|
||||||
/// </summary>
|
|
||||||
GainSettings = 64,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The lens settings
|
|
||||||
/// </summary>
|
|
||||||
LensSettings = 128,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The motion settings
|
|
||||||
/// </summary>
|
|
||||||
MotionSettings = 256,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The frame number
|
|
||||||
/// </summary>
|
|
||||||
FrameNumber = 512,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The solid background
|
|
||||||
/// </summary>
|
|
||||||
SolidBackground = 1024,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Defines the different H.264 encoding profiles to be used when capturing video.
|
/// The spotlight
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public enum CameraH264Profile
|
Spotlight,
|
||||||
{
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// BP: Primarily for lower-cost applications with limited computing resources,
|
/// The sports
|
||||||
/// this profile is used widely in videoconferencing and mobile applications.
|
/// </summary>
|
||||||
/// </summary>
|
Sports,
|
||||||
Baseline,
|
|
||||||
|
/// <summary>
|
||||||
/// <summary>
|
/// The snow
|
||||||
/// MP: Originally intended as the mainstream consumer profile for broadcast
|
/// </summary>
|
||||||
/// and storage applications, the importance of this profile faded when the High profile was developed for those applications.
|
Snow,
|
||||||
/// </summary>
|
|
||||||
Main,
|
/// <summary>
|
||||||
|
/// The beach
|
||||||
/// <summary>
|
/// </summary>
|
||||||
/// HiP: The primary profile for broadcast and disc storage applications, particularly
|
Beach,
|
||||||
/// for high-definition television applications (this is the profile adopted into HD DVD and Blu-ray Disc, for example).
|
|
||||||
/// </summary>
|
/// <summary>
|
||||||
High
|
/// The very long
|
||||||
}
|
/// </summary>
|
||||||
|
VeryLong,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The fixed FPS
|
||||||
|
/// </summary>
|
||||||
|
FixedFps,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The anti shake
|
||||||
|
/// </summary>
|
||||||
|
AntiShake,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The fireworks
|
||||||
|
/// </summary>
|
||||||
|
Fireworks
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the different AWB (Auto White Balance) modes for the Raspberry Pi's camera module
|
||||||
|
/// </summary>
|
||||||
|
public enum CameraWhiteBalanceMode {
|
||||||
|
/// <summary>
|
||||||
|
/// No white balance
|
||||||
|
/// </summary>
|
||||||
|
Off,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The automatic
|
||||||
|
/// </summary>
|
||||||
|
Auto,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The sun
|
||||||
|
/// </summary>
|
||||||
|
Sun,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The cloud
|
||||||
|
/// </summary>
|
||||||
|
Cloud,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The shade
|
||||||
|
/// </summary>
|
||||||
|
Shade,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The tungsten
|
||||||
|
/// </summary>
|
||||||
|
Tungsten,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The fluorescent
|
||||||
|
/// </summary>
|
||||||
|
Fluorescent,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The incandescent
|
||||||
|
/// </summary>
|
||||||
|
Incandescent,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The flash
|
||||||
|
/// </summary>
|
||||||
|
Flash,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The horizon
|
||||||
|
/// </summary>
|
||||||
|
Horizon
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the available image effects for the Raspberry Pi's camera module
|
||||||
|
/// </summary>
|
||||||
|
public enum CameraImageEffect {
|
||||||
|
/// <summary>
|
||||||
|
/// No effect
|
||||||
|
/// </summary>
|
||||||
|
None,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The negative
|
||||||
|
/// </summary>
|
||||||
|
Negative,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The solarise
|
||||||
|
/// </summary>
|
||||||
|
Solarise,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The whiteboard
|
||||||
|
/// </summary>
|
||||||
|
Whiteboard,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The blackboard
|
||||||
|
/// </summary>
|
||||||
|
Blackboard,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The sketch
|
||||||
|
/// </summary>
|
||||||
|
Sketch,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The denoise
|
||||||
|
/// </summary>
|
||||||
|
Denoise,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The emboss
|
||||||
|
/// </summary>
|
||||||
|
Emboss,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The oil paint
|
||||||
|
/// </summary>
|
||||||
|
OilPaint,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The hatch
|
||||||
|
/// </summary>
|
||||||
|
Hatch,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Graphite Pen
|
||||||
|
/// </summary>
|
||||||
|
GPen,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The pastel
|
||||||
|
/// </summary>
|
||||||
|
Pastel,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The water colour
|
||||||
|
/// </summary>
|
||||||
|
WaterColour,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The film
|
||||||
|
/// </summary>
|
||||||
|
Film,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The blur
|
||||||
|
/// </summary>
|
||||||
|
Blur,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The saturation
|
||||||
|
/// </summary>
|
||||||
|
Saturation,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The solour swap
|
||||||
|
/// </summary>
|
||||||
|
SolourSwap,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The washed out
|
||||||
|
/// </summary>
|
||||||
|
WashedOut,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The colour point
|
||||||
|
/// </summary>
|
||||||
|
ColourPoint,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The colour balance
|
||||||
|
/// </summary>
|
||||||
|
ColourBalance,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The cartoon
|
||||||
|
/// </summary>
|
||||||
|
Cartoon
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the different metering modes for the Raspberry Pi's camera module
|
||||||
|
/// </summary>
|
||||||
|
public enum CameraMeteringMode {
|
||||||
|
/// <summary>
|
||||||
|
/// The average
|
||||||
|
/// </summary>
|
||||||
|
Average,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The spot
|
||||||
|
/// </summary>
|
||||||
|
Spot,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The backlit
|
||||||
|
/// </summary>
|
||||||
|
Backlit,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The matrix
|
||||||
|
/// </summary>
|
||||||
|
Matrix,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the different image rotation modes for the Raspberry Pi's camera module
|
||||||
|
/// </summary>
|
||||||
|
public enum CameraImageRotation {
|
||||||
|
/// <summary>
|
||||||
|
/// No rerotation
|
||||||
|
/// </summary>
|
||||||
|
None = 0,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 90 Degrees
|
||||||
|
/// </summary>
|
||||||
|
Degrees90 = 90,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 180 Degrees
|
||||||
|
/// </summary>
|
||||||
|
Degrees180 = 180,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 270 degrees
|
||||||
|
/// </summary>
|
||||||
|
Degrees270 = 270
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the different DRC (Dynamic Range Compensation) modes for the Raspberry Pi's camera module
|
||||||
|
/// Helpful for low light photos
|
||||||
|
/// </summary>
|
||||||
|
public enum CameraDynamicRangeCompensation {
|
||||||
|
/// <summary>
|
||||||
|
/// The off setting
|
||||||
|
/// </summary>
|
||||||
|
Off,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The low
|
||||||
|
/// </summary>
|
||||||
|
Low,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The medium
|
||||||
|
/// </summary>
|
||||||
|
Medium,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The high
|
||||||
|
/// </summary>
|
||||||
|
High
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the bit-wise mask flags for the available annotation elements for the Raspberry Pi's camera module
|
||||||
|
/// </summary>
|
||||||
|
[Flags]
|
||||||
|
public enum CameraAnnotation {
|
||||||
|
/// <summary>
|
||||||
|
/// The none
|
||||||
|
/// </summary>
|
||||||
|
None = 0,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The time
|
||||||
|
/// </summary>
|
||||||
|
Time = 4,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The date
|
||||||
|
/// </summary>
|
||||||
|
Date = 8,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The shutter settings
|
||||||
|
/// </summary>
|
||||||
|
ShutterSettings = 16,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The caf settings
|
||||||
|
/// </summary>
|
||||||
|
CafSettings = 32,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The gain settings
|
||||||
|
/// </summary>
|
||||||
|
GainSettings = 64,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The lens settings
|
||||||
|
/// </summary>
|
||||||
|
LensSettings = 128,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The motion settings
|
||||||
|
/// </summary>
|
||||||
|
MotionSettings = 256,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The frame number
|
||||||
|
/// </summary>
|
||||||
|
FrameNumber = 512,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The solid background
|
||||||
|
/// </summary>
|
||||||
|
SolidBackground = 1024,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the different H.264 encoding profiles to be used when capturing video.
|
||||||
|
/// </summary>
|
||||||
|
public enum CameraH264Profile {
|
||||||
|
/// <summary>
|
||||||
|
/// BP: Primarily for lower-cost applications with limited computing resources,
|
||||||
|
/// this profile is used widely in videoconferencing and mobile applications.
|
||||||
|
/// </summary>
|
||||||
|
Baseline,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// MP: Originally intended as the mainstream consumer profile for broadcast
|
||||||
|
/// and storage applications, the importance of this profile faded when the High profile was developed for those applications.
|
||||||
|
/// </summary>
|
||||||
|
Main,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// HiP: The primary profile for broadcast and disc storage applications, particularly
|
||||||
|
/// for high-definition television applications (this is the profile adopted into HD DVD and Blu-ray Disc, for example).
|
||||||
|
/// </summary>
|
||||||
|
High
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,80 +1,66 @@
|
|||||||
namespace Unosquare.RaspberryIO.Computer
|
using Unosquare.Swan.Abstractions;
|
||||||
{
|
using System.Globalization;
|
||||||
using Swan.Abstractions;
|
using System.IO;
|
||||||
using System.Globalization;
|
using System;
|
||||||
using System.IO;
|
|
||||||
|
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";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The Official Raspberry Pi 7-inch touch display from the foundation
|
/// Prevents a default instance of the <see cref="DsiDisplay"/> class from being created.
|
||||||
/// Some docs available here:
|
|
||||||
/// http://forums.pimoroni.com/t/official-7-raspberry-pi-touch-screen-faq/959
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class DsiDisplay : SingletonBase<DsiDisplay>
|
private DsiDisplay() {
|
||||||
{
|
// placeholder
|
||||||
private const string BacklightFilename = "/sys/class/backlight/rpi_backlight/bl_power";
|
}
|
||||||
private const string BrightnessFilename = "/sys/class/backlight/rpi_backlight/brightness";
|
|
||||||
|
/// <summary>
|
||||||
/// <summary>
|
/// Gets a value indicating whether the Pi Foundation Display files are present.
|
||||||
/// Prevents a default instance of the <see cref="DsiDisplay"/> class from being created.
|
/// </summary>
|
||||||
/// </summary>
|
/// <value>
|
||||||
private DsiDisplay()
|
/// <c>true</c> if this instance is present; otherwise, <c>false</c>.
|
||||||
{
|
/// </value>
|
||||||
// placeholder
|
public Boolean IsPresent => File.Exists(BrightnessFilename);
|
||||||
}
|
|
||||||
|
/// <summary>
|
||||||
/// <summary>
|
/// Gets or sets the brightness of the DSI display via filesystem.
|
||||||
/// Gets a value indicating whether the Pi Foundation Display files are present.
|
/// </summary>
|
||||||
/// </summary>
|
/// <value>
|
||||||
/// <value>
|
/// The brightness.
|
||||||
/// <c>true</c> if this instance is present; otherwise, <c>false</c>.
|
/// </value>
|
||||||
/// </value>
|
public Byte Brightness {
|
||||||
public bool IsPresent => File.Exists(BrightnessFilename);
|
get => this.IsPresent == false ? (Byte)0 : Byte.TryParse(File.ReadAllText(BrightnessFilename).Trim(), out Byte brightness) ? brightness : (Byte)0;
|
||||||
|
set {
|
||||||
/// <summary>
|
if(this.IsPresent == false) {
|
||||||
/// Gets or sets the brightness of the DSI display via filesystem.
|
return;
|
||||||
/// </summary>
|
}
|
||||||
/// <value>
|
|
||||||
/// The brightness.
|
File.WriteAllText(BrightnessFilename, value.ToString(CultureInfo.InvariantCulture));
|
||||||
/// </value>
|
}
|
||||||
public byte Brightness
|
}
|
||||||
{
|
|
||||||
get
|
/// <summary>
|
||||||
{
|
/// Gets or sets a value indicating whether the backlight of the DSI display on.
|
||||||
if (IsPresent == false) return 0;
|
/// This operation is performed via the file system
|
||||||
|
/// </summary>
|
||||||
return byte.TryParse(File.ReadAllText(BrightnessFilename).Trim(), out var brightness) ? brightness : (byte)0;
|
/// <value>
|
||||||
}
|
/// <c>true</c> if this instance is backlight on; otherwise, <c>false</c>.
|
||||||
set
|
/// </value>
|
||||||
{
|
public Boolean IsBacklightOn {
|
||||||
if (IsPresent == false) return;
|
get => this.IsPresent == false ? false : Int32.TryParse(File.ReadAllText(BacklightFilename).Trim(), out Int32 backlight) ? backlight == 0 : false;
|
||||||
File.WriteAllText(BrightnessFilename, value.ToString(CultureInfo.InvariantCulture));
|
set {
|
||||||
}
|
if(this.IsPresent == false) {
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets a value indicating whether the backlight of the DSI display on.
|
File.WriteAllText(BacklightFilename, value ? "0" : "1");
|
||||||
/// This operation is performed via the file system
|
}
|
||||||
/// </summary>
|
}
|
||||||
/// <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;
|
|
||||||
}
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (IsPresent == false) return;
|
|
||||||
|
|
||||||
File.WriteAllText(BacklightFilename, value ? "0" : "1");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,40 +1,51 @@
|
|||||||
namespace Unosquare.RaspberryIO.Computer
|
using System;
|
||||||
{
|
using System.Net;
|
||||||
using System.Net;
|
|
||||||
|
namespace Unosquare.RaspberryIO.Computer {
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a Network Adapter
|
||||||
|
/// </summary>
|
||||||
|
public class NetworkAdapterInfo {
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a Network Adapter
|
/// Gets the name.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class NetworkAdapterInfo
|
public String Name {
|
||||||
{
|
get; internal set;
|
||||||
/// <summary>
|
}
|
||||||
/// Gets the name.
|
|
||||||
/// </summary>
|
/// <summary>
|
||||||
public string Name { get; internal set; }
|
/// Gets the IP V4 address.
|
||||||
|
/// </summary>
|
||||||
/// <summary>
|
public IPAddress IPv4 {
|
||||||
/// Gets the IP V4 address.
|
get; internal set;
|
||||||
/// </summary>
|
}
|
||||||
public IPAddress IPv4 { get; internal set; }
|
|
||||||
|
/// <summary>
|
||||||
/// <summary>
|
/// Gets the IP V6 address.
|
||||||
/// Gets the IP V6 address.
|
/// </summary>
|
||||||
/// </summary>
|
public IPAddress IPv6 {
|
||||||
public IPAddress IPv6 { get; internal set; }
|
get; internal set;
|
||||||
|
}
|
||||||
/// <summary>
|
|
||||||
/// Gets the name of the access point.
|
/// <summary>
|
||||||
/// </summary>
|
/// Gets the name of the access point.
|
||||||
public string AccessPointName { get; internal set; }
|
/// </summary>
|
||||||
|
public String AccessPointName {
|
||||||
/// <summary>
|
get; internal set;
|
||||||
/// Gets the MAC (Physical) address.
|
}
|
||||||
/// </summary>
|
|
||||||
public string MacAddress { get; internal set; }
|
/// <summary>
|
||||||
|
/// Gets the MAC (Physical) address.
|
||||||
/// <summary>
|
/// </summary>
|
||||||
/// Gets a value indicating whether this instance is wireless.
|
public String MacAddress {
|
||||||
/// </summary>
|
get; internal set;
|
||||||
public bool IsWireless { get; internal set; }
|
}
|
||||||
}
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value indicating whether this instance is wireless.
|
||||||
|
/// </summary>
|
||||||
|
public Boolean IsWireless {
|
||||||
|
get; internal set;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,266 +1,252 @@
|
|||||||
namespace Unosquare.RaspberryIO.Computer
|
using Unosquare.Swan;
|
||||||
{
|
using Unosquare.Swan.Abstractions;
|
||||||
using Swan;
|
using Unosquare.Swan.Components;
|
||||||
using Swan.Abstractions;
|
using System;
|
||||||
using Swan.Components;
|
using System.Collections.Generic;
|
||||||
using System;
|
using System.IO;
|
||||||
using System.Collections.Generic;
|
using System.Linq;
|
||||||
using System.IO;
|
using System.Net;
|
||||||
using System.Linq;
|
using System.Text;
|
||||||
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:";
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents the network information
|
/// Gets the local machine Host Name.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class NetworkSettings : SingletonBase<NetworkSettings>
|
public String HostName => Network.HostName;
|
||||||
{
|
|
||||||
private const string EssidTag = "ESSID:";
|
/// <summary>
|
||||||
|
/// Retrieves the wireless networks.
|
||||||
/// <summary>
|
/// </summary>
|
||||||
/// Gets the local machine Host Name.
|
/// <param name="adapter">The adapter.</param>
|
||||||
/// </summary>
|
/// <returns>A list of WiFi networks</returns>
|
||||||
public string HostName => Network.HostName;
|
public List<WirelessNetworkInfo> RetrieveWirelessNetworks(String adapter) => this.RetrieveWirelessNetworks(new[] { adapter });
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Retrieves the wireless networks.
|
/// Retrieves the wireless networks.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="adapter">The adapter.</param>
|
/// <param name="adapters">The adapters.</param>
|
||||||
/// <returns>A list of WiFi networks</returns>
|
/// <returns>A list of WiFi networks</returns>
|
||||||
public List<WirelessNetworkInfo> RetrieveWirelessNetworks(string adapter) => RetrieveWirelessNetworks(new[] { adapter });
|
public List<WirelessNetworkInfo> RetrieveWirelessNetworks(String[] adapters = null) {
|
||||||
|
List<WirelessNetworkInfo> result = new List<WirelessNetworkInfo>();
|
||||||
/// <summary>
|
|
||||||
/// Retrieves the wireless networks.
|
foreach(String networkAdapter in adapters ?? this.RetrieveAdapters().Where(x => x.IsWireless).Select(x => x.Name)) {
|
||||||
/// </summary>
|
String wirelessOutput = ProcessRunner.GetProcessOutputAsync("iwlist", $"{networkAdapter} scanning").Result;
|
||||||
/// <param name="adapters">The adapters.</param>
|
String[] outputLines =
|
||||||
/// <returns>A list of WiFi networks</returns>
|
wirelessOutput.Split('\n')
|
||||||
public List<WirelessNetworkInfo> RetrieveWirelessNetworks(string[] adapters = null)
|
.Select(x => x.Trim())
|
||||||
{
|
.Where(x => String.IsNullOrWhiteSpace(x) == false)
|
||||||
var result = new List<WirelessNetworkInfo>();
|
.ToArray();
|
||||||
|
|
||||||
foreach (var networkAdapter in adapters ?? RetrieveAdapters().Where(x => x.IsWireless).Select(x => x.Name))
|
for(Int32 i = 0; i < outputLines.Length; i++) {
|
||||||
{
|
String line = outputLines[i];
|
||||||
var wirelessOutput = ProcessRunner.GetProcessOutputAsync("iwlist", $"{networkAdapter} scanning").Result;
|
|
||||||
var outputLines =
|
if(line.StartsWith(EssidTag) == false) {
|
||||||
wirelessOutput.Split('\n')
|
continue;
|
||||||
.Select(x => x.Trim())
|
}
|
||||||
.Where(x => string.IsNullOrWhiteSpace(x) == false)
|
|
||||||
.ToArray();
|
WirelessNetworkInfo network = new WirelessNetworkInfo() {
|
||||||
|
Name = line.Replace(EssidTag, String.Empty).Replace("\"", String.Empty)
|
||||||
for (var i = 0; i < outputLines.Length; i++)
|
};
|
||||||
{
|
|
||||||
var line = outputLines[i];
|
while(true) {
|
||||||
|
if(i + 1 >= outputLines.Length) {
|
||||||
if (line.StartsWith(EssidTag) == false) continue;
|
break;
|
||||||
|
}
|
||||||
var network = new WirelessNetworkInfo()
|
|
||||||
{
|
// should look for two lines before the ESSID acording to the scan
|
||||||
Name = line.Replace(EssidTag, string.Empty).Replace("\"", string.Empty)
|
line = outputLines[i - 2];
|
||||||
};
|
|
||||||
|
if(line.StartsWith("Quality=")) {
|
||||||
while (true)
|
network.Quality = line.Replace("Quality=", String.Empty);
|
||||||
{
|
break;
|
||||||
if (i + 1 >= outputLines.Length) break;
|
}
|
||||||
|
}
|
||||||
// should look for two lines before the ESSID acording to the scan
|
|
||||||
line = outputLines[i - 2];
|
while(true) {
|
||||||
|
if(i + 1 >= outputLines.Length) {
|
||||||
if (line.StartsWith("Quality="))
|
break;
|
||||||
{
|
}
|
||||||
network.Quality = line.Replace("Quality=", string.Empty);
|
|
||||||
break;
|
// should look for a line before the ESSID acording to the scan
|
||||||
}
|
line = outputLines[i - 1];
|
||||||
}
|
|
||||||
|
if(line.StartsWith("Encryption key:")) {
|
||||||
while (true)
|
network.IsEncrypted = line.Replace("Encryption key:", String.Empty).Trim() == "on";
|
||||||
{
|
break;
|
||||||
if (i + 1 >= outputLines.Length) break;
|
}
|
||||||
|
}
|
||||||
// should look for a line before the ESSID acording to the scan
|
|
||||||
line = outputLines[i - 1];
|
if(result.Any(x => x.Name == network.Name) == false) {
|
||||||
|
result.Add(network);
|
||||||
if (line.StartsWith("Encryption key:"))
|
}
|
||||||
{
|
}
|
||||||
network.IsEncrypted = line.Replace("Encryption key:", string.Empty).Trim() == "on";
|
}
|
||||||
break;
|
|
||||||
}
|
return result.OrderBy(x => x.Name).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result.Any(x => x.Name == network.Name) == false)
|
/// <summary>
|
||||||
result.Add(network);
|
/// Setups the wireless network.
|
||||||
}
|
/// </summary>
|
||||||
}
|
/// <param name="adapterName">Name of the adapter.</param>
|
||||||
|
/// <param name="networkSsid">The network ssid.</param>
|
||||||
return result.OrderBy(x => x.Name).ToList();
|
/// <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>
|
||||||
/// <summary>
|
public Boolean SetupWirelessNetwork(String adapterName, String networkSsid, String password = null, String countryCode = "US") {
|
||||||
/// Setups the wireless network.
|
// TODO: Get the country where the device is located to set 'country' param in payload var
|
||||||
/// </summary>
|
String payload = $"country={countryCode}\nctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev\nupdate_config=1\n";
|
||||||
/// <param name="adapterName">Name of the adapter.</param>
|
payload += String.IsNullOrEmpty(password)
|
||||||
/// <param name="networkSsid">The network ssid.</param>
|
? $"network={{\n\tssid=\"{networkSsid}\"\n\t}}\n"
|
||||||
/// <param name="password">The password.</param>
|
: $"network={{\n\tssid=\"{networkSsid}\"\n\tpsk=\"{password}\"\n\t}}\n";
|
||||||
/// <param name="countryCode">The 2-letter country code in uppercase. Default is US.</param>
|
try {
|
||||||
/// <returns>True if successful. Otherwise, false.</returns>
|
File.WriteAllText("/etc/wpa_supplicant/wpa_supplicant.conf", payload);
|
||||||
public bool SetupWirelessNetwork(string adapterName, string networkSsid, string password = null, string countryCode = "US")
|
ProcessRunner.GetProcessOutputAsync("pkill", "-f wpa_supplicant").Wait();
|
||||||
{
|
ProcessRunner.GetProcessOutputAsync("ifdown", adapterName).Wait();
|
||||||
// TODO: Get the country where the device is located to set 'country' param in payload var
|
ProcessRunner.GetProcessOutputAsync("ifup", adapterName).Wait();
|
||||||
var payload = $"country={countryCode}\nctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev\nupdate_config=1\n";
|
} catch(Exception ex) {
|
||||||
payload += string.IsNullOrEmpty(password)
|
ex.Log(nameof(NetworkSettings));
|
||||||
? $"network={{\n\tssid=\"{networkSsid}\"\n\t}}\n"
|
return false;
|
||||||
: $"network={{\n\tssid=\"{networkSsid}\"\n\tpsk=\"{password}\"\n\t}}\n";
|
}
|
||||||
try
|
|
||||||
{
|
return true;
|
||||||
File.WriteAllText("/etc/wpa_supplicant/wpa_supplicant.conf", payload);
|
}
|
||||||
ProcessRunner.GetProcessOutputAsync("pkill", "-f wpa_supplicant").Wait();
|
|
||||||
ProcessRunner.GetProcessOutputAsync("ifdown", adapterName).Wait();
|
/// <summary>
|
||||||
ProcessRunner.GetProcessOutputAsync("ifup", adapterName).Wait();
|
/// Retrieves the network adapters.
|
||||||
}
|
/// </summary>
|
||||||
catch (Exception ex)
|
/// <returns>A list of network adapters.</returns>
|
||||||
{
|
public List<NetworkAdapterInfo> RetrieveAdapters() {
|
||||||
ex.Log(nameof(NetworkSettings));
|
const String hWaddr = "HWaddr ";
|
||||||
return false;
|
const String ether = "ether ";
|
||||||
}
|
|
||||||
|
List<NetworkAdapterInfo> result = new List<NetworkAdapterInfo>();
|
||||||
return true;
|
String interfacesOutput = ProcessRunner.GetProcessOutputAsync("ifconfig").Result;
|
||||||
}
|
String[] wlanOutput = ProcessRunner.GetProcessOutputAsync("iwconfig")
|
||||||
|
.Result.Split('\n')
|
||||||
/// <summary>
|
.Where(x => x.Contains("no wireless extensions.") == false)
|
||||||
/// Retrieves the network adapters.
|
.ToArray();
|
||||||
/// </summary>
|
|
||||||
/// <returns>A list of network adapters.</returns>
|
String[] outputLines = interfacesOutput.Split('\n').Where(x => String.IsNullOrWhiteSpace(x) == false).ToArray();
|
||||||
public List<NetworkAdapterInfo> RetrieveAdapters()
|
|
||||||
{
|
for(Int32 i = 0; i < outputLines.Length; i++) {
|
||||||
const string hWaddr = "HWaddr ";
|
// grab the current line
|
||||||
const string ether = "ether ";
|
String line = outputLines[i];
|
||||||
|
|
||||||
var result = new List<NetworkAdapterInfo>();
|
// skip if the line is indented
|
||||||
var interfacesOutput = ProcessRunner.GetProcessOutputAsync("ifconfig").Result;
|
if(Char.IsLetterOrDigit(line[0]) == false) {
|
||||||
var wlanOutput = ProcessRunner.GetProcessOutputAsync("iwconfig")
|
continue;
|
||||||
.Result.Split('\n')
|
}
|
||||||
.Where(x => x.Contains("no wireless extensions.") == false)
|
|
||||||
.ToArray();
|
// Read the line as an adatper
|
||||||
|
NetworkAdapterInfo adapter = new NetworkAdapterInfo {
|
||||||
var outputLines = interfacesOutput.Split('\n').Where(x => string.IsNullOrWhiteSpace(x) == false).ToArray();
|
Name = line.Substring(0, line.IndexOf(' ')).TrimEnd(':')
|
||||||
|
};
|
||||||
for (var i = 0; i < outputLines.Length; i++)
|
|
||||||
{
|
// Parse the MAC address in old version of ifconfig; it comes in the first line
|
||||||
// grab the current line
|
if(line.IndexOf(hWaddr) >= 0) {
|
||||||
var line = outputLines[i];
|
Int32 startIndexHwd = line.IndexOf(hWaddr) + hWaddr.Length;
|
||||||
|
adapter.MacAddress = line.Substring(startIndexHwd, 17).Trim();
|
||||||
// skip if the line is indented
|
}
|
||||||
if (char.IsLetterOrDigit(line[0]) == false)
|
|
||||||
continue;
|
// Parse the info in lines other than the first
|
||||||
|
for(Int32 j = i + 1; j < outputLines.Length; j++) {
|
||||||
// Read the line as an adatper
|
// Get the contents of the indented line
|
||||||
var adapter = new NetworkAdapterInfo
|
String indentedLine = outputLines[j];
|
||||||
{
|
|
||||||
Name = line.Substring(0, line.IndexOf(' ')).TrimEnd(':')
|
// We have hit the next adapter info
|
||||||
};
|
if(Char.IsLetterOrDigit(indentedLine[0])) {
|
||||||
|
i = j - 1;
|
||||||
// Parse the MAC address in old version of ifconfig; it comes in the first line
|
break;
|
||||||
if (line.IndexOf(hWaddr) >= 0)
|
}
|
||||||
{
|
|
||||||
var startIndexHwd = line.IndexOf(hWaddr) + hWaddr.Length;
|
// Parse the MAC address in new versions of ifconfig; it no longer comes in the first line
|
||||||
adapter.MacAddress = line.Substring(startIndexHwd, 17).Trim();
|
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 info in lines other than the first
|
}
|
||||||
for (var j = i + 1; j < outputLines.Length; j++)
|
|
||||||
{
|
// Parse the IPv4 Address
|
||||||
// Get the contents of the indented line
|
{
|
||||||
var indentedLine = outputLines[j];
|
String addressText = ParseOutputTagFromLine(indentedLine, "inet addr:") ?? ParseOutputTagFromLine(indentedLine, "inet ");
|
||||||
|
|
||||||
// We have hit the next adapter info
|
if(addressText != null) {
|
||||||
if (char.IsLetterOrDigit(indentedLine[0]))
|
if(IPAddress.TryParse(addressText, out IPAddress outValue)) {
|
||||||
{
|
adapter.IPv4 = outValue;
|
||||||
i = j - 1;
|
}
|
||||||
break;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse the MAC address in new versions of ifconfig; it no longer comes in the first line
|
// Parse the IPv6 Address
|
||||||
if (indentedLine.IndexOf(ether) >= 0 && string.IsNullOrWhiteSpace(adapter.MacAddress))
|
{
|
||||||
{
|
String addressText = ParseOutputTagFromLine(indentedLine, "inet6 addr:") ?? ParseOutputTagFromLine(indentedLine, "inet6 ");
|
||||||
var startIndexHwd = indentedLine.IndexOf(ether) + ether.Length;
|
|
||||||
adapter.MacAddress = indentedLine.Substring(startIndexHwd, 17).Trim();
|
if(addressText != null) {
|
||||||
}
|
if(IPAddress.TryParse(addressText, out IPAddress outValue)) {
|
||||||
|
adapter.IPv6 = outValue;
|
||||||
// Parse the IPv4 Address
|
}
|
||||||
{
|
}
|
||||||
var addressText = ParseOutputTagFromLine(indentedLine, "inet addr:") ?? ParseOutputTagFromLine(indentedLine, "inet ");
|
}
|
||||||
|
|
||||||
if (addressText != null)
|
// we have hit the end of the output in an indented line
|
||||||
{
|
if(j >= outputLines.Length - 1) {
|
||||||
if (IPAddress.TryParse(addressText, out var outValue))
|
i = outputLines.Length;
|
||||||
adapter.IPv4 = outValue;
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
// Retrieve the wireless LAN info
|
||||||
// Parse the IPv6 Address
|
String wlanInfo = wlanOutput.FirstOrDefault(x => x.StartsWith(adapter.Name));
|
||||||
{
|
|
||||||
var addressText = ParseOutputTagFromLine(indentedLine, "inet6 addr:") ?? ParseOutputTagFromLine(indentedLine, "inet6 ");
|
if(wlanInfo != null) {
|
||||||
|
adapter.IsWireless = true;
|
||||||
if (addressText != null)
|
String[] essidParts = wlanInfo.Split(new[] { EssidTag }, StringSplitOptions.RemoveEmptyEntries);
|
||||||
{
|
if(essidParts.Length >= 2) {
|
||||||
if (IPAddress.TryParse(addressText, out var outValue))
|
adapter.AccessPointName = essidParts[1].Replace("\"", String.Empty).Trim();
|
||||||
adapter.IPv6 = outValue;
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
// Add the current adapter to the result
|
||||||
// we have hit the end of the output in an indented line
|
result.Add(adapter);
|
||||||
if (j >= outputLines.Length - 1)
|
}
|
||||||
i = outputLines.Length;
|
|
||||||
}
|
return result.OrderBy(x => x.Name).ToList();
|
||||||
|
}
|
||||||
// Retrieve the wireless LAN info
|
|
||||||
var wlanInfo = wlanOutput.FirstOrDefault(x => x.StartsWith(adapter.Name));
|
/// <summary>
|
||||||
|
/// Retrieves current wireless connected network name.
|
||||||
if (wlanInfo != null)
|
/// </summary>
|
||||||
{
|
/// <returns>The connected network name.</returns>
|
||||||
adapter.IsWireless = true;
|
public String GetWirelessNetworkName() => ProcessRunner.GetProcessOutputAsync("iwgetid", "-r").Result;
|
||||||
var essidParts = wlanInfo.Split(new[] { EssidTag }, StringSplitOptions.RemoveEmptyEntries);
|
|
||||||
if (essidParts.Length >= 2)
|
/// <summary>
|
||||||
{
|
/// Parses the output tag from the given line.
|
||||||
adapter.AccessPointName = essidParts[1].Replace("\"", string.Empty).Trim();
|
/// </summary>
|
||||||
}
|
/// <param name="indentedLine">The indented line.</param>
|
||||||
}
|
/// <param name="tagName">Name of the tag.</param>
|
||||||
|
/// <returns>The value after the tag identifier</returns>
|
||||||
// Add the current adapter to the result
|
private static String ParseOutputTagFromLine(String indentedLine, String tagName) {
|
||||||
result.Add(adapter);
|
if(indentedLine.IndexOf(tagName) < 0) {
|
||||||
}
|
return null;
|
||||||
|
}
|
||||||
return result.OrderBy(x => x.Name).ToList();
|
|
||||||
}
|
Int32 startIndex = indentedLine.IndexOf(tagName) + tagName.Length;
|
||||||
|
StringBuilder builder = new StringBuilder(1024);
|
||||||
/// <summary>
|
for(Int32 c = startIndex; c < indentedLine.Length; c++) {
|
||||||
/// Retrieves current wireless connected network name.
|
Char currentChar = indentedLine[c];
|
||||||
/// </summary>
|
if(!Char.IsPunctuation(currentChar) && !Char.IsLetterOrDigit(currentChar)) {
|
||||||
/// <returns>The connected network name.</returns>
|
break;
|
||||||
public string GetWirelessNetworkName() => ProcessRunner.GetProcessOutputAsync("iwgetid", "-r").Result;
|
}
|
||||||
|
|
||||||
/// <summary>
|
_ = builder.Append(currentChar);
|
||||||
/// Parses the output tag from the given line.
|
}
|
||||||
/// </summary>
|
|
||||||
/// <param name="indentedLine">The indented line.</param>
|
return builder.ToString();
|
||||||
/// <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)
|
|
||||||
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))
|
|
||||||
break;
|
|
||||||
|
|
||||||
builder.Append(currentChar);
|
|
||||||
}
|
|
||||||
|
|
||||||
return builder.ToString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,46 +1,58 @@
|
|||||||
namespace Unosquare.RaspberryIO.Computer
|
using System;
|
||||||
{
|
|
||||||
|
namespace Unosquare.RaspberryIO.Computer {
|
||||||
|
/// <summary>
|
||||||
|
/// Represents the OS Information
|
||||||
|
/// </summary>
|
||||||
|
public class OsInfo {
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents the OS Information
|
/// System name
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class OsInfo
|
public String SysName {
|
||||||
{
|
get; set;
|
||||||
/// <summary>
|
}
|
||||||
/// System name
|
|
||||||
/// </summary>
|
/// <summary>
|
||||||
public string SysName { get; set; }
|
/// Node name
|
||||||
|
/// </summary>
|
||||||
/// <summary>
|
public String NodeName {
|
||||||
/// Node name
|
get; set;
|
||||||
/// </summary>
|
}
|
||||||
public string NodeName { get; set; }
|
|
||||||
|
/// <summary>
|
||||||
/// <summary>
|
/// Release level
|
||||||
/// Release level
|
/// </summary>
|
||||||
/// </summary>
|
public String Release {
|
||||||
public string Release { get; set; }
|
get; set;
|
||||||
|
}
|
||||||
/// <summary>
|
|
||||||
/// Version level
|
/// <summary>
|
||||||
/// </summary>
|
/// Version level
|
||||||
public string Version { get; set; }
|
/// </summary>
|
||||||
|
public String Version {
|
||||||
/// <summary>
|
get; set;
|
||||||
/// Hardware level
|
}
|
||||||
/// </summary>
|
|
||||||
public string Machine { get; set; }
|
/// <summary>
|
||||||
|
/// Hardware level
|
||||||
/// <summary>
|
/// </summary>
|
||||||
/// Domain name
|
public String Machine {
|
||||||
/// </summary>
|
get; set;
|
||||||
public string DomainName { get; set; }
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns a <see cref="string" /> that represents this instance.
|
/// Domain name
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>
|
public String DomainName {
|
||||||
/// A <see cref="string" /> that represents this instance.
|
get; set;
|
||||||
/// </returns>
|
}
|
||||||
public override string ToString() => $"{SysName} {Release} {Version}";
|
|
||||||
}
|
/// <summary>
|
||||||
|
/// Returns a <see cref="String" /> that represents this instance.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>
|
||||||
|
/// A <see cref="String" /> that represents this instance.
|
||||||
|
/// </returns>
|
||||||
|
public override String ToString() => $"{this.SysName} {this.Release} {this.Version}";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,134 +1,132 @@
|
|||||||
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 {
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Defines the board revision codes of the different versions of the Raspberry Pi
|
/// The unknown version
|
||||||
/// http://www.raspberrypi-spy.co.uk/2012/09/checking-your-raspberry-pi-board-version/
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public enum PiVersion
|
Unknown = 0,
|
||||||
{
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The unknown version
|
/// The model b rev1
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Unknown = 0,
|
ModelBRev1 = 0x0002,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The model b rev1
|
/// The model b rev1 ec N0001
|
||||||
/// </summary>
|
/// </summary>
|
||||||
ModelBRev1 = 0x0002,
|
ModelBRev1ECN0001 = 0x0003,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The model b rev1 ec N0001
|
/// The model b rev2x04
|
||||||
/// </summary>
|
/// </summary>
|
||||||
ModelBRev1ECN0001 = 0x0003,
|
ModelBRev2x04 = 0x0004,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The model b rev2x04
|
/// The model b rev2x05
|
||||||
/// </summary>
|
/// </summary>
|
||||||
ModelBRev2x04 = 0x0004,
|
ModelBRev2x05 = 0x0005,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The model b rev2x05
|
/// The model b rev2x06
|
||||||
/// </summary>
|
/// </summary>
|
||||||
ModelBRev2x05 = 0x0005,
|
ModelBRev2x06 = 0x0006,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The model b rev2x06
|
/// The model ax07
|
||||||
/// </summary>
|
/// </summary>
|
||||||
ModelBRev2x06 = 0x0006,
|
ModelAx07 = 0x0007,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The model ax07
|
/// The model ax08
|
||||||
/// </summary>
|
/// </summary>
|
||||||
ModelAx07 = 0x0007,
|
ModelAx08 = 0x0008,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The model ax08
|
/// The model ax09
|
||||||
/// </summary>
|
/// </summary>
|
||||||
ModelAx08 = 0x0008,
|
ModelAx09 = 0x0009,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The model ax09
|
/// The model b rev2x0d
|
||||||
/// </summary>
|
/// </summary>
|
||||||
ModelAx09 = 0x0009,
|
ModelBRev2x0d,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The model b rev2x0d
|
/// The model b rev2x0e
|
||||||
/// </summary>
|
/// </summary>
|
||||||
ModelBRev2x0d,
|
ModelBRev2x0e,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The model b rev2x0e
|
/// The model b rev2x0f
|
||||||
/// </summary>
|
/// </summary>
|
||||||
ModelBRev2x0e,
|
ModelBRev2x0f = 0x000f,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The model b rev2x0f
|
/// The model b plus0x10
|
||||||
/// </summary>
|
/// </summary>
|
||||||
ModelBRev2x0f = 0x000f,
|
ModelBPlus0x10 = 0x0010,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The model b plus0x10
|
/// The model b plus0x13
|
||||||
/// </summary>
|
/// </summary>
|
||||||
ModelBPlus0x10 = 0x0010,
|
ModelBPlus0x13 = 0x0013,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The model b plus0x13
|
/// The compute module0x11
|
||||||
/// </summary>
|
/// </summary>
|
||||||
ModelBPlus0x13 = 0x0013,
|
ComputeModule0x11 = 0x0011,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The compute module0x11
|
/// The compute module0x14
|
||||||
/// </summary>
|
/// </summary>
|
||||||
ComputeModule0x11 = 0x0011,
|
ComputeModule0x14 = 0x0014,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The compute module0x14
|
/// The model a plus0x12
|
||||||
/// </summary>
|
/// </summary>
|
||||||
ComputeModule0x14 = 0x0014,
|
ModelAPlus0x12 = 0x0012,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The model a plus0x12
|
/// The model a plus0x15
|
||||||
/// </summary>
|
/// </summary>
|
||||||
ModelAPlus0x12 = 0x0012,
|
ModelAPlus0x15 = 0x0015,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The model a plus0x15
|
/// The pi2 model B1V1 sony
|
||||||
/// </summary>
|
/// </summary>
|
||||||
ModelAPlus0x15 = 0x0015,
|
Pi2ModelB1v1Sony = 0xa01041,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The pi2 model B1V1 sony
|
/// The pi2 model B1V1 embest
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Pi2ModelB1v1Sony = 0xa01041,
|
Pi2ModelB1v1Embest = 0xa21041,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The pi2 model B1V1 embest
|
/// The pi2 model B1V2
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Pi2ModelB1v1Embest = 0xa21041,
|
Pi2ModelB1v2 = 0xa22042,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The pi2 model B1V2
|
/// The pi zero1v2
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Pi2ModelB1v2 = 0xa22042,
|
PiZero1v2 = 0x900092,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The pi zero1v2
|
/// The pi zero1v3
|
||||||
/// </summary>
|
/// </summary>
|
||||||
PiZero1v2 = 0x900092,
|
PiZero1v3 = 0x900093,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The pi zero1v3
|
/// The pi3 model b sony
|
||||||
/// </summary>
|
/// </summary>
|
||||||
PiZero1v3 = 0x900093,
|
Pi3ModelBSony = 0xa02082,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The pi3 model b sony
|
/// The pi3 model b embest
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Pi3ModelBSony = 0xa02082,
|
Pi3ModelBEmbest = 0xa22082
|
||||||
|
}
|
||||||
/// <summary>
|
|
||||||
/// The pi3 model b embest
|
|
||||||
/// </summary>
|
|
||||||
Pi3ModelBEmbest = 0xa22082
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -1,344 +1,343 @@
|
|||||||
namespace Unosquare.RaspberryIO.Computer
|
using Unosquare.RaspberryIO.Native;
|
||||||
{
|
using Unosquare.Swan.Abstractions;
|
||||||
using Native;
|
using System;
|
||||||
using Swan.Abstractions;
|
using System.Collections.Generic;
|
||||||
using System;
|
using System.Globalization;
|
||||||
using System.Collections.Generic;
|
using System.IO;
|
||||||
using System.Globalization;
|
using System.Linq;
|
||||||
using System.IO;
|
using System.Reflection;
|
||||||
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";
|
||||||
|
private static readonly StringComparer StringComparer = StringComparer.InvariantCultureIgnoreCase;
|
||||||
|
[System.Diagnostics.CodeAnalysis.SuppressMessage("Codequalität", "IDE0052:Ungelesene private Member entfernen", Justification = "<Ausstehend>")]
|
||||||
|
private static readonly Object SyncRoot = new Object();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// http://raspberry-pi-guide.readthedocs.io/en/latest/system.html
|
/// Prevents a default instance of the <see cref="SystemInfo"/> class from being created.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class SystemInfo : SingletonBase<SystemInfo>
|
/// <exception cref="NotSupportedException">Could not initialize the GPIO controller</exception>
|
||||||
{
|
private SystemInfo() {
|
||||||
private const string CpuInfoFilePath = "/proc/cpuinfo";
|
#region Obtain and format a property dictionary
|
||||||
private const string MemInfoFilePath = "/proc/meminfo";
|
|
||||||
private const string UptimeFilePath = "/proc/uptime";
|
PropertyInfo[] properties =
|
||||||
private static readonly StringComparer StringComparer = StringComparer.InvariantCultureIgnoreCase;
|
typeof(SystemInfo).GetTypeInfo()
|
||||||
|
.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
|
||||||
private static readonly object SyncRoot = new object();
|
.Where(
|
||||||
|
p =>
|
||||||
/// <summary>
|
p.CanWrite && p.CanRead &&
|
||||||
/// Prevents a default instance of the <see cref="SystemInfo"/> class from being created.
|
(p.PropertyType == typeof(String) || p.PropertyType == typeof(String[])))
|
||||||
/// </summary>
|
.ToArray();
|
||||||
/// <exception cref="NotSupportedException">Could not initialize the GPIO controller</exception>
|
Dictionary<String, PropertyInfo> propDictionary = new Dictionary<String, PropertyInfo>(StringComparer);
|
||||||
private SystemInfo()
|
|
||||||
{
|
foreach(PropertyInfo prop in properties) {
|
||||||
#region Obtain and format a property dictionary
|
propDictionary[prop.Name.Replace(" ", String.Empty).ToLowerInvariant().Trim()] = prop;
|
||||||
|
}
|
||||||
var properties =
|
|
||||||
typeof(SystemInfo).GetTypeInfo()
|
#endregion
|
||||||
.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
|
|
||||||
.Where(
|
#region Extract CPU information
|
||||||
p =>
|
|
||||||
p.CanWrite && p.CanRead &&
|
if(File.Exists(CpuInfoFilePath)) {
|
||||||
(p.PropertyType == typeof(string) || p.PropertyType == typeof(string[])))
|
String[] cpuInfoLines = File.ReadAllLines(CpuInfoFilePath);
|
||||||
.ToArray();
|
|
||||||
var propDictionary = new Dictionary<string, PropertyInfo>(StringComparer);
|
foreach(String line in cpuInfoLines) {
|
||||||
|
String[] lineParts = line.Split(new[] { ':' }, 2);
|
||||||
foreach (var prop in properties)
|
if(lineParts.Length != 2) {
|
||||||
{
|
continue;
|
||||||
propDictionary[prop.Name.Replace(" ", string.Empty).ToLowerInvariant().Trim()] = prop;
|
}
|
||||||
}
|
|
||||||
|
String propertyKey = lineParts[0].Trim().Replace(" ", String.Empty);
|
||||||
#endregion
|
String propertyStringValue = lineParts[1].Trim();
|
||||||
|
|
||||||
#region Extract CPU information
|
if(!propDictionary.ContainsKey(propertyKey)) {
|
||||||
|
continue;
|
||||||
if (File.Exists(CpuInfoFilePath))
|
}
|
||||||
{
|
|
||||||
var cpuInfoLines = File.ReadAllLines(CpuInfoFilePath);
|
PropertyInfo property = propDictionary[propertyKey];
|
||||||
|
if(property.PropertyType == typeof(String)) {
|
||||||
foreach (var line in cpuInfoLines)
|
property.SetValue(this, propertyStringValue);
|
||||||
{
|
} else if(property.PropertyType == typeof(String[])) {
|
||||||
var lineParts = line.Split(new[] { ':' }, 2);
|
String[] propertyArrayAvalue = propertyStringValue.Split(' ');
|
||||||
if (lineParts.Length != 2)
|
property.SetValue(this, propertyArrayAvalue);
|
||||||
continue;
|
}
|
||||||
|
}
|
||||||
var propertyKey = lineParts[0].Trim().Replace(" ", string.Empty);
|
}
|
||||||
var propertyStringValue = lineParts[1].Trim();
|
|
||||||
|
#endregion
|
||||||
if (!propDictionary.ContainsKey(propertyKey)) continue;
|
|
||||||
|
#region Extract Memory Information
|
||||||
var property = propDictionary[propertyKey];
|
|
||||||
if (property.PropertyType == typeof(string))
|
if(File.Exists(MemInfoFilePath)) {
|
||||||
{
|
String[] memInfoLines = File.ReadAllLines(MemInfoFilePath);
|
||||||
property.SetValue(this, propertyStringValue);
|
foreach(String line in memInfoLines) {
|
||||||
}
|
String[] lineParts = line.Split(new[] { ':' }, 2);
|
||||||
else if (property.PropertyType == typeof(string[]))
|
if(lineParts.Length != 2) {
|
||||||
{
|
continue;
|
||||||
var propertyArrayAvalue = propertyStringValue.Split(' ');
|
}
|
||||||
property.SetValue(this, propertyArrayAvalue);
|
|
||||||
}
|
if(lineParts[0].ToLowerInvariant().Trim().Equals("memtotal") == false) {
|
||||||
}
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
String memKb = lineParts[1].ToLowerInvariant().Trim().Replace("kb", String.Empty).Trim();
|
||||||
|
|
||||||
#region Extract Memory Information
|
if(Int32.TryParse(memKb, out Int32 parsedMem)) {
|
||||||
|
this.InstalledRam = parsedMem * 1024;
|
||||||
if (File.Exists(MemInfoFilePath))
|
break;
|
||||||
{
|
}
|
||||||
var memInfoLines = File.ReadAllLines(MemInfoFilePath);
|
}
|
||||||
foreach (var line in memInfoLines)
|
}
|
||||||
{
|
|
||||||
var lineParts = line.Split(new[] { ':' }, 2);
|
#endregion
|
||||||
if (lineParts.Length != 2)
|
|
||||||
continue;
|
#region Board Version and Form Factor
|
||||||
|
|
||||||
if (lineParts[0].ToLowerInvariant().Trim().Equals("memtotal") == false)
|
try {
|
||||||
continue;
|
if(String.IsNullOrWhiteSpace(this.Revision) == false &&
|
||||||
|
Int32.TryParse(
|
||||||
var memKb = lineParts[1].ToLowerInvariant().Trim().Replace("kb", string.Empty).Trim();
|
this.Revision.ToUpperInvariant(),
|
||||||
|
NumberStyles.HexNumber,
|
||||||
if (int.TryParse(memKb, out var parsedMem))
|
CultureInfo.InvariantCulture,
|
||||||
{
|
out Int32 boardVersion)) {
|
||||||
InstalledRam = parsedMem * 1024;
|
this.RaspberryPiVersion = PiVersion.Unknown;
|
||||||
break;
|
if(Enum.GetValues(typeof(PiVersion)).Cast<Int32>().Contains(boardVersion)) {
|
||||||
}
|
this.RaspberryPiVersion = (PiVersion)boardVersion;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
this.WiringPiBoardRevision = WiringPi.PiBoardRev();
|
||||||
|
} catch {
|
||||||
#region Board Version and Form Factor
|
/* Ignore */
|
||||||
|
}
|
||||||
try
|
|
||||||
{
|
#endregion
|
||||||
if (string.IsNullOrWhiteSpace(Revision) == false &&
|
|
||||||
int.TryParse(
|
#region Version Information
|
||||||
Revision.ToUpperInvariant(),
|
|
||||||
NumberStyles.HexNumber,
|
{
|
||||||
CultureInfo.InvariantCulture,
|
String[] libParts = WiringPi.WiringPiLibrary.Split('.');
|
||||||
out var boardVersion))
|
Int32 major = Int32.Parse(libParts[libParts.Length - 2]);
|
||||||
{
|
Int32 minor = Int32.Parse(libParts[libParts.Length - 1]);
|
||||||
RaspberryPiVersion = PiVersion.Unknown;
|
Version version = new Version(major, minor);
|
||||||
if (Enum.GetValues(typeof(PiVersion)).Cast<int>().Contains(boardVersion))
|
this.WiringPiVersion = version;
|
||||||
{
|
}
|
||||||
RaspberryPiVersion = (PiVersion)boardVersion;
|
|
||||||
}
|
#endregion
|
||||||
}
|
|
||||||
|
#region Extract OS Info
|
||||||
WiringPiBoardRevision = WiringPi.PiBoardRev();
|
|
||||||
}
|
try {
|
||||||
catch
|
_ = Standard.Uname(out SystemName unameInfo);
|
||||||
{
|
this.OperatingSystem = new OsInfo {
|
||||||
/* Ignore */
|
DomainName = unameInfo.DomainName,
|
||||||
}
|
Machine = unameInfo.Machine,
|
||||||
|
NodeName = unameInfo.NodeName,
|
||||||
#endregion
|
Release = unameInfo.Release,
|
||||||
|
SysName = unameInfo.SysName,
|
||||||
#region Version Information
|
Version = unameInfo.Version
|
||||||
|
};
|
||||||
{
|
} catch {
|
||||||
var libParts = WiringPi.WiringPiLibrary.Split('.');
|
this.OperatingSystem = new OsInfo();
|
||||||
var major = int.Parse(libParts[libParts.Length - 2]);
|
}
|
||||||
var minor = int.Parse(libParts[libParts.Length - 1]);
|
|
||||||
var version = new Version(major, minor);
|
#endregion
|
||||||
WiringPiVersion = version;
|
}
|
||||||
}
|
|
||||||
|
/// <summary>
|
||||||
#endregion
|
/// Gets the wiring pi library version.
|
||||||
|
/// </summary>
|
||||||
#region Extract OS Info
|
public Version WiringPiVersion {
|
||||||
|
get;
|
||||||
try
|
}
|
||||||
{
|
|
||||||
Standard.Uname(out var unameInfo);
|
/// <summary>
|
||||||
OperatingSystem = new OsInfo
|
/// Gets the OS information.
|
||||||
{
|
/// </summary>
|
||||||
DomainName = unameInfo.DomainName,
|
/// <value>
|
||||||
Machine = unameInfo.Machine,
|
/// The os information.
|
||||||
NodeName = unameInfo.NodeName,
|
/// </value>
|
||||||
Release = unameInfo.Release,
|
public OsInfo OperatingSystem {
|
||||||
SysName = unameInfo.SysName,
|
get;
|
||||||
Version = unameInfo.Version
|
}
|
||||||
};
|
|
||||||
}
|
/// <summary>
|
||||||
catch
|
/// Gets the Raspberry Pi version.
|
||||||
{
|
/// </summary>
|
||||||
OperatingSystem = new OsInfo();
|
public PiVersion RaspberryPiVersion {
|
||||||
}
|
get;
|
||||||
|
}
|
||||||
#endregion
|
|
||||||
}
|
/// <summary>
|
||||||
|
/// Gets the Wiring Pi board revision (1 or 2).
|
||||||
/// <summary>
|
/// </summary>
|
||||||
/// Gets the wiring pi library version.
|
/// <value>
|
||||||
/// </summary>
|
/// The wiring pi board revision.
|
||||||
public Version WiringPiVersion { get; }
|
/// </value>
|
||||||
|
public Int32 WiringPiBoardRevision {
|
||||||
/// <summary>
|
get;
|
||||||
/// Gets the OS information.
|
}
|
||||||
/// </summary>
|
|
||||||
/// <value>
|
/// <summary>
|
||||||
/// The os information.
|
/// Gets the number of processor cores.
|
||||||
/// </value>
|
/// </summary>
|
||||||
public OsInfo OperatingSystem { get; }
|
public Int32 ProcessorCount => Int32.TryParse(this.Processor, out Int32 outIndex) ? outIndex + 1 : 0;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the Raspberry Pi version.
|
/// Gets the installed ram in bytes.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public PiVersion RaspberryPiVersion { get; }
|
public Int32 InstalledRam {
|
||||||
|
get;
|
||||||
/// <summary>
|
}
|
||||||
/// Gets the Wiring Pi board revision (1 or 2).
|
|
||||||
/// </summary>
|
/// <summary>
|
||||||
/// <value>
|
/// Gets a value indicating whether this CPU is little endian.
|
||||||
/// The wiring pi board revision.
|
/// </summary>
|
||||||
/// </value>
|
public Boolean IsLittleEndian => BitConverter.IsLittleEndian;
|
||||||
public int WiringPiBoardRevision { get; }
|
|
||||||
|
/// <summary>
|
||||||
/// <summary>
|
/// Gets the CPU model name.
|
||||||
/// Gets the number of processor cores.
|
/// </summary>
|
||||||
/// </summary>
|
public String ModelName {
|
||||||
public int ProcessorCount
|
get; private set;
|
||||||
{
|
}
|
||||||
get
|
|
||||||
{
|
/// <summary>
|
||||||
if (int.TryParse(Processor, out var outIndex))
|
/// Gets a list of supported CPU features.
|
||||||
{
|
/// </summary>
|
||||||
return outIndex + 1;
|
public String[] Features {
|
||||||
}
|
get; private set;
|
||||||
|
}
|
||||||
return 0;
|
|
||||||
}
|
/// <summary>
|
||||||
}
|
/// Gets the CPU implementer hex code.
|
||||||
|
/// </summary>
|
||||||
/// <summary>
|
public String CpuImplementer {
|
||||||
/// Gets the installed ram in bytes.
|
get; private set;
|
||||||
/// </summary>
|
}
|
||||||
public int InstalledRam { get; }
|
|
||||||
|
/// <summary>
|
||||||
/// <summary>
|
/// Gets the CPU architecture code.
|
||||||
/// Gets a value indicating whether this CPU is little endian.
|
/// </summary>
|
||||||
/// </summary>
|
public String CpuArchitecture {
|
||||||
public bool IsLittleEndian => BitConverter.IsLittleEndian;
|
get; private set;
|
||||||
|
}
|
||||||
/// <summary>
|
|
||||||
/// Gets the CPU model name.
|
/// <summary>
|
||||||
/// </summary>
|
/// Gets the CPU variant code.
|
||||||
public string ModelName { get; private set; }
|
/// </summary>
|
||||||
|
public String CpuVariant {
|
||||||
/// <summary>
|
get; private set;
|
||||||
/// Gets a list of supported CPU features.
|
}
|
||||||
/// </summary>
|
|
||||||
public string[] Features { get; private set; }
|
/// <summary>
|
||||||
|
/// Gets the CPU part code.
|
||||||
/// <summary>
|
/// </summary>
|
||||||
/// Gets the CPU implementer hex code.
|
public String CpuPart {
|
||||||
/// </summary>
|
get; private set;
|
||||||
public string CpuImplementer { get; private set; }
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the CPU architecture code.
|
/// Gets the CPU revision code.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string CpuArchitecture { get; private set; }
|
public String CpuRevision {
|
||||||
|
get; private set;
|
||||||
/// <summary>
|
}
|
||||||
/// Gets the CPU variant code.
|
|
||||||
/// </summary>
|
/// <summary>
|
||||||
public string CpuVariant { get; private set; }
|
/// Gets the hardware model number.
|
||||||
|
/// </summary>
|
||||||
/// <summary>
|
public String Hardware {
|
||||||
/// Gets the CPU part code.
|
get; private set;
|
||||||
/// </summary>
|
}
|
||||||
public string CpuPart { get; private set; }
|
|
||||||
|
/// <summary>
|
||||||
/// <summary>
|
/// Gets the hardware revision number.
|
||||||
/// Gets the CPU revision code.
|
/// </summary>
|
||||||
/// </summary>
|
public String Revision {
|
||||||
public string CpuRevision { get; private set; }
|
get; private set;
|
||||||
|
}
|
||||||
/// <summary>
|
|
||||||
/// Gets the hardware model number.
|
/// <summary>
|
||||||
/// </summary>
|
/// Gets the serial number.
|
||||||
public string Hardware { get; private set; }
|
/// </summary>
|
||||||
|
public String Serial {
|
||||||
/// <summary>
|
get; private set;
|
||||||
/// Gets the hardware revision number.
|
}
|
||||||
/// </summary>
|
|
||||||
public string Revision { get; private set; }
|
/// <summary>
|
||||||
|
/// Gets the system uptime (in seconds).
|
||||||
/// <summary>
|
/// </summary>
|
||||||
/// Gets the serial number.
|
public Double Uptime {
|
||||||
/// </summary>
|
get {
|
||||||
public string Serial { get; private set; }
|
try {
|
||||||
|
if(File.Exists(UptimeFilePath) == false) {
|
||||||
/// <summary>
|
return 0;
|
||||||
/// Gets the system uptime (in seconds).
|
}
|
||||||
/// </summary>
|
|
||||||
public double Uptime
|
String[] parts = File.ReadAllText(UptimeFilePath).Trim().Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
|
||||||
{
|
if(parts.Length >= 1 && Single.TryParse(parts[0], out Single result)) {
|
||||||
get
|
return result;
|
||||||
{
|
}
|
||||||
try
|
} catch {
|
||||||
{
|
/* Ignore */
|
||||||
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))
|
return 0;
|
||||||
return result;
|
}
|
||||||
}
|
}
|
||||||
catch
|
|
||||||
{
|
/// <summary>
|
||||||
/* Ignore */
|
/// Gets the uptime in TimeSpan.
|
||||||
}
|
/// </summary>
|
||||||
|
public TimeSpan UptimeTimeSpan => TimeSpan.FromSeconds(this.Uptime);
|
||||||
return 0;
|
|
||||||
}
|
/// <summary>
|
||||||
}
|
/// Placeholder for processor index
|
||||||
|
/// </summary>
|
||||||
/// <summary>
|
private String Processor {
|
||||||
/// Gets the uptime in TimeSpan.
|
get; set;
|
||||||
/// </summary>
|
}
|
||||||
public TimeSpan UptimeTimeSpan => TimeSpan.FromSeconds(Uptime);
|
|
||||||
|
/// <summary>
|
||||||
/// <summary>
|
/// Returns a <see cref="String" /> that represents this instance.
|
||||||
/// Placeholder for processor index
|
/// </summary>
|
||||||
/// </summary>
|
/// <returns>
|
||||||
private string Processor { get; set; }
|
/// A <see cref="String" /> that represents this instance.
|
||||||
|
/// </returns>
|
||||||
/// <summary>
|
public override String ToString() {
|
||||||
/// Returns a <see cref="string" /> that represents this instance.
|
PropertyInfo[] properties = typeof(SystemInfo).GetTypeInfo().GetProperties(BindingFlags.Instance | BindingFlags.Public)
|
||||||
/// </summary>
|
.Where(p => p.CanRead && (
|
||||||
/// <returns>
|
p.PropertyType == typeof(String) ||
|
||||||
/// A <see cref="string" /> that represents this instance.
|
p.PropertyType == typeof(String[]) ||
|
||||||
/// </returns>
|
p.PropertyType == typeof(Int32) ||
|
||||||
public override string ToString()
|
p.PropertyType == typeof(Boolean) ||
|
||||||
{
|
p.PropertyType == typeof(TimeSpan)))
|
||||||
var properties = typeof(SystemInfo).GetTypeInfo().GetProperties(BindingFlags.Instance | BindingFlags.Public)
|
.ToArray();
|
||||||
.Where(p => p.CanRead && (
|
|
||||||
p.PropertyType == typeof(string) ||
|
List<String> properyValues = new List<String>
|
||||||
p.PropertyType == typeof(string[]) ||
|
{
|
||||||
p.PropertyType == typeof(int) ||
|
|
||||||
p.PropertyType == typeof(bool) ||
|
|
||||||
p.PropertyType == typeof(TimeSpan)))
|
|
||||||
.ToArray();
|
|
||||||
|
|
||||||
var properyValues = new List<string>
|
|
||||||
{
|
|
||||||
"System Information",
|
"System Information",
|
||||||
$"\t{nameof(WiringPiVersion),-22}: {WiringPiVersion}",
|
$"\t{nameof(this.WiringPiVersion),-22}: {this.WiringPiVersion}",
|
||||||
$"\t{nameof(RaspberryPiVersion),-22}: {RaspberryPiVersion}"
|
$"\t{nameof(this.RaspberryPiVersion),-22}: {this.RaspberryPiVersion}"
|
||||||
};
|
};
|
||||||
|
|
||||||
foreach (var property in properties)
|
foreach(PropertyInfo property in properties) {
|
||||||
{
|
if(property.PropertyType != typeof(String[])) {
|
||||||
if (property.PropertyType != typeof(string[]))
|
properyValues.Add($"\t{property.Name,-22}: {property.GetValue(this)}");
|
||||||
{
|
} else if(property.GetValue(this) is String[] allValues) {
|
||||||
properyValues.Add($"\t{property.Name,-22}: {property.GetValue(this)}");
|
String concatValues = String.Join(" ", allValues);
|
||||||
}
|
properyValues.Add($"\t{property.Name,-22}: {concatValues}");
|
||||||
else if (property.GetValue(this) is string[] allValues)
|
}
|
||||||
{
|
}
|
||||||
var concatValues = string.Join(" ", allValues);
|
|
||||||
properyValues.Add($"\t{property.Name,-22}: {concatValues}");
|
return String.Join(Environment.NewLine, properyValues.ToArray());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return string.Join(Environment.NewLine, properyValues.ToArray());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -1,23 +1,29 @@
|
|||||||
namespace Unosquare.RaspberryIO.Computer
|
using System;
|
||||||
{
|
|
||||||
|
namespace Unosquare.RaspberryIO.Computer {
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a wireless network information
|
||||||
|
/// </summary>
|
||||||
|
public class WirelessNetworkInfo {
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a wireless network information
|
/// Gets the ESSID of the Wireless network.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class WirelessNetworkInfo
|
public String Name {
|
||||||
{
|
get; internal set;
|
||||||
/// <summary>
|
}
|
||||||
/// Gets the ESSID of the Wireless network.
|
|
||||||
/// </summary>
|
/// <summary>
|
||||||
public string Name { get; internal set; }
|
/// Gets the network quality.
|
||||||
|
/// </summary>
|
||||||
/// <summary>
|
public String Quality {
|
||||||
/// Gets the network quality.
|
get; internal set;
|
||||||
/// </summary>
|
}
|
||||||
public string Quality { get; internal set; }
|
|
||||||
|
/// <summary>
|
||||||
/// <summary>
|
/// Gets a value indicating whether this instance is encrypted.
|
||||||
/// Gets a value indicating whether this instance is encrypted.
|
/// </summary>
|
||||||
/// </summary>
|
public Boolean IsEncrypted {
|
||||||
public bool IsEncrypted { get; internal set; }
|
get; internal set;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,201 +1,167 @@
|
|||||||
namespace Unosquare.RaspberryIO.Gpio
|
using System;
|
||||||
{
|
|
||||||
using System;
|
namespace Unosquare.RaspberryIO.Gpio {
|
||||||
|
public partial class GpioPin {
|
||||||
public partial class GpioPin
|
#region Static Pin Definitions
|
||||||
{
|
|
||||||
#region Static Pin Definitions
|
internal static readonly Lazy<GpioPin> Pin08 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin08, 3) {
|
||||||
|
Capabilities = new[] { PinCapability.GP, PinCapability.I2CSDA },
|
||||||
internal static readonly Lazy<GpioPin> Pin08 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin08, 3)
|
Name = "BCM 2 (SDA)"
|
||||||
{
|
});
|
||||||
Capabilities = new[] { PinCapability.GP, PinCapability.I2CSDA },
|
|
||||||
Name = "BCM 2 (SDA)"
|
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> Pin09 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin09, 5)
|
});
|
||||||
{
|
|
||||||
Capabilities = new[] { PinCapability.GP, PinCapability.I2CSCL },
|
internal static readonly Lazy<GpioPin> Pin07 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin07, 7) {
|
||||||
Name = "BCM 3 (SCL)"
|
Capabilities = new[] { PinCapability.GP, PinCapability.GPCLK },
|
||||||
});
|
Name = "BCM 4 (GPCLK0)"
|
||||||
|
});
|
||||||
internal static readonly Lazy<GpioPin> Pin07 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin07, 7)
|
|
||||||
{
|
internal static readonly Lazy<GpioPin> Pin00 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin00, 11) {
|
||||||
Capabilities = new[] { PinCapability.GP, PinCapability.GPCLK },
|
Capabilities = new[] { PinCapability.GP, PinCapability.UARTRTS },
|
||||||
Name = "BCM 4 (GPCLK0)"
|
Name = "BCM 17"
|
||||||
});
|
});
|
||||||
|
|
||||||
internal static readonly Lazy<GpioPin> Pin00 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin00, 11)
|
internal static readonly Lazy<GpioPin> Pin02 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin02, 13) {
|
||||||
{
|
Capabilities = new[] { PinCapability.GP },
|
||||||
Capabilities = new[] { PinCapability.GP, PinCapability.UARTRTS },
|
Name = "BCM 27"
|
||||||
Name = "BCM 17"
|
});
|
||||||
});
|
|
||||||
|
internal static readonly Lazy<GpioPin> Pin03 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin03, 15) {
|
||||||
internal static readonly Lazy<GpioPin> Pin02 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin02, 13)
|
Capabilities = new[] { PinCapability.GP },
|
||||||
{
|
Name = "BCM 22"
|
||||||
Capabilities = new[] { PinCapability.GP },
|
});
|
||||||
Name = "BCM 27"
|
|
||||||
});
|
internal static readonly Lazy<GpioPin> Pin12 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin12, 19) {
|
||||||
|
Capabilities = new[] { PinCapability.GP, PinCapability.SPIMOSI },
|
||||||
internal static readonly Lazy<GpioPin> Pin03 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin03, 15)
|
Name = "BCM 10 (MOSI)"
|
||||||
{
|
});
|
||||||
Capabilities = new[] { PinCapability.GP },
|
|
||||||
Name = "BCM 22"
|
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> Pin12 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin12, 19)
|
});
|
||||||
{
|
|
||||||
Capabilities = new[] { PinCapability.GP, PinCapability.SPIMOSI },
|
internal static readonly Lazy<GpioPin> Pin14 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin14, 23) {
|
||||||
Name = "BCM 10 (MOSI)"
|
Capabilities = new[] { PinCapability.GP, PinCapability.SPICLK },
|
||||||
});
|
Name = "BCM 11 (SCLCK)"
|
||||||
|
});
|
||||||
internal static readonly Lazy<GpioPin> Pin13 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin13, 21)
|
|
||||||
{
|
internal static readonly Lazy<GpioPin> Pin30 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin30, 27) {
|
||||||
Capabilities = new[] { PinCapability.GP, PinCapability.SPIMISO },
|
Capabilities = new[] { PinCapability.I2CSDA },
|
||||||
Name = "BCM 9 (MISO)"
|
Name = "BCM 0 (ID_SD)"
|
||||||
});
|
});
|
||||||
|
|
||||||
internal static readonly Lazy<GpioPin> Pin14 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin14, 23)
|
internal static readonly Lazy<GpioPin> Pin31 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin31, 28) {
|
||||||
{
|
Capabilities = new[] { PinCapability.I2CSCL },
|
||||||
Capabilities = new[] { PinCapability.GP, PinCapability.SPICLK },
|
Name = "BCM 1 (ID_SC)"
|
||||||
Name = "BCM 11 (SCLCK)"
|
});
|
||||||
});
|
|
||||||
|
internal static readonly Lazy<GpioPin> Pin11 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin11, 26) {
|
||||||
internal static readonly Lazy<GpioPin> Pin30 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin30, 27)
|
Capabilities = new[] { PinCapability.GP, PinCapability.SPICS },
|
||||||
{
|
Name = "BCM 7 (CE1)"
|
||||||
Capabilities = new[] { PinCapability.I2CSDA },
|
});
|
||||||
Name = "BCM 0 (ID_SD)"
|
|
||||||
});
|
internal static readonly Lazy<GpioPin> Pin10 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin10, 24) {
|
||||||
|
Capabilities = new[] { PinCapability.GP, PinCapability.SPICS },
|
||||||
internal static readonly Lazy<GpioPin> Pin31 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin31, 28)
|
Name = "BCM 8 (CE0)"
|
||||||
{
|
});
|
||||||
Capabilities = new[] { PinCapability.I2CSCL },
|
|
||||||
Name = "BCM 1 (ID_SC)"
|
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> Pin11 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin11, 26)
|
});
|
||||||
{
|
internal static readonly Lazy<GpioPin> Pin05 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin05, 18) {
|
||||||
Capabilities = new[] { PinCapability.GP, PinCapability.SPICS },
|
Capabilities = new[] { PinCapability.GP },
|
||||||
Name = "BCM 7 (CE1)"
|
Name = "BCM 24"
|
||||||
});
|
});
|
||||||
|
|
||||||
internal static readonly Lazy<GpioPin> Pin10 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin10, 24)
|
internal static readonly Lazy<GpioPin> Pin04 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin04, 16) {
|
||||||
{
|
Capabilities = new[] { PinCapability.GP },
|
||||||
Capabilities = new[] { PinCapability.GP, PinCapability.SPICS },
|
Name = "BCM 23"
|
||||||
Name = "BCM 8 (CE0)"
|
});
|
||||||
});
|
|
||||||
|
internal static readonly Lazy<GpioPin> Pin01 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin01, 12) {
|
||||||
internal static readonly Lazy<GpioPin> Pin06 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin06, 22)
|
Capabilities = new[] { PinCapability.GP, PinCapability.PWM },
|
||||||
{
|
Name = "BCM 18 (PWM0)"
|
||||||
Capabilities = new[] { PinCapability.GP },
|
});
|
||||||
Name = "BCM 25"
|
|
||||||
});
|
internal static readonly Lazy<GpioPin> Pin16 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin16, 10) {
|
||||||
internal static readonly Lazy<GpioPin> Pin05 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin05, 18)
|
Capabilities = new[] { PinCapability.UARTRXD },
|
||||||
{
|
Name = "BCM 15 (RXD)"
|
||||||
Capabilities = new[] { PinCapability.GP },
|
});
|
||||||
Name = "BCM 24"
|
|
||||||
});
|
internal static readonly Lazy<GpioPin> Pin15 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin15, 8) {
|
||||||
|
Capabilities = new[] { PinCapability.UARTTXD },
|
||||||
internal static readonly Lazy<GpioPin> Pin04 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin04, 16)
|
Name = "BCM 14 (TXD)"
|
||||||
{
|
});
|
||||||
Capabilities = new[] { PinCapability.GP },
|
|
||||||
Name = "BCM 23"
|
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> Pin01 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin01, 12)
|
});
|
||||||
{
|
|
||||||
Capabilities = new[] { PinCapability.GP, PinCapability.PWM },
|
internal static readonly Lazy<GpioPin> Pin22 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin22, 31) {
|
||||||
Name = "BCM 18 (PWM0)"
|
Capabilities = new[] { PinCapability.GP },
|
||||||
});
|
Name = "BCM 6"
|
||||||
|
});
|
||||||
internal static readonly Lazy<GpioPin> Pin16 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin16, 10)
|
|
||||||
{
|
internal static readonly Lazy<GpioPin> Pin23 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin23, 33) {
|
||||||
Capabilities = new[] { PinCapability.UARTRXD },
|
Capabilities = new[] { PinCapability.GP, PinCapability.PWM },
|
||||||
Name = "BCM 15 (RXD)"
|
Name = "BCM 13 (PWM1)"
|
||||||
});
|
});
|
||||||
|
|
||||||
internal static readonly Lazy<GpioPin> Pin15 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin15, 8)
|
internal static readonly Lazy<GpioPin> Pin24 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin24, 35) {
|
||||||
{
|
Capabilities = new[] { PinCapability.GP, PinCapability.SPIMISO },
|
||||||
Capabilities = new[] { PinCapability.UARTTXD },
|
Name = "BCM 19 (MISO)"
|
||||||
Name = "BCM 14 (TXD)"
|
});
|
||||||
});
|
|
||||||
|
internal static readonly Lazy<GpioPin> Pin25 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin25, 37) {
|
||||||
internal static readonly Lazy<GpioPin> Pin21 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin21, 29)
|
Capabilities = new[] { PinCapability.GP },
|
||||||
{
|
Name = "BCM 26"
|
||||||
Capabilities = new[] { PinCapability.GP },
|
});
|
||||||
Name = "BCM 5"
|
|
||||||
});
|
internal static readonly Lazy<GpioPin> Pin29 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin29, 40) {
|
||||||
|
Capabilities = new[] { PinCapability.GP, PinCapability.SPICLK },
|
||||||
internal static readonly Lazy<GpioPin> Pin22 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin22, 31)
|
Name = "BCM 21 (SCLK)"
|
||||||
{
|
});
|
||||||
Capabilities = new[] { PinCapability.GP },
|
|
||||||
Name = "BCM 6"
|
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> Pin23 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin23, 33)
|
});
|
||||||
{
|
|
||||||
Capabilities = new[] { PinCapability.GP, PinCapability.PWM },
|
internal static readonly Lazy<GpioPin> Pin27 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin27, 36) {
|
||||||
Name = "BCM 13 (PWM1)"
|
Capabilities = new[] { PinCapability.GP },
|
||||||
});
|
Name = "BCM 16"
|
||||||
|
});
|
||||||
internal static readonly Lazy<GpioPin> Pin24 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin24, 35)
|
internal static readonly Lazy<GpioPin> Pin26 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin26, 32) {
|
||||||
{
|
Capabilities = new[] { PinCapability.GP },
|
||||||
Capabilities = new[] { PinCapability.GP, PinCapability.SPIMISO },
|
Name = "BCM 12 (PWM0)"
|
||||||
Name = "BCM 19 (MISO)"
|
});
|
||||||
});
|
|
||||||
|
internal static readonly Lazy<GpioPin> Pin17 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin17, 3) {
|
||||||
internal static readonly Lazy<GpioPin> Pin25 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin25, 37)
|
Capabilities = new[] { PinCapability.GP, PinCapability.I2CSDA },
|
||||||
{
|
Name = "BCM 28 (SDA)"
|
||||||
Capabilities = new[] { PinCapability.GP },
|
});
|
||||||
Name = "BCM 26"
|
|
||||||
});
|
internal static readonly Lazy<GpioPin> Pin18 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin18, 4) {
|
||||||
|
Capabilities = new[] { PinCapability.GP, PinCapability.I2CSCL },
|
||||||
internal static readonly Lazy<GpioPin> Pin29 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin29, 40)
|
Name = "BCM 29 (SCL)"
|
||||||
{
|
});
|
||||||
Capabilities = new[] { PinCapability.GP, PinCapability.SPICLK },
|
|
||||||
Name = "BCM 21 (SCLK)"
|
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> Pin28 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin28, 38)
|
});
|
||||||
{
|
|
||||||
Capabilities = new[] { PinCapability.GP, PinCapability.SPIMOSI },
|
internal static readonly Lazy<GpioPin> Pin20 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin20, 6) {
|
||||||
Name = "BCM 20 (MOSI)"
|
Capabilities = new[] { PinCapability.GP },
|
||||||
});
|
Name = "BCM 31"
|
||||||
|
});
|
||||||
internal static readonly Lazy<GpioPin> Pin27 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin27, 36)
|
|
||||||
{
|
#endregion
|
||||||
Capabilities = new[] { PinCapability.GP },
|
}
|
||||||
Name = "BCM 16"
|
|
||||||
});
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
Capabilities = new[] { PinCapability.GP, PinCapability.I2CSDA },
|
|
||||||
Name = "BCM 28 (SDA)"
|
|
||||||
});
|
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
Capabilities = new[] { PinCapability.GP },
|
|
||||||
Name = "BCM 30"
|
|
||||||
});
|
|
||||||
|
|
||||||
internal static readonly Lazy<GpioPin> Pin20 = new Lazy<GpioPin>(() => new GpioPin(WiringPiPin.Pin20, 6)
|
|
||||||
{
|
|
||||||
Capabilities = new[] { PinCapability.GP },
|
|
||||||
Name = "BCM 31"
|
|
||||||
});
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,93 +1,87 @@
|
|||||||
namespace Unosquare.RaspberryIO.Gpio
|
using Unosquare.RaspberryIO.Native;
|
||||||
{
|
using Unosquare.Swan.Abstractions;
|
||||||
using Native;
|
using System.Collections.Generic;
|
||||||
using Swan.Abstractions;
|
using System.Collections.ObjectModel;
|
||||||
using System.Collections.Generic;
|
using System.Linq;
|
||||||
using System.Collections.ObjectModel;
|
using System;
|
||||||
using System.Linq;
|
|
||||||
|
namespace Unosquare.RaspberryIO.Gpio {
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A simple wrapper for the I2c bus on the Raspberry Pi
|
/// A simple wrapper for the I2c bus on the Raspberry Pi
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class I2CBus : SingletonBase<I2CBus>
|
public class I2CBus : SingletonBase<I2CBus> {
|
||||||
{
|
// TODO: It would be nice to integrate i2c device detection.
|
||||||
// TODO: It would be nice to integrate i2c device detection.
|
private static readonly Object SyncRoot = new Object();
|
||||||
private static readonly object SyncRoot = new object();
|
private readonly Dictionary<Int32, I2CDevice> _devices = new Dictionary<Int32, I2CDevice>();
|
||||||
private readonly Dictionary<int, I2CDevice> _devices = new Dictionary<int, I2CDevice>();
|
|
||||||
|
/// <summary>
|
||||||
/// <summary>
|
/// Prevents a default instance of the <see cref="I2CBus"/> class from being created.
|
||||||
/// Prevents a default instance of the <see cref="I2CBus"/> class from being created.
|
/// </summary>
|
||||||
/// </summary>
|
private I2CBus() {
|
||||||
private I2CBus()
|
// placeholder
|
||||||
{
|
}
|
||||||
// placeholder
|
|
||||||
}
|
/// <summary>
|
||||||
|
/// Gets the registered devices as a read only collection.
|
||||||
/// <summary>
|
/// </summary>
|
||||||
/// Gets the registered devices as a read only collection.
|
public ReadOnlyCollection<I2CDevice> Devices => new ReadOnlyCollection<I2CDevice>(this._devices.Values.ToArray());
|
||||||
/// </summary>
|
|
||||||
public ReadOnlyCollection<I2CDevice> Devices => new ReadOnlyCollection<I2CDevice>(_devices.Values.ToArray());
|
/// <summary>
|
||||||
|
/// Gets the <see cref="I2CDevice"/> with the specified device identifier.
|
||||||
/// <summary>
|
/// </summary>
|
||||||
/// Gets the <see cref="I2CDevice"/> with the specified device identifier.
|
/// <value>
|
||||||
/// </summary>
|
/// The <see cref="I2CDevice"/>.
|
||||||
/// <value>
|
/// </value>
|
||||||
/// The <see cref="I2CDevice"/>.
|
/// <param name="deviceId">The device identifier.</param>
|
||||||
/// </value>
|
/// <returns>A reference to an I2C device</returns>
|
||||||
/// <param name="deviceId">The device identifier.</param>
|
public I2CDevice this[Int32 deviceId] => this.GetDeviceById(deviceId);
|
||||||
/// <returns>A reference to an I2C device</returns>
|
|
||||||
public I2CDevice this[int deviceId] => GetDeviceById(deviceId);
|
/// <summary>
|
||||||
|
/// Gets the device by identifier.
|
||||||
/// <summary>
|
/// </summary>
|
||||||
/// Gets the device by identifier.
|
/// <param name="deviceId">The device identifier.</param>
|
||||||
/// </summary>
|
/// <returns>The device reference</returns>
|
||||||
/// <param name="deviceId">The device identifier.</param>
|
public I2CDevice GetDeviceById(Int32 deviceId) {
|
||||||
/// <returns>The device reference</returns>
|
lock(SyncRoot) {
|
||||||
public I2CDevice GetDeviceById(int deviceId)
|
return this._devices[deviceId];
|
||||||
{
|
}
|
||||||
lock (SyncRoot)
|
}
|
||||||
{
|
|
||||||
return _devices[deviceId];
|
/// <summary>
|
||||||
}
|
/// Adds a device to the bus by its Id. If the device is already registered it simply returns the existing device.
|
||||||
}
|
/// </summary>
|
||||||
|
/// <param name="deviceId">The device identifier.</param>
|
||||||
/// <summary>
|
/// <returns>The device reference</returns>
|
||||||
/// Adds a device to the bus by its Id. If the device is already registered it simply returns the existing device.
|
/// <exception cref="KeyNotFoundException">When the device file descriptor is not found</exception>
|
||||||
/// </summary>
|
public I2CDevice AddDevice(Int32 deviceId) {
|
||||||
/// <param name="deviceId">The device identifier.</param>
|
lock(SyncRoot) {
|
||||||
/// <returns>The device reference</returns>
|
if(this._devices.ContainsKey(deviceId)) {
|
||||||
/// <exception cref="KeyNotFoundException">When the device file descriptor is not found</exception>
|
return this._devices[deviceId];
|
||||||
public I2CDevice AddDevice(int deviceId)
|
}
|
||||||
{
|
|
||||||
lock (SyncRoot)
|
Int32 fileDescriptor = SetupFileDescriptor(deviceId);
|
||||||
{
|
if(fileDescriptor < 0) {
|
||||||
if (_devices.ContainsKey(deviceId))
|
throw new KeyNotFoundException($"Device with id {deviceId} could not be registered with the I2C bus. Error Code: {fileDescriptor}.");
|
||||||
return _devices[deviceId];
|
}
|
||||||
|
|
||||||
var fileDescriptor = SetupFileDescriptor(deviceId);
|
I2CDevice device = new I2CDevice(deviceId, fileDescriptor);
|
||||||
if (fileDescriptor < 0)
|
this._devices[deviceId] = device;
|
||||||
throw new KeyNotFoundException($"Device with id {deviceId} could not be registered with the I2C bus. Error Code: {fileDescriptor}.");
|
return device;
|
||||||
|
}
|
||||||
var device = new I2CDevice(deviceId, fileDescriptor);
|
}
|
||||||
_devices[deviceId] = device;
|
|
||||||
return device;
|
/// <summary>
|
||||||
}
|
/// This initializes the I2C system with your given device identifier.
|
||||||
}
|
/// The ID is the I2C number of the device and you can use the i2cdetect program to find this out.
|
||||||
|
/// wiringPiI2CSetup() will work out which revision Raspberry Pi you have and open the appropriate device in /dev.
|
||||||
/// <summary>
|
/// The return value is the standard Linux filehandle, or -1 if any error – in which case, you can consult errno as usual.
|
||||||
/// This initializes the I2C system with your given device identifier.
|
/// </summary>
|
||||||
/// The ID is the I2C number of the device and you can use the i2cdetect program to find this out.
|
/// <param name="deviceId">The device identifier.</param>
|
||||||
/// wiringPiI2CSetup() will work out which revision Raspberry Pi you have and open the appropriate device in /dev.
|
/// <returns>The Linux file handle</returns>
|
||||||
/// The return value is the standard Linux filehandle, or -1 if any error – in which case, you can consult errno as usual.
|
private static Int32 SetupFileDescriptor(Int32 deviceId) {
|
||||||
/// </summary>
|
lock(SyncRoot) {
|
||||||
/// <param name="deviceId">The device identifier.</param>
|
return WiringPi.WiringPiI2CSetup(deviceId);
|
||||||
/// <returns>The Linux file handle</returns>
|
}
|
||||||
private static int SetupFileDescriptor(int deviceId)
|
}
|
||||||
{
|
}
|
||||||
lock (SyncRoot)
|
}
|
||||||
{
|
|
||||||
return WiringPi.WiringPiI2CSetup(deviceId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -1,195 +1,193 @@
|
|||||||
namespace Unosquare.RaspberryIO.Gpio
|
using System;
|
||||||
{
|
using System.Threading.Tasks;
|
||||||
using System;
|
using Unosquare.RaspberryIO.Native;
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Native;
|
namespace Unosquare.RaspberryIO.Gpio {
|
||||||
|
/// <summary>
|
||||||
/// <summary>
|
/// Represents a device on the I2C Bus
|
||||||
/// Represents a device on the I2C Bus
|
/// </summary>
|
||||||
/// </summary>
|
public class I2CDevice {
|
||||||
public class I2CDevice
|
private readonly Object _syncLock = new Object();
|
||||||
{
|
|
||||||
private readonly object _syncLock = new object();
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="I2CDevice"/> class.
|
||||||
/// <summary>
|
/// </summary>
|
||||||
/// Initializes a new instance of the <see cref="I2CDevice"/> class.
|
/// <param name="deviceId">The device identifier.</param>
|
||||||
/// </summary>
|
/// <param name="fileDescriptor">The file descriptor.</param>
|
||||||
/// <param name="deviceId">The device identifier.</param>
|
internal I2CDevice(Int32 deviceId, Int32 fileDescriptor) {
|
||||||
/// <param name="fileDescriptor">The file descriptor.</param>
|
this.DeviceId = deviceId;
|
||||||
internal I2CDevice(int deviceId, int fileDescriptor)
|
this.FileDescriptor = fileDescriptor;
|
||||||
{
|
}
|
||||||
DeviceId = deviceId;
|
|
||||||
FileDescriptor = fileDescriptor;
|
/// <summary>
|
||||||
}
|
/// Gets the device identifier.
|
||||||
|
/// </summary>
|
||||||
/// <summary>
|
/// <value>
|
||||||
/// Gets the device identifier.
|
/// The device identifier.
|
||||||
/// </summary>
|
/// </value>
|
||||||
/// <value>
|
public Int32 DeviceId {
|
||||||
/// The device identifier.
|
get;
|
||||||
/// </value>
|
}
|
||||||
public int DeviceId { get; }
|
|
||||||
|
/// <summary>
|
||||||
/// <summary>
|
/// Gets the standard POSIX file descriptor.
|
||||||
/// Gets the standard POSIX file descriptor.
|
/// </summary>
|
||||||
/// </summary>
|
/// <value>
|
||||||
/// <value>
|
/// The file descriptor.
|
||||||
/// The file descriptor.
|
/// </value>
|
||||||
/// </value>
|
public Int32 FileDescriptor {
|
||||||
public int FileDescriptor { get; }
|
get;
|
||||||
|
}
|
||||||
/// <summary>
|
|
||||||
/// Reads a byte from the specified file descriptor
|
/// <summary>
|
||||||
/// </summary>
|
/// Reads a byte from the specified file descriptor
|
||||||
/// <returns>The byte from device</returns>
|
/// </summary>
|
||||||
public byte Read()
|
/// <returns>The byte from device</returns>
|
||||||
{
|
public Byte Read() {
|
||||||
lock (_syncLock)
|
lock(this._syncLock) {
|
||||||
{
|
Int32 result = WiringPi.WiringPiI2CRead(this.FileDescriptor);
|
||||||
var result = WiringPi.WiringPiI2CRead(FileDescriptor);
|
if(result < 0) {
|
||||||
if (result < 0) HardwareException.Throw(nameof(I2CDevice), nameof(Read));
|
HardwareException.Throw(nameof(I2CDevice), nameof(Read));
|
||||||
return (byte)result;
|
}
|
||||||
}
|
|
||||||
}
|
return (Byte)result;
|
||||||
|
}
|
||||||
/// <summary>
|
}
|
||||||
/// Reads a byte from the specified file descriptor
|
|
||||||
/// </summary>
|
/// <summary>
|
||||||
/// <returns>The byte from device</returns>
|
/// Reads a byte from the specified file descriptor
|
||||||
public Task<byte> ReadAsync() => Task.Run(() => Read());
|
/// </summary>
|
||||||
|
/// <returns>The byte from device</returns>
|
||||||
/// <summary>
|
public Task<Byte> ReadAsync() => Task.Run(() => this.Read());
|
||||||
/// Reads a buffer of the specified length, one byte at a time
|
|
||||||
/// </summary>
|
/// <summary>
|
||||||
/// <param name="length">The length.</param>
|
/// Reads a buffer of the specified length, one byte at a time
|
||||||
/// <returns>The byte array from device</returns>
|
/// </summary>
|
||||||
public byte[] Read(int length)
|
/// <param name="length">The length.</param>
|
||||||
{
|
/// <returns>The byte array from device</returns>
|
||||||
lock (_syncLock)
|
public Byte[] Read(Int32 length) {
|
||||||
{
|
lock(this._syncLock) {
|
||||||
var buffer = new byte[length];
|
Byte[] buffer = new Byte[length];
|
||||||
for (var i = 0; i < length; i++)
|
for(Int32 i = 0; i < length; i++) {
|
||||||
{
|
Int32 result = WiringPi.WiringPiI2CRead(this.FileDescriptor);
|
||||||
var result = WiringPi.WiringPiI2CRead(FileDescriptor);
|
if(result < 0) {
|
||||||
if (result < 0) HardwareException.Throw(nameof(I2CDevice), nameof(Read));
|
HardwareException.Throw(nameof(I2CDevice), nameof(Read));
|
||||||
buffer[i] = (byte)result;
|
}
|
||||||
}
|
|
||||||
|
buffer[i] = (Byte)result;
|
||||||
return buffer;
|
}
|
||||||
}
|
|
||||||
}
|
return buffer;
|
||||||
|
}
|
||||||
/// <summary>
|
}
|
||||||
/// Reads a buffer of the specified length, one byte at a time
|
|
||||||
/// </summary>
|
/// <summary>
|
||||||
/// <param name="length">The length.</param>
|
/// Reads a buffer of the specified length, one byte at a time
|
||||||
/// <returns>The byte array from device</returns>
|
/// </summary>
|
||||||
public Task<byte[]> ReadAsync(int length) => Task.Run(() => Read(length));
|
/// <param name="length">The length.</param>
|
||||||
|
/// <returns>The byte array from device</returns>
|
||||||
/// <summary>
|
public Task<Byte[]> ReadAsync(Int32 length) => Task.Run(() => this.Read(length));
|
||||||
/// Writes a byte of data the specified file descriptor.
|
|
||||||
/// </summary>
|
/// <summary>
|
||||||
/// <param name="data">The data.</param>
|
/// Writes a byte of data the specified file descriptor.
|
||||||
public void Write(byte data)
|
/// </summary>
|
||||||
{
|
/// <param name="data">The data.</param>
|
||||||
lock (_syncLock)
|
public void Write(Byte data) {
|
||||||
{
|
lock(this._syncLock) {
|
||||||
var result = WiringPi.WiringPiI2CWrite(FileDescriptor, data);
|
Int32 result = WiringPi.WiringPiI2CWrite(this.FileDescriptor, data);
|
||||||
if (result < 0) HardwareException.Throw(nameof(I2CDevice), nameof(Write));
|
if(result < 0) {
|
||||||
}
|
HardwareException.Throw(nameof(I2CDevice), nameof(Write));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
/// <summary>
|
}
|
||||||
/// Writes a byte of data the specified file descriptor.
|
|
||||||
/// </summary>
|
/// <summary>
|
||||||
/// <param name="data">The data.</param>
|
/// Writes a byte of data the specified file descriptor.
|
||||||
/// <returns>The awaitable task</returns>
|
/// </summary>
|
||||||
public Task WriteAsync(byte data) => Task.Run(() => { Write(data); });
|
/// <param name="data">The data.</param>
|
||||||
|
/// <returns>The awaitable task</returns>
|
||||||
/// <summary>
|
public Task WriteAsync(Byte data) => Task.Run(() => this.Write(data));
|
||||||
/// Writes a set of bytes to the specified file descriptor.
|
|
||||||
/// </summary>
|
/// <summary>
|
||||||
/// <param name="data">The data.</param>
|
/// Writes a set of bytes to the specified file descriptor.
|
||||||
public void Write(byte[] data)
|
/// </summary>
|
||||||
{
|
/// <param name="data">The data.</param>
|
||||||
lock (_syncLock)
|
public void Write(Byte[] data) {
|
||||||
{
|
lock(this._syncLock) {
|
||||||
foreach (var b in data)
|
foreach(Byte b in data) {
|
||||||
{
|
Int32 result = WiringPi.WiringPiI2CWrite(this.FileDescriptor, b);
|
||||||
var result = WiringPi.WiringPiI2CWrite(FileDescriptor, b);
|
if(result < 0) {
|
||||||
if (result < 0) HardwareException.Throw(nameof(I2CDevice), nameof(Write));
|
HardwareException.Throw(nameof(I2CDevice), nameof(Write));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
/// <summary>
|
|
||||||
/// Writes a set of bytes to the specified file descriptor.
|
/// <summary>
|
||||||
/// </summary>
|
/// Writes a set of bytes to the specified file descriptor.
|
||||||
/// <param name="data">The data.</param>
|
/// </summary>
|
||||||
/// <returns>The awaitable task</returns>
|
/// <param name="data">The data.</param>
|
||||||
public Task WriteAsync(byte[] data)
|
/// <returns>The awaitable task</returns>
|
||||||
{
|
public Task WriteAsync(Byte[] data) => Task.Run(() => this.Write(data));
|
||||||
return Task.Run(() => { Write(data); });
|
|
||||||
}
|
/// <summary>
|
||||||
|
/// These write an 8 or 16-bit data value into the device register indicated.
|
||||||
/// <summary>
|
/// </summary>
|
||||||
/// These write an 8 or 16-bit data value into the device register indicated.
|
/// <param name="address">The register.</param>
|
||||||
/// </summary>
|
/// <param name="data">The data.</param>
|
||||||
/// <param name="address">The register.</param>
|
public void WriteAddressByte(Int32 address, Byte data) {
|
||||||
/// <param name="data">The data.</param>
|
lock(this._syncLock) {
|
||||||
public void WriteAddressByte(int address, byte data)
|
Int32 result = WiringPi.WiringPiI2CWriteReg8(this.FileDescriptor, address, data);
|
||||||
{
|
if(result < 0) {
|
||||||
lock (_syncLock)
|
HardwareException.Throw(nameof(I2CDevice), nameof(WriteAddressByte));
|
||||||
{
|
}
|
||||||
var result = WiringPi.WiringPiI2CWriteReg8(FileDescriptor, address, data);
|
}
|
||||||
if (result < 0) HardwareException.Throw(nameof(I2CDevice), nameof(WriteAddressByte));
|
}
|
||||||
}
|
|
||||||
}
|
/// <summary>
|
||||||
|
/// These write an 8 or 16-bit data value into the device register indicated.
|
||||||
/// <summary>
|
/// </summary>
|
||||||
/// These write an 8 or 16-bit data value into the device register indicated.
|
/// <param name="address">The register.</param>
|
||||||
/// </summary>
|
/// <param name="data">The data.</param>
|
||||||
/// <param name="address">The register.</param>
|
public void WriteAddressWord(Int32 address, UInt16 data) {
|
||||||
/// <param name="data">The data.</param>
|
lock(this._syncLock) {
|
||||||
public void WriteAddressWord(int address, ushort data)
|
Int32 result = WiringPi.WiringPiI2CWriteReg16(this.FileDescriptor, address, data);
|
||||||
{
|
if(result < 0) {
|
||||||
lock (_syncLock)
|
HardwareException.Throw(nameof(I2CDevice), nameof(WriteAddressWord));
|
||||||
{
|
}
|
||||||
var result = WiringPi.WiringPiI2CWriteReg16(FileDescriptor, address, data);
|
}
|
||||||
if (result < 0) HardwareException.Throw(nameof(I2CDevice), nameof(WriteAddressWord));
|
}
|
||||||
}
|
|
||||||
}
|
/// <summary>
|
||||||
|
/// These read an 8 or 16-bit value from the device register indicated.
|
||||||
/// <summary>
|
/// </summary>
|
||||||
/// These read an 8 or 16-bit value from the device register indicated.
|
/// <param name="address">The register.</param>
|
||||||
/// </summary>
|
/// <returns>The address byte from device</returns>
|
||||||
/// <param name="address">The register.</param>
|
public Byte ReadAddressByte(Int32 address) {
|
||||||
/// <returns>The address byte from device</returns>
|
lock(this._syncLock) {
|
||||||
public byte ReadAddressByte(int address)
|
Int32 result = WiringPi.WiringPiI2CReadReg8(this.FileDescriptor, address);
|
||||||
{
|
if(result < 0) {
|
||||||
lock (_syncLock)
|
HardwareException.Throw(nameof(I2CDevice), nameof(ReadAddressByte));
|
||||||
{
|
}
|
||||||
var result = WiringPi.WiringPiI2CReadReg8(FileDescriptor, address);
|
|
||||||
if (result < 0) HardwareException.Throw(nameof(I2CDevice), nameof(ReadAddressByte));
|
return (Byte)result;
|
||||||
|
}
|
||||||
return (byte)result;
|
}
|
||||||
}
|
|
||||||
}
|
/// <summary>
|
||||||
|
/// These read an 8 or 16-bit value from the device register indicated.
|
||||||
/// <summary>
|
/// </summary>
|
||||||
/// These read an 8 or 16-bit value from the device register indicated.
|
/// <param name="address">The register.</param>
|
||||||
/// </summary>
|
/// <returns>The address word from device</returns>
|
||||||
/// <param name="address">The register.</param>
|
public UInt16 ReadAddressWord(Int32 address) {
|
||||||
/// <returns>The address word from device</returns>
|
lock(this._syncLock) {
|
||||||
public ushort ReadAddressWord(int address)
|
Int32 result = WiringPi.WiringPiI2CReadReg16(this.FileDescriptor, address);
|
||||||
{
|
if(result < 0) {
|
||||||
lock (_syncLock)
|
HardwareException.Throw(nameof(I2CDevice), nameof(ReadAddressWord));
|
||||||
{
|
}
|
||||||
var result = WiringPi.WiringPiI2CReadReg16(FileDescriptor, address);
|
|
||||||
if (result < 0) HardwareException.Throw(nameof(I2CDevice), nameof(ReadAddressWord));
|
return Convert.ToUInt16(result);
|
||||||
|
}
|
||||||
return Convert.ToUInt16(result);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -1,72 +1,72 @@
|
|||||||
namespace Unosquare.RaspberryIO.Gpio
|
using System;
|
||||||
{
|
using Unosquare.Swan.Abstractions;
|
||||||
using Swan.Abstractions;
|
|
||||||
|
namespace Unosquare.RaspberryIO.Gpio {
|
||||||
|
/// <summary>
|
||||||
|
/// The SPI Bus containing the 2 SPI channels
|
||||||
|
/// </summary>
|
||||||
|
public class SpiBus : SingletonBase<SpiBus> {
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The SPI Bus containing the 2 SPI channels
|
/// Prevents a default instance of the <see cref="SpiBus"/> class from being created.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class SpiBus : SingletonBase<SpiBus>
|
private SpiBus() {
|
||||||
{
|
// placeholder
|
||||||
/// <summary>
|
}
|
||||||
/// Prevents a default instance of the <see cref="SpiBus"/> class from being created.
|
|
||||||
/// </summary>
|
#region SPI Access
|
||||||
private SpiBus()
|
|
||||||
{
|
/// <summary>
|
||||||
// placeholder
|
/// Gets or sets the channel 0 frequency in Hz.
|
||||||
}
|
/// </summary>
|
||||||
|
/// <value>
|
||||||
#region SPI Access
|
/// The channel0 frequency.
|
||||||
|
/// </value>
|
||||||
/// <summary>
|
public Int32 Channel0Frequency {
|
||||||
/// Gets or sets the channel 0 frequency in Hz.
|
get; set;
|
||||||
/// </summary>
|
}
|
||||||
/// <value>
|
|
||||||
/// The channel0 frequency.
|
/// <summary>
|
||||||
/// </value>
|
/// Gets the SPI bus on channel 1.
|
||||||
public int Channel0Frequency { get; set; }
|
/// </summary>
|
||||||
|
/// <value>
|
||||||
/// <summary>
|
/// The channel0.
|
||||||
/// Gets the SPI bus on channel 1.
|
/// </value>
|
||||||
/// </summary>
|
public SpiChannel Channel0 {
|
||||||
/// <value>
|
get {
|
||||||
/// The channel0.
|
if(this.Channel0Frequency == 0) {
|
||||||
/// </value>
|
this.Channel0Frequency = SpiChannel.DefaultFrequency;
|
||||||
public SpiChannel Channel0
|
}
|
||||||
{
|
|
||||||
get
|
return SpiChannel.Retrieve(SpiChannelNumber.Channel0, this.Channel0Frequency);
|
||||||
{
|
}
|
||||||
if (Channel0Frequency == 0)
|
}
|
||||||
Channel0Frequency = SpiChannel.DefaultFrequency;
|
|
||||||
|
/// <summary>
|
||||||
return SpiChannel.Retrieve(SpiChannelNumber.Channel0, Channel0Frequency);
|
/// Gets or sets the channel 1 frequency in Hz
|
||||||
}
|
/// </summary>
|
||||||
}
|
/// <value>
|
||||||
|
/// The channel1 frequency.
|
||||||
/// <summary>
|
/// </value>
|
||||||
/// Gets or sets the channel 1 frequency in Hz
|
public Int32 Channel1Frequency {
|
||||||
/// </summary>
|
get; set;
|
||||||
/// <value>
|
}
|
||||||
/// The channel1 frequency.
|
|
||||||
/// </value>
|
/// <summary>
|
||||||
public int Channel1Frequency { get; set; }
|
/// Gets the SPI bus on channel 1.
|
||||||
|
/// </summary>
|
||||||
/// <summary>
|
/// <value>
|
||||||
/// Gets the SPI bus on channel 1.
|
/// The channel1.
|
||||||
/// </summary>
|
/// </value>
|
||||||
/// <value>
|
public SpiChannel Channel1 {
|
||||||
/// The channel1.
|
get {
|
||||||
/// </value>
|
if(this.Channel1Frequency == 0) {
|
||||||
public SpiChannel Channel1
|
this.Channel1Frequency = SpiChannel.DefaultFrequency;
|
||||||
{
|
}
|
||||||
get
|
|
||||||
{
|
return SpiChannel.Retrieve(SpiChannelNumber.Channel1, this.Channel1Frequency);
|
||||||
if (Channel1Frequency == 0)
|
}
|
||||||
Channel1Frequency = SpiChannel.DefaultFrequency;
|
}
|
||||||
|
|
||||||
return SpiChannel.Retrieve(SpiChannelNumber.Channel1, Channel1Frequency);
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,154 +1,154 @@
|
|||||||
namespace Unosquare.RaspberryIO.Gpio
|
using Unosquare.RaspberryIO.Native;
|
||||||
{
|
using Unosquare.Swan;
|
||||||
using Native;
|
using System;
|
||||||
using Swan;
|
using System.Collections.Generic;
|
||||||
using System;
|
using System.Threading.Tasks;
|
||||||
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 {
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Provides access to using the SPI buses on the GPIO.
|
/// The minimum frequency of an SPI Channel
|
||||||
/// 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>
|
/// </summary>
|
||||||
public sealed class SpiChannel
|
public const Int32 MinFrequency = 500000;
|
||||||
{
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The minimum frequency of an SPI Channel
|
/// The maximum frequency of an SPI channel
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const int MinFrequency = 500000;
|
public const Int32 MaxFrequency = 32000000;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The maximum frequency of an SPI channel
|
/// The default frequency of SPI channels
|
||||||
/// </summary>
|
/// This is set to 8 Mhz wich is typical in modern hardware.
|
||||||
public const int MaxFrequency = 32000000;
|
/// </summary>
|
||||||
|
public const Int32 DefaultFrequency = 8000000;
|
||||||
/// <summary>
|
|
||||||
/// The default frequency of SPI channels
|
private static readonly Object SyncRoot = new Object();
|
||||||
/// This is set to 8 Mhz wich is typical in modern hardware.
|
private static readonly Dictionary<SpiChannelNumber, SpiChannel> Buses = new Dictionary<SpiChannelNumber, SpiChannel>();
|
||||||
/// </summary>
|
private readonly Object _syncLock = new Object();
|
||||||
public const int DefaultFrequency = 8000000;
|
|
||||||
|
/// <summary>
|
||||||
private static readonly object SyncRoot = new object();
|
/// Initializes a new instance of the <see cref="SpiChannel"/> class.
|
||||||
private static readonly Dictionary<SpiChannelNumber, SpiChannel> Buses = new Dictionary<SpiChannelNumber, SpiChannel>();
|
/// </summary>
|
||||||
private readonly object _syncLock = new object();
|
/// <param name="channel">The channel.</param>
|
||||||
|
/// <param name="frequency">The frequency.</param>
|
||||||
/// <summary>
|
private SpiChannel(SpiChannelNumber channel, Int32 frequency) {
|
||||||
/// Initializes a new instance of the <see cref="SpiChannel"/> class.
|
lock(SyncRoot) {
|
||||||
/// </summary>
|
this.Frequency = frequency.Clamp(MinFrequency, MaxFrequency);
|
||||||
/// <param name="channel">The channel.</param>
|
this.Channel = (Int32)channel;
|
||||||
/// <param name="frequency">The frequency.</param>
|
this.FileDescriptor = WiringPi.WiringPiSPISetup((Int32)channel, this.Frequency);
|
||||||
private SpiChannel(SpiChannelNumber channel, int frequency)
|
|
||||||
{
|
if(this.FileDescriptor < 0) {
|
||||||
lock (SyncRoot)
|
HardwareException.Throw(nameof(SpiChannel), channel.ToString());
|
||||||
{
|
}
|
||||||
Frequency = frequency.Clamp(MinFrequency, MaxFrequency);
|
}
|
||||||
Channel = (int)channel;
|
}
|
||||||
FileDescriptor = WiringPi.WiringPiSPISetup((int)channel, Frequency);
|
|
||||||
|
/// <summary>
|
||||||
if (FileDescriptor < 0)
|
/// Gets the standard initialization file descriptor.
|
||||||
{
|
/// anything negative means error.
|
||||||
HardwareException.Throw(nameof(SpiChannel), channel.ToString());
|
/// </summary>
|
||||||
}
|
/// <value>
|
||||||
}
|
/// The file descriptor.
|
||||||
}
|
/// </value>
|
||||||
|
public Int32 FileDescriptor {
|
||||||
/// <summary>
|
get;
|
||||||
/// Gets the standard initialization file descriptor.
|
}
|
||||||
/// anything negative means error.
|
|
||||||
/// </summary>
|
/// <summary>
|
||||||
/// <value>
|
/// Gets the channel.
|
||||||
/// The file descriptor.
|
/// </summary>
|
||||||
/// </value>
|
public Int32 Channel {
|
||||||
public int FileDescriptor { get; }
|
get;
|
||||||
|
}
|
||||||
/// <summary>
|
|
||||||
/// Gets the channel.
|
/// <summary>
|
||||||
/// </summary>
|
/// Gets the frequency.
|
||||||
public int Channel { get; }
|
/// </summary>
|
||||||
|
public Int32 Frequency {
|
||||||
/// <summary>
|
get;
|
||||||
/// Gets the frequency.
|
}
|
||||||
/// </summary>
|
|
||||||
public int Frequency { get; }
|
/// <summary>
|
||||||
|
/// Sends data and simultaneously receives the data in the return buffer
|
||||||
/// <summary>
|
/// </summary>
|
||||||
/// Sends data and simultaneously receives the data in the return buffer
|
/// <param name="buffer">The buffer.</param>
|
||||||
/// </summary>
|
/// <returns>The read bytes from the ring-style bus</returns>
|
||||||
/// <param name="buffer">The buffer.</param>
|
public Byte[] SendReceive(Byte[] buffer) {
|
||||||
/// <returns>The read bytes from the ring-style bus</returns>
|
if(buffer == null || buffer.Length == 0) {
|
||||||
public byte[] SendReceive(byte[] buffer)
|
return null;
|
||||||
{
|
}
|
||||||
if (buffer == null || buffer.Length == 0)
|
|
||||||
return null;
|
lock(this._syncLock) {
|
||||||
|
Byte[] spiBuffer = new Byte[buffer.Length];
|
||||||
lock (_syncLock)
|
Array.Copy(buffer, spiBuffer, buffer.Length);
|
||||||
{
|
|
||||||
var spiBuffer = new byte[buffer.Length];
|
Int32 result = WiringPi.WiringPiSPIDataRW(this.Channel, spiBuffer, spiBuffer.Length);
|
||||||
Array.Copy(buffer, spiBuffer, buffer.Length);
|
if(result < 0) {
|
||||||
|
HardwareException.Throw(nameof(SpiChannel), nameof(SendReceive));
|
||||||
var result = WiringPi.WiringPiSPIDataRW(Channel, spiBuffer, spiBuffer.Length);
|
}
|
||||||
if (result < 0) HardwareException.Throw(nameof(SpiChannel), nameof(SendReceive));
|
|
||||||
|
return spiBuffer;
|
||||||
return spiBuffer;
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
/// <summary>
|
||||||
/// <summary>
|
/// Sends data and simultaneously receives the data in the return buffer
|
||||||
/// Sends data and simultaneously receives the data in the return buffer
|
/// </summary>
|
||||||
/// </summary>
|
/// <param name="buffer">The buffer.</param>
|
||||||
/// <param name="buffer">The buffer.</param>
|
/// <returns>
|
||||||
/// <returns>
|
/// The read bytes from the ring-style bus
|
||||||
/// The read bytes from the ring-style bus
|
/// </returns>
|
||||||
/// </returns>
|
public Task<Byte[]> SendReceiveAsync(Byte[] buffer) => Task.Run(() => this.SendReceive(buffer));
|
||||||
public Task<byte[]> SendReceiveAsync(byte[] buffer) => Task.Run(() => SendReceive(buffer));
|
|
||||||
|
/// <summary>
|
||||||
/// <summary>
|
/// Writes the specified buffer the the underlying FileDescriptor.
|
||||||
/// Writes the specified buffer the the underlying FileDescriptor.
|
/// Do not use this method if you expect data back.
|
||||||
/// Do not use this method if you expect data back.
|
/// This method is efficient if used in a fire-and-forget scenario
|
||||||
/// This method is efficient if used in a fire-and-forget scenario
|
/// like sending data over to those long RGB LED strips
|
||||||
/// like sending data over to those long RGB LED strips
|
/// </summary>
|
||||||
/// </summary>
|
/// <param name="buffer">The buffer.</param>
|
||||||
/// <param name="buffer">The buffer.</param>
|
public void Write(Byte[] buffer) {
|
||||||
public void Write(byte[] buffer)
|
lock(this._syncLock) {
|
||||||
{
|
Int32 result = Standard.Write(this.FileDescriptor, buffer, buffer.Length);
|
||||||
lock (_syncLock)
|
|
||||||
{
|
if(result < 0) {
|
||||||
var result = Standard.Write(FileDescriptor, buffer, buffer.Length);
|
HardwareException.Throw(nameof(SpiChannel), nameof(Write));
|
||||||
|
}
|
||||||
if (result < 0)
|
}
|
||||||
HardwareException.Throw(nameof(SpiChannel), nameof(Write));
|
}
|
||||||
}
|
|
||||||
}
|
/// <summary>
|
||||||
|
/// Writes the specified buffer the the underlying FileDescriptor.
|
||||||
/// <summary>
|
/// Do not use this method if you expect data back.
|
||||||
/// Writes the specified buffer the the underlying FileDescriptor.
|
/// This method is efficient if used in a fire-and-forget scenario
|
||||||
/// Do not use this method if you expect data back.
|
/// like sending data over to those long RGB LED strips
|
||||||
/// This method is efficient if used in a fire-and-forget scenario
|
/// </summary>
|
||||||
/// like sending data over to those long RGB LED strips
|
/// <param name="buffer">The buffer.</param>
|
||||||
/// </summary>
|
/// <returns>The awaitable task</returns>
|
||||||
/// <param name="buffer">The buffer.</param>
|
public Task WriteAsync(Byte[] buffer) => Task.Run(() => this.Write(buffer));
|
||||||
/// <returns>The awaitable task</returns>
|
|
||||||
public Task WriteAsync(byte[] buffer) => Task.Run(() => { Write(buffer); });
|
/// <summary>
|
||||||
|
/// Retrieves the spi bus. If the bus channel is not registered it sets it up automatically.
|
||||||
/// <summary>
|
/// If it had been previously registered, then the bus is simply returned.
|
||||||
/// Retrieves the spi bus. If the bus channel is not registered it sets it up automatically.
|
/// </summary>
|
||||||
/// If it had been previously registered, then the bus is simply returned.
|
/// <param name="channel">The channel.</param>
|
||||||
/// </summary>
|
/// <param name="frequency">The frequency.</param>
|
||||||
/// <param name="channel">The channel.</param>
|
/// <returns>The usable SPI channel</returns>
|
||||||
/// <param name="frequency">The frequency.</param>
|
internal static SpiChannel Retrieve(SpiChannelNumber channel, Int32 frequency) {
|
||||||
/// <returns>The usable SPI channel</returns>
|
lock(SyncRoot) {
|
||||||
internal static SpiChannel Retrieve(SpiChannelNumber channel, int frequency)
|
if(Buses.ContainsKey(channel)) {
|
||||||
{
|
return Buses[channel];
|
||||||
lock (SyncRoot)
|
}
|
||||||
{
|
|
||||||
if (Buses.ContainsKey(channel))
|
SpiChannel newBus = new SpiChannel(channel, frequency);
|
||||||
return Buses[channel];
|
Buses[channel] = newBus;
|
||||||
|
return newBus;
|
||||||
var newBus = new SpiChannel(channel, frequency);
|
}
|
||||||
Buses[channel] = newBus;
|
}
|
||||||
return newBus;
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,11 @@
|
|||||||
namespace Unosquare.RaspberryIO.Native
|
namespace Unosquare.RaspberryIO.Native {
|
||||||
{
|
/// <summary>
|
||||||
/// <summary>
|
/// A delegate defining a callback for an Interrupt Service Routine
|
||||||
/// A delegate defining a callback for an Interrupt Service Routine
|
/// </summary>
|
||||||
/// </summary>
|
public delegate void InterruptServiceRoutineCallback();
|
||||||
public delegate void InterruptServiceRoutineCallback();
|
|
||||||
|
/// <summary>
|
||||||
/// <summary>
|
/// Defines the body of a thread worker
|
||||||
/// Defines the body of a thread worker
|
/// </summary>
|
||||||
/// </summary>
|
public delegate void ThreadWorker();
|
||||||
public delegate void ThreadWorker();
|
|
||||||
}
|
}
|
||||||
|
@ -1,73 +1,73 @@
|
|||||||
namespace Unosquare.RaspberryIO.Native
|
using Unosquare.Swan;
|
||||||
{
|
using System;
|
||||||
using Swan;
|
using System.Runtime.InteropServices;
|
||||||
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 {
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Represents a low-level exception, typically thrown when return codes from a
|
/// Initializes a new instance of the <see cref="HardwareException" /> class.
|
||||||
/// low-level operation is non-zero or in some cases when it is less than zero.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <seealso cref="Exception" />
|
/// <param name="errorCode">The error code.</param>
|
||||||
public class HardwareException : Exception
|
/// <param name="component">The component.</param>
|
||||||
{
|
public HardwareException(Int32 errorCode, String component)
|
||||||
/// <summary>
|
: base($"A hardware exception occurred. Error Code: {errorCode}") {
|
||||||
/// Initializes a new instance of the <see cref="HardwareException" /> class.
|
this.ExtendedMessage = null;
|
||||||
/// </summary>
|
|
||||||
/// <param name="errorCode">The error code.</param>
|
try {
|
||||||
/// <param name="component">The component.</param>
|
this.ExtendedMessage = Standard.Strerror(errorCode);
|
||||||
public HardwareException(int errorCode, string component)
|
} catch {
|
||||||
: base($"A hardware exception occurred. Error Code: {errorCode}")
|
// TODO: strerror not working great...
|
||||||
{
|
$"Could not retrieve native error description using {nameof(Standard.Strerror)}".Error(Pi.LoggerSource);
|
||||||
ExtendedMessage = null;
|
}
|
||||||
|
|
||||||
try
|
this.ErrorCode = errorCode;
|
||||||
{
|
this.Component = component;
|
||||||
ExtendedMessage = Standard.Strerror(errorCode);
|
}
|
||||||
}
|
|
||||||
catch
|
/// <summary>
|
||||||
{
|
/// Gets the error code.
|
||||||
// TODO: strerror not working great...
|
/// </summary>
|
||||||
$"Could not retrieve native error description using {nameof(Standard.Strerror)}".Error(Pi.LoggerSource);
|
/// <value>
|
||||||
}
|
/// The error code.
|
||||||
|
/// </value>
|
||||||
ErrorCode = errorCode;
|
public Int32 ErrorCode {
|
||||||
Component = component;
|
get;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the error code.
|
/// Gets the component.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <value>
|
/// <value>
|
||||||
/// The error code.
|
/// The component.
|
||||||
/// </value>
|
/// </value>
|
||||||
public int ErrorCode { get; }
|
public String Component {
|
||||||
|
get;
|
||||||
/// <summary>
|
}
|
||||||
/// Gets the component.
|
|
||||||
/// </summary>
|
/// <summary>
|
||||||
/// <value>
|
/// Gets the extended message (could be null).
|
||||||
/// The component.
|
/// </summary>
|
||||||
/// </value>
|
/// <value>
|
||||||
public string Component { get; }
|
/// The extended message.
|
||||||
|
/// </value>
|
||||||
/// <summary>
|
public String ExtendedMessage {
|
||||||
/// Gets the extended message (could be null).
|
get;
|
||||||
/// </summary>
|
}
|
||||||
/// <value>
|
|
||||||
/// The extended message.
|
/// <summary>
|
||||||
/// </value>
|
/// Throws a new instance of a hardware error by retrieving the last error number (errno).
|
||||||
public string ExtendedMessage { get; }
|
/// </summary>
|
||||||
|
/// <param name="className">Name of the class.</param>
|
||||||
/// <summary>
|
/// <param name="methodName">Name of the method.</param>
|
||||||
/// Throws a new instance of a hardware error by retrieving the last error number (errno).
|
/// <exception cref="HardwareException">When an error thrown by an API call occurs</exception>
|
||||||
/// </summary>
|
public static void Throw(String className, String methodName) => throw new HardwareException(Marshal.GetLastWin32Error(), $"{className}.{methodName}");
|
||||||
/// <param name="className">Name of the class.</param>
|
|
||||||
/// <param name="methodName">Name of the method.</param>
|
/// <inheritdoc />
|
||||||
/// <exception cref="HardwareException">When an error thrown by an API call occurs</exception>
|
public override String ToString() => $"{this.GetType()}{(String.IsNullOrWhiteSpace(this.Component) ? String.Empty : $" on {this.Component}")}: ({this.ErrorCode}) - {this.Message}";
|
||||||
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}";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,32 +1,30 @@
|
|||||||
namespace Unosquare.RaspberryIO.Native
|
using System;
|
||||||
{
|
using System.Diagnostics;
|
||||||
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 {
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Provides access to a high- esolution, time measuring device.
|
/// Initializes a new instance of the <see cref="HighResolutionTimer"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <seealso cref="Stopwatch" />
|
/// <exception cref="NotSupportedException">High-resolution timer not available</exception>
|
||||||
public class HighResolutionTimer : Stopwatch
|
public HighResolutionTimer() {
|
||||||
{
|
if(!IsHighResolution) {
|
||||||
/// <summary>
|
throw new NotSupportedException("High-resolution timer not available");
|
||||||
/// Initializes a new instance of the <see cref="HighResolutionTimer"/> class.
|
}
|
||||||
/// </summary>
|
}
|
||||||
/// <exception cref="NotSupportedException">High-resolution timer not available</exception>
|
|
||||||
public HighResolutionTimer()
|
/// <summary>
|
||||||
{
|
/// Gets the numer of microseconds per timer tick.
|
||||||
if (!IsHighResolution)
|
/// </summary>
|
||||||
throw new NotSupportedException("High-resolution timer not available");
|
public static Double MicrosecondsPerTick { get; } = 1000000d / Frequency;
|
||||||
}
|
|
||||||
|
/// <summary>
|
||||||
/// <summary>
|
/// Gets the elapsed microseconds.
|
||||||
/// Gets the numer of microseconds per timer tick.
|
/// </summary>
|
||||||
/// </summary>
|
public Int64 ElapsedMicroseconds => (Int64)(this.ElapsedTicks * MicrosecondsPerTick);
|
||||||
public static double MicrosecondsPerTick { get; } = 1000000d / Frequency;
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the elapsed microseconds.
|
|
||||||
/// </summary>
|
|
||||||
public long ElapsedMicroseconds => (long)(ElapsedTicks * MicrosecondsPerTick);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,84 +1,80 @@
|
|||||||
namespace Unosquare.RaspberryIO.Native
|
using Unosquare.Swan;
|
||||||
{
|
using System;
|
||||||
using Swan;
|
using System.Runtime.InteropServices;
|
||||||
using System;
|
using System.Text;
|
||||||
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";
|
||||||
|
|
||||||
|
#region LibC Calls
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Provides standard libc calls using platform-invoke
|
/// Strerrors the specified error.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static class Standard
|
/// <param name="error">The error.</param>
|
||||||
{
|
/// <returns></returns>
|
||||||
internal const string LibCLibrary = "libc";
|
public static String Strerror(Int32 error) {
|
||||||
|
if(!Runtime.IsUsingMonoRuntime) {
|
||||||
#region LibC Calls
|
return StrError(error);
|
||||||
|
}
|
||||||
/// <summary>
|
|
||||||
/// Strerrors the specified error.
|
try {
|
||||||
/// </summary>
|
StringBuilder buffer = new StringBuilder(256);
|
||||||
/// <param name="error">The error.</param>
|
Int32 result = Strerror(error, buffer, (UInt64)buffer.Capacity);
|
||||||
/// <returns></returns>
|
return (result != -1) ? buffer.ToString() : null;
|
||||||
public static string Strerror(int error)
|
} catch(EntryPointNotFoundException) {
|
||||||
{
|
return null;
|
||||||
if (!Runtime.IsUsingMonoRuntime) return StrError(error);
|
}
|
||||||
|
}
|
||||||
try
|
|
||||||
{
|
/// <summary>
|
||||||
var buffer = new StringBuilder(256);
|
/// Changes file permissions on a Unix file system
|
||||||
var result = Strerror(error, buffer, (ulong)buffer.Capacity);
|
/// </summary>
|
||||||
return (result != -1) ? buffer.ToString() : null;
|
/// <param name="filename">The filename.</param>
|
||||||
}
|
/// <param name="mode">The mode.</param>
|
||||||
catch (EntryPointNotFoundException)
|
/// <returns>The result</returns>
|
||||||
{
|
[DllImport(LibCLibrary, EntryPoint = "chmod", SetLastError = true)]
|
||||||
return null;
|
public static extern Int32 Chmod(String filename, UInt32 mode);
|
||||||
}
|
|
||||||
}
|
/// <summary>
|
||||||
|
/// Converts a string to a 32 bit integer. Use endpointer as IntPtr.Zero
|
||||||
/// <summary>
|
/// </summary>
|
||||||
/// Changes file permissions on a Unix file system
|
/// <param name="numberString">The number string.</param>
|
||||||
/// </summary>
|
/// <param name="endPointer">The end pointer.</param>
|
||||||
/// <param name="filename">The filename.</param>
|
/// <param name="numberBase">The number base.</param>
|
||||||
/// <param name="mode">The mode.</param>
|
/// <returns>The result</returns>
|
||||||
/// <returns>The result</returns>
|
[DllImport(LibCLibrary, EntryPoint = "strtol", SetLastError = true)]
|
||||||
[DllImport(LibCLibrary, EntryPoint = "chmod", SetLastError = true)]
|
public static extern Int32 StringToInteger(String numberString, IntPtr endPointer, Int32 numberBase);
|
||||||
public static extern int Chmod(string filename, uint mode);
|
|
||||||
|
/// <summary>
|
||||||
/// <summary>
|
/// The write() function attempts to write nbytes from buffer to the file associated with handle. On text files, it expands each LF to a CR/LF.
|
||||||
/// Converts a string to a 32 bit integer. Use endpointer as IntPtr.Zero
|
/// The function returns the number of bytes written to the file. A return value of -1 indicates an error, with errno set appropriately.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="numberString">The number string.</param>
|
/// <param name="fd">The fd.</param>
|
||||||
/// <param name="endPointer">The end pointer.</param>
|
/// <param name="buffer">The buffer.</param>
|
||||||
/// <param name="numberBase">The number base.</param>
|
/// <param name="count">The count.</param>
|
||||||
/// <returns>The result</returns>
|
/// <returns>The result</returns>
|
||||||
[DllImport(LibCLibrary, EntryPoint = "strtol", SetLastError = true)]
|
[DllImport(LibCLibrary, EntryPoint = "write", SetLastError = true)]
|
||||||
public static extern int StringToInteger(string numberString, IntPtr endPointer, int numberBase);
|
public static extern Int32 Write(Int32 fd, Byte[] buffer, Int32 count);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The write() function attempts to write nbytes from buffer to the file associated with handle. On text files, it expands each LF to a CR/LF.
|
/// Fills in the structure with information about the system.
|
||||||
/// The function returns the number of bytes written to the file. A return value of -1 indicates an error, with errno set appropriately.
|
/// </summary>
|
||||||
/// </summary>
|
/// <param name="name">The name.</param>
|
||||||
/// <param name="fd">The fd.</param>
|
/// <returns>The result</returns>
|
||||||
/// <param name="buffer">The buffer.</param>
|
[DllImport(LibCLibrary, EntryPoint = "uname", SetLastError = true)]
|
||||||
/// <param name="count">The count.</param>
|
public static extern Int32 Uname(out SystemName name);
|
||||||
/// <returns>The result</returns>
|
|
||||||
[DllImport(LibCLibrary, EntryPoint = "write", SetLastError = true)]
|
[DllImport(LibCLibrary, EntryPoint = "strerror", SetLastError = true)]
|
||||||
public static extern int Write(int fd, byte[] buffer, int count);
|
private static extern String StrError(Int32 errnum);
|
||||||
|
|
||||||
/// <summary>
|
[DllImport("MonoPosixHelper", EntryPoint = "Mono_Posix_Syscall_strerror_r", SetLastError = true)]
|
||||||
/// Fills in the structure with information about the system.
|
private static extern Int32 Strerror(Int32 error, [Out] StringBuilder buffer, UInt64 length);
|
||||||
/// </summary>
|
|
||||||
/// <param name="name">The name.</param>
|
#endregion
|
||||||
/// <returns>The result</returns>
|
}
|
||||||
[DllImport(LibCLibrary, EntryPoint = "uname", SetLastError = true)]
|
|
||||||
public static extern int Uname(out SystemName name);
|
|
||||||
|
|
||||||
[DllImport(LibCLibrary, EntryPoint = "strerror", SetLastError = true)]
|
|
||||||
private static extern string StrError(int errnum);
|
|
||||||
|
|
||||||
[DllImport("MonoPosixHelper", EntryPoint = "Mono_Posix_Syscall_strerror_r", SetLastError = true)]
|
|
||||||
private static extern int Strerror(int error, [Out] StringBuilder buffer, ulong length);
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -1,47 +1,46 @@
|
|||||||
namespace Unosquare.RaspberryIO.Native
|
using System;
|
||||||
{
|
using System.Runtime.InteropServices;
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
namespace Unosquare.RaspberryIO.Native {
|
||||||
|
/// <summary>
|
||||||
|
/// OS uname structure
|
||||||
|
/// </summary>
|
||||||
|
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
|
||||||
|
internal struct SystemName {
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// OS uname structure
|
/// System name
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
|
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 65)]
|
||||||
internal struct SystemName
|
public String SysName;
|
||||||
{
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// System name
|
/// Node name
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 65)]
|
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 65)]
|
||||||
public string SysName;
|
public String NodeName;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Node name
|
/// Release level
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 65)]
|
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 65)]
|
||||||
public string NodeName;
|
public String Release;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Release level
|
/// Version level
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 65)]
|
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 65)]
|
||||||
public string Release;
|
public String Version;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Version level
|
/// Hardware level
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 65)]
|
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 65)]
|
||||||
public string Version;
|
public String Machine;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Hardware level
|
/// Domain name
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 65)]
|
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 65)]
|
||||||
public string Machine;
|
public String DomainName;
|
||||||
|
}
|
||||||
/// <summary>
|
|
||||||
/// Domain name
|
|
||||||
/// </summary>
|
|
||||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 65)]
|
|
||||||
public string DomainName;
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -1,28 +1,26 @@
|
|||||||
namespace Unosquare.RaspberryIO.Native
|
namespace Unosquare.RaspberryIO.Native {
|
||||||
{
|
/// <summary>
|
||||||
|
/// Defines the different threading locking keys
|
||||||
|
/// </summary>
|
||||||
|
public enum ThreadLockKey {
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Defines the different threading locking keys
|
/// The lock 0
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public enum ThreadLockKey
|
Lock0 = 0,
|
||||||
{
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The lock 0
|
/// The lock 1
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Lock0 = 0,
|
Lock1 = 1,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The lock 1
|
/// The lock 2
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Lock1 = 1,
|
Lock2 = 2,
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The lock 2
|
/// The lock 3
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Lock2 = 2,
|
Lock3 = 3,
|
||||||
|
}
|
||||||
/// <summary>
|
|
||||||
/// The lock 3
|
|
||||||
/// </summary>
|
|
||||||
Lock3 = 3,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,108 +1,108 @@
|
|||||||
namespace Unosquare.RaspberryIO.Native
|
using Unosquare.Swan;
|
||||||
{
|
using Unosquare.Swan.Abstractions;
|
||||||
using Swan;
|
using System;
|
||||||
using Swan.Abstractions;
|
|
||||||
using System;
|
namespace Unosquare.RaspberryIO.Native {
|
||||||
|
/// <summary>
|
||||||
|
/// Provides access to timing and threading properties and methods
|
||||||
|
/// </summary>
|
||||||
|
public class Timing : SingletonBase<Timing> {
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Provides access to timing and threading properties and methods
|
/// Prevents a default instance of the <see cref="Timing"/> class from being created.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class Timing : SingletonBase<Timing>
|
/// <exception cref="NotSupportedException">Could not initialize the GPIO controller</exception>
|
||||||
{
|
private Timing() {
|
||||||
/// <summary>
|
// placeholder
|
||||||
/// Prevents a default instance of the <see cref="Timing"/> class from being created.
|
}
|
||||||
/// </summary>
|
|
||||||
/// <exception cref="NotSupportedException">Could not initialize the GPIO controller</exception>
|
/// <summary>
|
||||||
private Timing()
|
/// This returns a number representing the number of milliseconds since your program
|
||||||
{
|
/// initialized the GPIO controller.
|
||||||
// placeholder
|
/// It returns an unsigned 32-bit number which wraps after 49 days.
|
||||||
}
|
/// </summary>
|
||||||
|
/// <value>
|
||||||
/// <summary>
|
/// The milliseconds since setup.
|
||||||
/// This returns a number representing the number of milliseconds since your program
|
/// </value>
|
||||||
/// initialized the GPIO controller.
|
public UInt32 MillisecondsSinceSetup => WiringPi.Millis();
|
||||||
/// It returns an unsigned 32-bit number which wraps after 49 days.
|
|
||||||
/// </summary>
|
/// <summary>
|
||||||
/// <value>
|
/// This returns a number representing the number of microseconds since your
|
||||||
/// The milliseconds since setup.
|
/// program initialized the GPIO controller
|
||||||
/// </value>
|
/// It returns an unsigned 32-bit number which wraps after approximately 71 minutes.
|
||||||
public uint MillisecondsSinceSetup => WiringPi.Millis();
|
/// </summary>
|
||||||
|
/// <value>
|
||||||
/// <summary>
|
/// The microseconds since setup.
|
||||||
/// This returns a number representing the number of microseconds since your
|
/// </value>
|
||||||
/// program initialized the GPIO controller
|
public UInt32 MicrosecondsSinceSetup => WiringPi.Micros();
|
||||||
/// It returns an unsigned 32-bit number which wraps after approximately 71 minutes.
|
|
||||||
/// </summary>
|
/// <summary>
|
||||||
/// <value>
|
/// This causes program execution to pause for at least howLong milliseconds.
|
||||||
/// The microseconds since setup.
|
/// Due to the multi-tasking nature of Linux it could be longer.
|
||||||
/// </value>
|
/// Note that the maximum delay is an unsigned 32-bit integer or approximately 49 days.
|
||||||
public uint MicrosecondsSinceSetup => WiringPi.Micros();
|
/// </summary>
|
||||||
|
/// <param name="value">The value.</param>
|
||||||
/// <summary>
|
public static void SleepMilliseconds(UInt32 value) => WiringPi.Delay(value);
|
||||||
/// This causes program execution to pause for at least howLong milliseconds.
|
|
||||||
/// Due to the multi-tasking nature of Linux it could be longer.
|
/// <summary>
|
||||||
/// Note that the maximum delay is an unsigned 32-bit integer or approximately 49 days.
|
/// This causes program execution to pause for at least howLong microseconds.
|
||||||
/// </summary>
|
/// Due to the multi-tasking nature of Linux it could be longer.
|
||||||
/// <param name="value">The value.</param>
|
/// Note that the maximum delay is an unsigned 32-bit integer microseconds or approximately 71 minutes.
|
||||||
public static void SleepMilliseconds(uint value) => WiringPi.Delay(value);
|
/// Delays under 100 microseconds are timed using a hard-coded loop continually polling the system time,
|
||||||
|
/// Delays over 100 microseconds are done using the system nanosleep() function –
|
||||||
/// <summary>
|
/// You may need to consider the implications of very short delays on the overall performance of the system,
|
||||||
/// This causes program execution to pause for at least howLong microseconds.
|
/// especially if using threads.
|
||||||
/// Due to the multi-tasking nature of Linux it could be longer.
|
/// </summary>
|
||||||
/// Note that the maximum delay is an unsigned 32-bit integer microseconds or approximately 71 minutes.
|
/// <param name="value">The value.</param>
|
||||||
/// Delays under 100 microseconds are timed using a hard-coded loop continually polling the system time,
|
public void SleepMicroseconds(UInt32 value) => WiringPi.DelayMicroseconds(value);
|
||||||
/// Delays over 100 microseconds are done using the system nanosleep() function –
|
|
||||||
/// You may need to consider the implications of very short delays on the overall performance of the system,
|
/// <summary>
|
||||||
/// especially if using threads.
|
/// This attempts to shift your program (or thread in a multi-threaded program) to a higher priority and
|
||||||
/// </summary>
|
/// enables a real-time scheduling. The priority parameter should be from 0 (the default) to 99 (the maximum).
|
||||||
/// <param name="value">The value.</param>
|
/// This won’t make your program go any faster, but it will give it a bigger slice of time when other programs
|
||||||
public void SleepMicroseconds(uint value) => WiringPi.DelayMicroseconds(value);
|
/// are running. The priority parameter works relative to others – so you can make one program priority 1 and
|
||||||
|
/// another priority 2 and it will have the same effect as setting one to 10 and the other to 90
|
||||||
/// <summary>
|
/// (as long as no other programs are running with elevated priorities)
|
||||||
/// This attempts to shift your program (or thread in a multi-threaded program) to a higher priority and
|
/// </summary>
|
||||||
/// enables a real-time scheduling. The priority parameter should be from 0 (the default) to 99 (the maximum).
|
/// <param name="priority">The priority.</param>
|
||||||
/// This won’t make your program go any faster, but it will give it a bigger slice of time when other programs
|
public void SetThreadPriority(Int32 priority) {
|
||||||
/// are running. The priority parameter works relative to others – so you can make one program priority 1 and
|
priority = priority.Clamp(0, 99);
|
||||||
/// another priority 2 and it will have the same effect as setting one to 10 and the other to 90
|
Int32 result = WiringPi.PiHiPri(priority);
|
||||||
/// (as long as no other programs are running with elevated priorities)
|
if(result < 0) {
|
||||||
/// </summary>
|
HardwareException.Throw(nameof(Timing), nameof(SetThreadPriority));
|
||||||
/// <param name="priority">The priority.</param>
|
}
|
||||||
public void SetThreadPriority(int priority)
|
}
|
||||||
{
|
|
||||||
priority = priority.Clamp(0, 99);
|
/// <summary>
|
||||||
var result = WiringPi.PiHiPri(priority);
|
/// This is really nothing more than a simplified interface to the Posix threads mechanism that Linux supports.
|
||||||
if (result < 0) HardwareException.Throw(nameof(Timing), nameof(SetThreadPriority));
|
/// See the manual pages on Posix threads (man pthread) if you need more control over them.
|
||||||
}
|
/// </summary>
|
||||||
|
/// <param name="worker">The worker.</param>
|
||||||
/// <summary>
|
/// <exception cref="ArgumentNullException">worker</exception>
|
||||||
/// This is really nothing more than a simplified interface to the Posix threads mechanism that Linux supports.
|
public void CreateThread(ThreadWorker worker) {
|
||||||
/// See the manual pages on Posix threads (man pthread) if you need more control over them.
|
if(worker == null) {
|
||||||
/// </summary>
|
throw new ArgumentNullException(nameof(worker));
|
||||||
/// <param name="worker">The worker.</param>
|
}
|
||||||
/// <exception cref="ArgumentNullException">worker</exception>
|
|
||||||
public void CreateThread(ThreadWorker worker)
|
Int32 result = WiringPi.PiThreadCreate(worker);
|
||||||
{
|
if(result != 0) {
|
||||||
if (worker == null)
|
HardwareException.Throw(nameof(Timing), nameof(CreateThread));
|
||||||
throw new ArgumentNullException(nameof(worker));
|
}
|
||||||
|
}
|
||||||
var result = WiringPi.PiThreadCreate(worker);
|
|
||||||
if (result != 0) HardwareException.Throw(nameof(Timing), nameof(CreateThread));
|
/// <summary>
|
||||||
}
|
/// These allow you to synchronize 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”. When another process tries to lock the same key,
|
||||||
/// <summary>
|
/// it will be stalled until the first process has unlocked the same key.
|
||||||
/// These allow you to synchronize variable updates from your main program to any threads running in your program.
|
/// </summary>
|
||||||
/// keyNum is a number from 0 to 3 and represents a “key”. When another process tries to lock the same key,
|
/// <param name="key">The key.</param>
|
||||||
/// it will be stalled until the first process has unlocked the same key.
|
public void Lock(ThreadLockKey key) => WiringPi.PiLock((Int32)key);
|
||||||
/// </summary>
|
|
||||||
/// <param name="key">The key.</param>
|
/// <summary>
|
||||||
public void Lock(ThreadLockKey key) => WiringPi.PiLock((int)key);
|
/// These allow you to synchronize 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”. When another process tries to lock the same key,
|
||||||
/// <summary>
|
/// it will be stalled until the first process has unlocked the same key.
|
||||||
/// These allow you to synchronize variable updates from your main program to any threads running in your program.
|
/// </summary>
|
||||||
/// keyNum is a number from 0 to 3 and represents a “key”. When another process tries to lock the same key,
|
/// <param name="key">The key.</param>
|
||||||
/// it will be stalled until the first process has unlocked the same key.
|
public void Unlock(ThreadLockKey key) => WiringPi.PiUnlock((Int32)key);
|
||||||
/// </summary>
|
}
|
||||||
/// <param name="key">The key.</param>
|
|
||||||
public void Unlock(ThreadLockKey key) => WiringPi.PiUnlock((int)key);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,79 +1,78 @@
|
|||||||
namespace Unosquare.RaspberryIO.Native
|
using System;
|
||||||
{
|
using System.Runtime.InteropServices;
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
namespace Unosquare.RaspberryIO.Native {
|
||||||
public partial class WiringPi
|
public partial class WiringPi {
|
||||||
{
|
#region WiringPi - I2C Library Calls
|
||||||
#region WiringPi - I2C Library Calls
|
|
||||||
|
/// <summary>
|
||||||
/// <summary>
|
/// Simple device read. Some devices present data when you read them without having to do any register transactions.
|
||||||
/// Simple device read. Some devices present data when you read them without having to do any register transactions.
|
/// </summary>
|
||||||
/// </summary>
|
/// <param name="fd">The fd.</param>
|
||||||
/// <param name="fd">The fd.</param>
|
/// <returns>The result</returns>
|
||||||
/// <returns>The result</returns>
|
[DllImport(WiringPiLibrary, EntryPoint = "wiringPiI2CRead", SetLastError = true)]
|
||||||
[DllImport(WiringPiLibrary, EntryPoint = "wiringPiI2CRead", SetLastError = true)]
|
public static extern Int32 WiringPiI2CRead(Int32 fd);
|
||||||
public static extern int WiringPiI2CRead(int fd);
|
|
||||||
|
/// <summary>
|
||||||
/// <summary>
|
/// These read an 8-bit value from the device register indicated.
|
||||||
/// These read an 8-bit value from the device register indicated.
|
/// </summary>
|
||||||
/// </summary>
|
/// <param name="fd">The fd.</param>
|
||||||
/// <param name="fd">The fd.</param>
|
/// <param name="reg">The reg.</param>
|
||||||
/// <param name="reg">The reg.</param>
|
/// <returns>The result</returns>
|
||||||
/// <returns>The result</returns>
|
[DllImport(WiringPiLibrary, EntryPoint = "wiringPiI2CReadReg8", SetLastError = true)]
|
||||||
[DllImport(WiringPiLibrary, EntryPoint = "wiringPiI2CReadReg8", SetLastError = true)]
|
public static extern Int32 WiringPiI2CReadReg8(Int32 fd, Int32 reg);
|
||||||
public static extern int WiringPiI2CReadReg8(int fd, int reg);
|
|
||||||
|
/// <summary>
|
||||||
/// <summary>
|
/// These read a 16-bit value from the device register indicated.
|
||||||
/// These read a 16-bit value from the device register indicated.
|
/// </summary>
|
||||||
/// </summary>
|
/// <param name="fd">The fd.</param>
|
||||||
/// <param name="fd">The fd.</param>
|
/// <param name="reg">The reg.</param>
|
||||||
/// <param name="reg">The reg.</param>
|
/// <returns>The result</returns>
|
||||||
/// <returns>The result</returns>
|
[DllImport(WiringPiLibrary, EntryPoint = "wiringPiI2CReadReg16", SetLastError = true)]
|
||||||
[DllImport(WiringPiLibrary, EntryPoint = "wiringPiI2CReadReg16", SetLastError = true)]
|
public static extern Int32 WiringPiI2CReadReg16(Int32 fd, Int32 reg);
|
||||||
public static extern int WiringPiI2CReadReg16(int fd, int reg);
|
|
||||||
|
/// <summary>
|
||||||
/// <summary>
|
/// Simple device write. Some devices accept data this way without needing to access any internal registers.
|
||||||
/// Simple device write. Some devices accept data this way without needing to access any internal registers.
|
/// </summary>
|
||||||
/// </summary>
|
/// <param name="fd">The fd.</param>
|
||||||
/// <param name="fd">The fd.</param>
|
/// <param name="data">The data.</param>
|
||||||
/// <param name="data">The data.</param>
|
/// <returns>The result</returns>
|
||||||
/// <returns>The result</returns>
|
[DllImport(WiringPiLibrary, EntryPoint = "wiringPiI2CWrite", SetLastError = true)]
|
||||||
[DllImport(WiringPiLibrary, EntryPoint = "wiringPiI2CWrite", SetLastError = true)]
|
public static extern Int32 WiringPiI2CWrite(Int32 fd, Int32 data);
|
||||||
public static extern int WiringPiI2CWrite(int fd, int data);
|
|
||||||
|
/// <summary>
|
||||||
/// <summary>
|
/// These write an 8-bit data value into the device register indicated.
|
||||||
/// These write an 8-bit data value into the device register indicated.
|
/// </summary>
|
||||||
/// </summary>
|
/// <param name="fd">The fd.</param>
|
||||||
/// <param name="fd">The fd.</param>
|
/// <param name="reg">The reg.</param>
|
||||||
/// <param name="reg">The reg.</param>
|
/// <param name="data">The data.</param>
|
||||||
/// <param name="data">The data.</param>
|
/// <returns>The result</returns>
|
||||||
/// <returns>The result</returns>
|
[DllImport(WiringPiLibrary, EntryPoint = "wiringPiI2CWriteReg8", SetLastError = true)]
|
||||||
[DllImport(WiringPiLibrary, EntryPoint = "wiringPiI2CWriteReg8", SetLastError = true)]
|
public static extern Int32 WiringPiI2CWriteReg8(Int32 fd, Int32 reg, Int32 data);
|
||||||
public static extern int WiringPiI2CWriteReg8(int fd, int reg, int data);
|
|
||||||
|
/// <summary>
|
||||||
/// <summary>
|
/// These write a 16-bit data value into the device register indicated.
|
||||||
/// These write a 16-bit data value into the device register indicated.
|
/// </summary>
|
||||||
/// </summary>
|
/// <param name="fd">The fd.</param>
|
||||||
/// <param name="fd">The fd.</param>
|
/// <param name="reg">The reg.</param>
|
||||||
/// <param name="reg">The reg.</param>
|
/// <param name="data">The data.</param>
|
||||||
/// <param name="data">The data.</param>
|
/// <returns>The result</returns>
|
||||||
/// <returns>The result</returns>
|
[DllImport(WiringPiLibrary, EntryPoint = "wiringPiI2CWriteReg16", SetLastError = true)]
|
||||||
[DllImport(WiringPiLibrary, EntryPoint = "wiringPiI2CWriteReg16", SetLastError = true)]
|
public static extern Int32 WiringPiI2CWriteReg16(Int32 fd, Int32 reg, Int32 data);
|
||||||
public static extern int WiringPiI2CWriteReg16(int fd, int reg, int data);
|
|
||||||
|
/// <summary>
|
||||||
/// <summary>
|
/// This initialises the I2C system with your given device identifier.
|
||||||
/// This initialises the I2C system with your given device identifier.
|
/// The ID is the I2C number of the device and you can use the i2cdetect program to find this out. wiringPiI2CSetup()
|
||||||
/// The ID is the I2C number of the device and you can use the i2cdetect program to find this out. wiringPiI2CSetup()
|
/// will work out which revision Raspberry Pi you have and open the appropriate device in /dev.
|
||||||
/// will work out which revision Raspberry Pi you have and open the appropriate device in /dev.
|
/// The return value is the standard Linux filehandle, or -1 if any error – in which case, you can consult errno as usual.
|
||||||
/// The return value is the standard Linux filehandle, or -1 if any error – in which case, you can consult errno as usual.
|
/// E.g. the popular MCP23017 GPIO expander is usually device Id 0x20, so this is the number you would pass into wiringPiI2CSetup().
|
||||||
/// E.g. the popular MCP23017 GPIO expander is usually device Id 0x20, so this is the number you would pass into wiringPiI2CSetup().
|
/// </summary>
|
||||||
/// </summary>
|
/// <param name="devId">The dev identifier.</param>
|
||||||
/// <param name="devId">The dev identifier.</param>
|
/// <returns>The result</returns>
|
||||||
/// <returns>The result</returns>
|
[DllImport(WiringPiLibrary, EntryPoint = "wiringPiI2CSetup", SetLastError = true)]
|
||||||
[DllImport(WiringPiLibrary, EntryPoint = "wiringPiI2CSetup", SetLastError = true)]
|
public static extern Int32 WiringPiI2CSetup(Int32 devId);
|
||||||
public static extern int WiringPiI2CSetup(int devId);
|
|
||||||
|
#endregion
|
||||||
#endregion
|
|
||||||
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,73 +1,72 @@
|
|||||||
namespace Unosquare.RaspberryIO.Native
|
using System;
|
||||||
{
|
using System.Runtime.InteropServices;
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
namespace Unosquare.RaspberryIO.Native {
|
||||||
public partial class WiringPi
|
public partial class WiringPi {
|
||||||
{
|
#region WiringPi - Serial Port
|
||||||
#region WiringPi - Serial Port
|
|
||||||
|
/// <summary>
|
||||||
/// <summary>
|
/// This opens and initialises the serial device and sets the baud rate. It sets the port into “raw” mode (character at a time and no translations),
|
||||||
/// This opens and initialises the serial device and sets the baud rate. It sets the port into “raw” mode (character at a time and no translations),
|
/// and sets the read timeout to 10 seconds. The return value is the file descriptor or -1 for any error, in which case errno will be set as appropriate.
|
||||||
/// and sets the read timeout to 10 seconds. The return value is the file descriptor or -1 for any error, in which case errno will be set as appropriate.
|
/// The wiringSerial library is intended to provide simplified control – suitable for most applications, however if you need advanced control
|
||||||
/// The wiringSerial library is intended to provide simplified control – suitable for most applications, however if you need advanced control
|
/// – e.g. parity control, modem control lines (via a USB adapter, there are none on the Pi’s on-board UART!) and so on,
|
||||||
/// – e.g. parity control, modem control lines (via a USB adapter, there are none on the Pi’s on-board UART!) and so on,
|
/// then you need to do some of this the old fashioned way.
|
||||||
/// then you need to do some of this the old fashioned way.
|
/// </summary>
|
||||||
/// </summary>
|
/// <param name="device">The device.</param>
|
||||||
/// <param name="device">The device.</param>
|
/// <param name="baud">The baud.</param>
|
||||||
/// <param name="baud">The baud.</param>
|
/// <returns>The result</returns>
|
||||||
/// <returns>The result</returns>
|
[DllImport(WiringPiLibrary, EntryPoint = "serialOpen", SetLastError = true)]
|
||||||
[DllImport(WiringPiLibrary, EntryPoint = "serialOpen", SetLastError = true)]
|
public static extern Int32 SerialOpen(String device, Int32 baud);
|
||||||
public static extern int SerialOpen(string device, int baud);
|
|
||||||
|
/// <summary>
|
||||||
/// <summary>
|
/// Closes the device identified by the file descriptor given.
|
||||||
/// Closes the device identified by the file descriptor given.
|
/// </summary>
|
||||||
/// </summary>
|
/// <param name="fd">The fd.</param>
|
||||||
/// <param name="fd">The fd.</param>
|
/// <returns>The result</returns>
|
||||||
/// <returns>The result</returns>
|
[DllImport(WiringPiLibrary, EntryPoint = "serialClose", SetLastError = true)]
|
||||||
[DllImport(WiringPiLibrary, EntryPoint = "serialClose", SetLastError = true)]
|
public static extern Int32 SerialClose(Int32 fd);
|
||||||
public static extern int SerialClose(int fd);
|
|
||||||
|
/// <summary>
|
||||||
/// <summary>
|
/// Sends the single byte to the serial device identified by the given file descriptor.
|
||||||
/// Sends the single byte to the serial device identified by the given file descriptor.
|
/// </summary>
|
||||||
/// </summary>
|
/// <param name="fd">The fd.</param>
|
||||||
/// <param name="fd">The fd.</param>
|
/// <param name="c">The c.</param>
|
||||||
/// <param name="c">The c.</param>
|
[DllImport(WiringPiLibrary, EntryPoint = "serialPutchar", SetLastError = true)]
|
||||||
[DllImport(WiringPiLibrary, EntryPoint = "serialPutchar", SetLastError = true)]
|
public static extern void SerialPutchar(Int32 fd, Byte c);
|
||||||
public static extern void SerialPutchar(int fd, byte c);
|
|
||||||
|
/// <summary>
|
||||||
/// <summary>
|
/// Sends the nul-terminated string to the serial device identified by the given file descriptor.
|
||||||
/// Sends the nul-terminated string to the serial device identified by the given file descriptor.
|
/// </summary>
|
||||||
/// </summary>
|
/// <param name="fd">The fd.</param>
|
||||||
/// <param name="fd">The fd.</param>
|
/// <param name="s">The s.</param>
|
||||||
/// <param name="s">The s.</param>
|
[DllImport(WiringPiLibrary, EntryPoint = "serialPuts", SetLastError = true)]
|
||||||
[DllImport(WiringPiLibrary, EntryPoint = "serialPuts", SetLastError = true)]
|
public static extern void SerialPuts(Int32 fd, String s);
|
||||||
public static extern void SerialPuts(int fd, string s);
|
|
||||||
|
/// <summary>
|
||||||
/// <summary>
|
/// Returns the number of characters available for reading, or -1 for any error condition,
|
||||||
/// Returns the number of characters available for reading, or -1 for any error condition,
|
/// in which case errno will be set appropriately.
|
||||||
/// in which case errno will be set appropriately.
|
/// </summary>
|
||||||
/// </summary>
|
/// <param name="fd">The fd.</param>
|
||||||
/// <param name="fd">The fd.</param>
|
/// <returns>The result</returns>
|
||||||
/// <returns>The result</returns>
|
[DllImport(WiringPiLibrary, EntryPoint = "serialDataAvail", SetLastError = true)]
|
||||||
[DllImport(WiringPiLibrary, EntryPoint = "serialDataAvail", SetLastError = true)]
|
public static extern Int32 SerialDataAvail(Int32 fd);
|
||||||
public static extern int SerialDataAvail(int fd);
|
|
||||||
|
/// <summary>
|
||||||
/// <summary>
|
/// Returns the next character available on the serial device.
|
||||||
/// Returns the next character available on the serial device.
|
/// This call will block for up to 10 seconds if no data is available (when it will return -1)
|
||||||
/// This call will block for up to 10 seconds if no data is available (when it will return -1)
|
/// </summary>
|
||||||
/// </summary>
|
/// <param name="fd">The fd.</param>
|
||||||
/// <param name="fd">The fd.</param>
|
/// <returns>The result</returns>
|
||||||
/// <returns>The result</returns>
|
[DllImport(WiringPiLibrary, EntryPoint = "serialGetchar", SetLastError = true)]
|
||||||
[DllImport(WiringPiLibrary, EntryPoint = "serialGetchar", SetLastError = true)]
|
public static extern Int32 SerialGetchar(Int32 fd);
|
||||||
public static extern int SerialGetchar(int fd);
|
|
||||||
|
/// <summary>
|
||||||
/// <summary>
|
/// This discards all data received, or waiting to be send down the given device.
|
||||||
/// This discards all data received, or waiting to be send down the given device.
|
/// </summary>
|
||||||
/// </summary>
|
/// <param name="fd">The fd.</param>
|
||||||
/// <param name="fd">The fd.</param>
|
[DllImport(WiringPiLibrary, EntryPoint = "serialFlush", SetLastError = true)]
|
||||||
[DllImport(WiringPiLibrary, EntryPoint = "serialFlush", SetLastError = true)]
|
public static extern void SerialFlush(Int32 fd);
|
||||||
public static extern void SerialFlush(int fd);
|
|
||||||
|
#endregion
|
||||||
#endregion
|
}
|
||||||
}
|
|
||||||
}
|
}
|
@ -1,36 +1,35 @@
|
|||||||
namespace Unosquare.RaspberryIO.Native
|
using System;
|
||||||
{
|
using System.Runtime.InteropServices;
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
namespace Unosquare.RaspberryIO.Native {
|
||||||
public partial class WiringPi
|
public partial class WiringPi {
|
||||||
{
|
#region WiringPi - Shift Library
|
||||||
#region WiringPi - Shift Library
|
|
||||||
|
/// <summary>
|
||||||
/// <summary>
|
/// This shifts an 8-bit data value in with the data appearing on the dPin and the clock being sent out on the cPin.
|
||||||
/// This shifts an 8-bit data value in with the data appearing on the dPin and the clock being sent out on the cPin.
|
/// Order is either LSBFIRST or MSBFIRST. The data is sampled after the cPin goes high.
|
||||||
/// Order is either LSBFIRST or MSBFIRST. The data is sampled after the cPin goes high.
|
/// (So cPin high, sample data, cPin low, repeat for 8 bits) The 8-bit value is returned by the function.
|
||||||
/// (So cPin high, sample data, cPin low, repeat for 8 bits) The 8-bit value is returned by the function.
|
/// </summary>
|
||||||
/// </summary>
|
/// <param name="dPin">The d pin.</param>
|
||||||
/// <param name="dPin">The d pin.</param>
|
/// <param name="cPin">The c pin.</param>
|
||||||
/// <param name="cPin">The c pin.</param>
|
/// <param name="order">The order.</param>
|
||||||
/// <param name="order">The order.</param>
|
/// <returns>The result</returns>
|
||||||
/// <returns>The result</returns>
|
[DllImport(WiringPiLibrary, EntryPoint = "shiftIn", SetLastError = true)]
|
||||||
[DllImport(WiringPiLibrary, EntryPoint = "shiftIn", SetLastError = true)]
|
public static extern Byte ShiftIn(Byte dPin, Byte cPin, Byte order);
|
||||||
public static extern byte ShiftIn(byte dPin, byte cPin, byte order);
|
|
||||||
|
/// <summary>
|
||||||
/// <summary>
|
/// The shifts an 8-bit data value val out with the data being sent out on dPin and the clock being sent out on the cPin.
|
||||||
/// The shifts an 8-bit data value val out with the data being sent out on dPin and the clock being sent out on the cPin.
|
/// order is as above. Data is clocked out on the rising or falling edge – ie. dPin is set, then cPin is taken high then low
|
||||||
/// order is as above. Data is clocked out on the rising or falling edge – ie. dPin is set, then cPin is taken high then low
|
/// – repeated for the 8 bits.
|
||||||
/// – repeated for the 8 bits.
|
/// </summary>
|
||||||
/// </summary>
|
/// <param name="dPin">The d pin.</param>
|
||||||
/// <param name="dPin">The d pin.</param>
|
/// <param name="cPin">The c pin.</param>
|
||||||
/// <param name="cPin">The c pin.</param>
|
/// <param name="order">The order.</param>
|
||||||
/// <param name="order">The order.</param>
|
/// <param name="val">The value.</param>
|
||||||
/// <param name="val">The value.</param>
|
[DllImport(WiringPiLibrary, EntryPoint = "shiftOut", SetLastError = true)]
|
||||||
[DllImport(WiringPiLibrary, EntryPoint = "shiftOut", SetLastError = true)]
|
public static extern void ShiftOut(Byte dPin, Byte cPin, Byte order, Byte val);
|
||||||
public static extern void ShiftOut(byte dPin, byte cPin, byte order, byte val);
|
|
||||||
|
#endregion
|
||||||
#endregion
|
|
||||||
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,64 +1,63 @@
|
|||||||
namespace Unosquare.RaspberryIO.Native
|
using System;
|
||||||
{
|
using System.Runtime.InteropServices;
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
namespace Unosquare.RaspberryIO.Native {
|
||||||
public partial class WiringPi
|
public partial class WiringPi {
|
||||||
{
|
#region WiringPi - Soft PWM (https://github.com/WiringPi/WiringPi/blob/master/wiringPi/softPwm.h)
|
||||||
#region WiringPi - Soft PWM (https://github.com/WiringPi/WiringPi/blob/master/wiringPi/softPwm.h)
|
|
||||||
|
/// <summary>
|
||||||
/// <summary>
|
/// This creates a software controlled PWM pin. You can use any GPIO pin and the pin numbering will be that of the wiringPiSetup()
|
||||||
/// This creates a software controlled PWM pin. You can use any GPIO pin and the pin numbering will be that of the wiringPiSetup()
|
/// function you used. Use 100 for the pwmRange, then the value can be anything from 0 (off) to 100 (fully on) for the given pin.
|
||||||
/// function you used. Use 100 for the pwmRange, then the value can be anything from 0 (off) to 100 (fully on) for the given pin.
|
/// The return value is 0 for success. Anything else and you should check the global errno variable to see what went wrong.
|
||||||
/// The return value is 0 for success. Anything else and you should check the global errno variable to see what went wrong.
|
/// </summary>
|
||||||
/// </summary>
|
/// <param name="pin">The pin.</param>
|
||||||
/// <param name="pin">The pin.</param>
|
/// <param name="initialValue">The initial value.</param>
|
||||||
/// <param name="initialValue">The initial value.</param>
|
/// <param name="pwmRange">The PWM range.</param>
|
||||||
/// <param name="pwmRange">The PWM range.</param>
|
/// <returns>The result</returns>
|
||||||
/// <returns>The result</returns>
|
[DllImport(WiringPiLibrary, EntryPoint = "softPwmCreate", SetLastError = true)]
|
||||||
[DllImport(WiringPiLibrary, EntryPoint = "softPwmCreate", SetLastError = true)]
|
public static extern Int32 SoftPwmCreate(Int32 pin, Int32 initialValue, Int32 pwmRange);
|
||||||
public static extern int SoftPwmCreate(int pin, int initialValue, int pwmRange);
|
|
||||||
|
/// <summary>
|
||||||
/// <summary>
|
/// This updates the PWM value on the given pin. The value is checked to be in-range and pins that haven’t previously
|
||||||
/// This updates the PWM value on the given pin. The value is checked to be in-range and pins that haven’t previously
|
/// been initialized via softPwmCreate will be silently ignored.
|
||||||
/// been initialized via softPwmCreate will be silently ignored.
|
/// </summary>
|
||||||
/// </summary>
|
/// <param name="pin">The pin.</param>
|
||||||
/// <param name="pin">The pin.</param>
|
/// <param name="value">The value.</param>
|
||||||
/// <param name="value">The value.</param>
|
[DllImport(WiringPiLibrary, EntryPoint = "softPwmWrite", SetLastError = true)]
|
||||||
[DllImport(WiringPiLibrary, EntryPoint = "softPwmWrite", SetLastError = true)]
|
public static extern void SoftPwmWrite(Int32 pin, Int32 value);
|
||||||
public static extern void SoftPwmWrite(int pin, int value);
|
|
||||||
|
/// <summary>
|
||||||
/// <summary>
|
/// This function is undocumented
|
||||||
/// This function is undocumented
|
/// </summary>
|
||||||
/// </summary>
|
/// <param name="pin">The pin.</param>
|
||||||
/// <param name="pin">The pin.</param>
|
[DllImport(WiringPiLibrary, EntryPoint = "softPwmStop", SetLastError = true)]
|
||||||
[DllImport(WiringPiLibrary, EntryPoint = "softPwmStop", SetLastError = true)]
|
public static extern void SoftPwmStop(Int32 pin);
|
||||||
public static extern void SoftPwmStop(int pin);
|
|
||||||
|
/// <summary>
|
||||||
/// <summary>
|
/// This creates a software controlled tone pin. You can use any GPIO pin and the pin numbering will be that of the wiringPiSetup() function you used.
|
||||||
/// This creates a software controlled tone pin. You can use any GPIO pin and the pin numbering will be that of the wiringPiSetup() function you used.
|
/// The return value is 0 for success. Anything else and you should check the global errno variable to see what went wrong.
|
||||||
/// The return value is 0 for success. Anything else and you should check the global errno variable to see what went wrong.
|
/// </summary>
|
||||||
/// </summary>
|
/// <param name="pin">The pin.</param>
|
||||||
/// <param name="pin">The pin.</param>
|
/// <returns>The result</returns>
|
||||||
/// <returns>The result</returns>
|
[DllImport(WiringPiLibrary, EntryPoint = "softToneCreate", SetLastError = true)]
|
||||||
[DllImport(WiringPiLibrary, EntryPoint = "softToneCreate", SetLastError = true)]
|
public static extern Int32 SoftToneCreate(Int32 pin);
|
||||||
public static extern int SoftToneCreate(int pin);
|
|
||||||
|
/// <summary>
|
||||||
/// <summary>
|
/// This function is undocumented
|
||||||
/// This function is undocumented
|
/// </summary>
|
||||||
/// </summary>
|
/// <param name="pin">The pin.</param>
|
||||||
/// <param name="pin">The pin.</param>
|
[DllImport(WiringPiLibrary, EntryPoint = "softToneStop", SetLastError = true)]
|
||||||
[DllImport(WiringPiLibrary, EntryPoint = "softToneStop", SetLastError = true)]
|
public static extern void SoftToneStop(Int32 pin);
|
||||||
public static extern void SoftToneStop(int pin);
|
|
||||||
|
/// <summary>
|
||||||
/// <summary>
|
/// This updates the tone frequency value on the given pin. The tone will be played until you set the frequency to 0.
|
||||||
/// This updates the tone frequency value on the given pin. The tone will be played until you set the frequency to 0.
|
/// </summary>
|
||||||
/// </summary>
|
/// <param name="pin">The pin.</param>
|
||||||
/// <param name="pin">The pin.</param>
|
/// <param name="freq">The freq.</param>
|
||||||
/// <param name="freq">The freq.</param>
|
[DllImport(WiringPiLibrary, EntryPoint = "softToneWrite", SetLastError = true)]
|
||||||
[DllImport(WiringPiLibrary, EntryPoint = "softToneWrite", SetLastError = true)]
|
public static extern void SoftToneWrite(Int32 pin, Int32 freq);
|
||||||
public static extern void SoftToneWrite(int pin, int freq);
|
|
||||||
|
#endregion
|
||||||
#endregion
|
|
||||||
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,53 +1,52 @@
|
|||||||
namespace Unosquare.RaspberryIO.Native
|
using System;
|
||||||
{
|
using System.Runtime.InteropServices;
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
|
namespace Unosquare.RaspberryIO.Native {
|
||||||
public partial class WiringPi
|
public partial class WiringPi {
|
||||||
{
|
#region WiringPi - SPI Library Calls
|
||||||
#region WiringPi - SPI Library Calls
|
|
||||||
|
/// <summary>
|
||||||
/// <summary>
|
/// This function is undocumented
|
||||||
/// This function is undocumented
|
/// </summary>
|
||||||
/// </summary>
|
/// <param name="channel">The channel.</param>
|
||||||
/// <param name="channel">The channel.</param>
|
/// <returns>Unknown</returns>
|
||||||
/// <returns>Unknown</returns>
|
[DllImport(WiringPiLibrary, EntryPoint = "wiringPiSPIGetFd", SetLastError = true)]
|
||||||
[DllImport(WiringPiLibrary, EntryPoint = "wiringPiSPIGetFd", SetLastError = true)]
|
public static extern Int32 WiringPiSPIGetFd(Int32 channel);
|
||||||
public static extern int WiringPiSPIGetFd(int channel);
|
|
||||||
|
/// <summary>
|
||||||
/// <summary>
|
/// This performs a simultaneous write/read transaction over the selected SPI bus. Data that was in your buffer is overwritten by data returned from the SPI bus.
|
||||||
/// This performs a simultaneous write/read transaction over the selected SPI bus. Data that was in your buffer is overwritten by data returned from the SPI bus.
|
/// That’s all there is in the helper library. It is possible to do simple read and writes over the SPI bus using the standard read() and write() system calls though –
|
||||||
/// That’s all there is in the helper library. It is possible to do simple read and writes over the SPI bus using the standard read() and write() system calls though –
|
/// write() may be better to use for sending data to chains of shift registers, or those LED strings where you send RGB triplets of data.
|
||||||
/// write() may be better to use for sending data to chains of shift registers, or those LED strings where you send RGB triplets of data.
|
/// Devices such as A/D and D/A converters usually need to perform a concurrent write/read transaction to work.
|
||||||
/// Devices such as A/D and D/A converters usually need to perform a concurrent write/read transaction to work.
|
/// </summary>
|
||||||
/// </summary>
|
/// <param name="channel">The channel.</param>
|
||||||
/// <param name="channel">The channel.</param>
|
/// <param name="data">The data.</param>
|
||||||
/// <param name="data">The data.</param>
|
/// <param name="len">The length.</param>
|
||||||
/// <param name="len">The length.</param>
|
/// <returns>The result</returns>
|
||||||
/// <returns>The result</returns>
|
[DllImport(WiringPiLibrary, EntryPoint = "wiringPiSPIDataRW", SetLastError = true)]
|
||||||
[DllImport(WiringPiLibrary, EntryPoint = "wiringPiSPIDataRW", SetLastError = true)]
|
public static extern Int32 WiringPiSPIDataRW(Int32 channel, Byte[] data, Int32 len);
|
||||||
public static extern int WiringPiSPIDataRW(int channel, byte[] data, int len);
|
|
||||||
|
/// <summary>
|
||||||
/// <summary>
|
/// This function is undocumented
|
||||||
/// This function is undocumented
|
/// </summary>
|
||||||
/// </summary>
|
/// <param name="channel">The channel.</param>
|
||||||
/// <param name="channel">The channel.</param>
|
/// <param name="speed">The speed.</param>
|
||||||
/// <param name="speed">The speed.</param>
|
/// <param name="mode">The mode.</param>
|
||||||
/// <param name="mode">The mode.</param>
|
/// <returns>Unkown</returns>
|
||||||
/// <returns>Unkown</returns>
|
[DllImport(WiringPiLibrary, EntryPoint = "wiringPiSPISetupMode", SetLastError = true)]
|
||||||
[DllImport(WiringPiLibrary, EntryPoint = "wiringPiSPISetupMode", SetLastError = true)]
|
public static extern Int32 WiringPiSPISetupMode(Int32 channel, Int32 speed, Int32 mode);
|
||||||
public static extern int WiringPiSPISetupMode(int channel, int speed, int mode);
|
|
||||||
|
/// <summary>
|
||||||
/// <summary>
|
/// This is the way to initialize a channel (The Pi has 2 channels; 0 and 1). The speed parameter is an integer
|
||||||
/// This is the way to initialize a channel (The Pi has 2 channels; 0 and 1). The speed parameter is an integer
|
/// in the range 500,000 through 32,000,000 and represents the SPI clock speed in Hz.
|
||||||
/// in the range 500,000 through 32,000,000 and represents the SPI clock speed in Hz.
|
/// The returned value is the Linux file-descriptor for the device, or -1 on error. If an error has happened, you may use the standard errno global variable to see why.
|
||||||
/// The returned value is the Linux file-descriptor for the device, or -1 on error. If an error has happened, you may use the standard errno global variable to see why.
|
/// </summary>
|
||||||
/// </summary>
|
/// <param name="channel">The channel.</param>
|
||||||
/// <param name="channel">The channel.</param>
|
/// <param name="speed">The speed.</param>
|
||||||
/// <param name="speed">The speed.</param>
|
/// <returns>The Linux file descriptor for the device or -1 for error</returns>
|
||||||
/// <returns>The Linux file descriptor for the device or -1 for error</returns>
|
[DllImport(WiringPiLibrary, EntryPoint = "wiringPiSPISetup", SetLastError = true)]
|
||||||
[DllImport(WiringPiLibrary, EntryPoint = "wiringPiSPISetup", SetLastError = true)]
|
public static extern Int32 WiringPiSPISetup(Int32 channel, Int32 speed);
|
||||||
public static extern int WiringPiSPISetup(int channel, int speed);
|
|
||||||
|
#endregion
|
||||||
#endregion
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,394 +1,392 @@
|
|||||||
namespace Unosquare.RaspberryIO.Native
|
using System;
|
||||||
{
|
using System.Runtime.InteropServices;
|
||||||
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";
|
||||||
|
|
||||||
|
#region WiringPi - Core Functions (https://github.com/WiringPi/WiringPi/blob/master/wiringPi/wiringPi.h)
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Provides native C WiringPi Library function call wrappers
|
/// This initialises wiringPi and assumes that the calling program is going to be using the wiringPi pin numbering scheme.
|
||||||
/// All credit for the native library goes to the author of http://wiringpi.com/
|
/// This is a simplified numbering scheme which provides a mapping from virtual pin numbers 0 through 16 to the real underlying Broadcom GPIO pin numbers.
|
||||||
/// The wrappers were written based on https://github.com/WiringPi/WiringPi/blob/master/wiringPi/wiringPi.h
|
/// See the pins page for a table which maps the wiringPi pin number to the Broadcom GPIO pin number to the physical location on the edge connector.
|
||||||
|
/// This function needs to be called with root privileges.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public partial class WiringPi
|
/// <returns>The result code</returns>
|
||||||
{
|
[DllImport(WiringPiLibrary, EntryPoint = "wiringPiSetup", SetLastError = true)]
|
||||||
internal const string WiringPiLibrary = "libwiringPi.so.2.46";
|
public static extern Int32 WiringPiSetup();
|
||||||
|
|
||||||
#region WiringPi - Core Functions (https://github.com/WiringPi/WiringPi/blob/master/wiringPi/wiringPi.h)
|
/// <summary>
|
||||||
|
/// This initialises wiringPi but uses the /sys/class/gpio interface rather than accessing the hardware directly.
|
||||||
/// <summary>
|
/// This can be called as a non-root user provided the GPIO pins have been exported before-hand using the gpio program.
|
||||||
/// This initialises wiringPi and assumes that the calling program is going to be using the wiringPi pin numbering scheme.
|
/// Pin numbering in this mode is the native Broadcom GPIO numbers – the same as wiringPiSetupGpio() above,
|
||||||
/// This is a simplified numbering scheme which provides a mapping from virtual pin numbers 0 through 16 to the real underlying Broadcom GPIO pin numbers.
|
/// so be aware of the differences between Rev 1 and Rev 2 boards.
|
||||||
/// See the pins page for a table which maps the wiringPi pin number to the Broadcom GPIO pin number to the physical location on the edge connector.
|
///
|
||||||
/// This function needs to be called with root privileges.
|
/// Note: In this mode you can only use the pins which have been exported via the /sys/class/gpio interface before you run your program.
|
||||||
/// </summary>
|
/// You can do this in a separate shell-script, or by using the system() function from inside your program to call the gpio program.
|
||||||
/// <returns>The result code</returns>
|
/// Also note that some functions have no effect when using this mode as they’re not currently possible to action unless called with root privileges.
|
||||||
[DllImport(WiringPiLibrary, EntryPoint = "wiringPiSetup", SetLastError = true)]
|
/// (although you can use system() to call gpio to set/change modes if needed)
|
||||||
public static extern int WiringPiSetup();
|
/// </summary>
|
||||||
|
/// <returns>The result code</returns>
|
||||||
/// <summary>
|
[DllImport(WiringPiLibrary, EntryPoint = "wiringPiSetupSys", SetLastError = true)]
|
||||||
/// This initialises wiringPi but uses the /sys/class/gpio interface rather than accessing the hardware directly.
|
public static extern Int32 WiringPiSetupSys();
|
||||||
/// This can be called as a non-root user provided the GPIO pins have been exported before-hand using the gpio program.
|
|
||||||
/// Pin numbering in this mode is the native Broadcom GPIO numbers – the same as wiringPiSetupGpio() above,
|
/// <summary>
|
||||||
/// so be aware of the differences between Rev 1 and Rev 2 boards.
|
/// This is identical to wiringPiSetup, however it allows the calling programs to use the Broadcom GPIO
|
||||||
///
|
/// pin numbers directly with no re-mapping.
|
||||||
/// Note: In this mode you can only use the pins which have been exported via the /sys/class/gpio interface before you run your program.
|
/// As above, this function needs to be called with root privileges, and note that some pins are different
|
||||||
/// You can do this in a separate shell-script, or by using the system() function from inside your program to call the gpio program.
|
/// from revision 1 to revision 2 boards.
|
||||||
/// Also note that some functions have no effect when using this mode as they’re not currently possible to action unless called with root privileges.
|
/// </summary>
|
||||||
/// (although you can use system() to call gpio to set/change modes if needed)
|
/// <returns>The result code</returns>
|
||||||
/// </summary>
|
[DllImport(WiringPiLibrary, EntryPoint = "wiringPiSetupGpio", SetLastError = true)]
|
||||||
/// <returns>The result code</returns>
|
public static extern Int32 WiringPiSetupGpio();
|
||||||
[DllImport(WiringPiLibrary, EntryPoint = "wiringPiSetupSys", SetLastError = true)]
|
|
||||||
public static extern int WiringPiSetupSys();
|
/// <summary>
|
||||||
|
/// Identical to wiringPiSetup, however it allows the calling programs to use the physical pin numbers on the P1 connector only.
|
||||||
/// <summary>
|
/// This function needs to be called with root privileges.
|
||||||
/// This is identical to wiringPiSetup, however it allows the calling programs to use the Broadcom GPIO
|
/// </summary>
|
||||||
/// pin numbers directly with no re-mapping.
|
/// <returns>The result code</returns>
|
||||||
/// As above, this function needs to be called with root privileges, and note that some pins are different
|
[DllImport(WiringPiLibrary, EntryPoint = "wiringPiSetupPhys", SetLastError = true)]
|
||||||
/// from revision 1 to revision 2 boards.
|
public static extern Int32 WiringPiSetupPhys();
|
||||||
/// </summary>
|
|
||||||
/// <returns>The result code</returns>
|
/// <summary>
|
||||||
[DllImport(WiringPiLibrary, EntryPoint = "wiringPiSetupGpio", SetLastError = true)]
|
/// This function is undocumented
|
||||||
public static extern int WiringPiSetupGpio();
|
/// </summary>
|
||||||
|
/// <param name="pin">The pin.</param>
|
||||||
/// <summary>
|
/// <param name="mode">The mode.</param>
|
||||||
/// Identical to wiringPiSetup, however it allows the calling programs to use the physical pin numbers on the P1 connector only.
|
[DllImport(WiringPiLibrary, EntryPoint = "pinModeAlt", SetLastError = true)]
|
||||||
/// This function needs to be called with root privileges.
|
public static extern void PinModeAlt(Int32 pin, Int32 mode);
|
||||||
/// </summary>
|
|
||||||
/// <returns>The result code</returns>
|
/// <summary>
|
||||||
[DllImport(WiringPiLibrary, EntryPoint = "wiringPiSetupPhys", SetLastError = true)]
|
/// This sets the mode of a pin to either INPUT, OUTPUT, PWM_OUTPUT or GPIO_CLOCK.
|
||||||
public static extern int WiringPiSetupPhys();
|
/// Note that only wiringPi pin 1 (BCM_GPIO 18) supports PWM output and only wiringPi pin 7 (BCM_GPIO 4)
|
||||||
|
/// supports CLOCK output modes.
|
||||||
/// <summary>
|
///
|
||||||
/// This function is undocumented
|
/// This function has no effect when in Sys mode. If you need to change the pin mode, then you can
|
||||||
/// </summary>
|
/// do it with the gpio program in a script before you start your program.
|
||||||
/// <param name="pin">The pin.</param>
|
/// </summary>
|
||||||
/// <param name="mode">The mode.</param>
|
/// <param name="pin">The pin.</param>
|
||||||
[DllImport(WiringPiLibrary, EntryPoint = "pinModeAlt", SetLastError = true)]
|
/// <param name="mode">The mode.</param>
|
||||||
public static extern void PinModeAlt(int pin, int mode);
|
[DllImport(WiringPiLibrary, EntryPoint = "pinMode", SetLastError = true)]
|
||||||
|
public static extern void PinMode(Int32 pin, Int32 mode);
|
||||||
/// <summary>
|
|
||||||
/// This sets the mode of a pin to either INPUT, OUTPUT, PWM_OUTPUT or GPIO_CLOCK.
|
/// <summary>
|
||||||
/// Note that only wiringPi pin 1 (BCM_GPIO 18) supports PWM output and only wiringPi pin 7 (BCM_GPIO 4)
|
/// This sets the pull-up or pull-down resistor mode on the given pin, which should be set as an input.
|
||||||
/// supports CLOCK output modes.
|
/// Unlike the Arduino, the BCM2835 has both pull-up an down internal resistors. 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
|
||||||
/// This function has no effect when in Sys mode. If you need to change the pin mode, then you can
|
/// have a value of approximately 50KΩ on the Raspberry Pi.
|
||||||
/// do it with the gpio program in a script before you start your program.
|
///
|
||||||
/// </summary>
|
/// This function has no effect on the Raspberry Pi’s GPIO pins when in Sys mode.
|
||||||
/// <param name="pin">The pin.</param>
|
/// If you need to activate a pull-up/pull-down, then you can do it with the gpio program in a script before you start your program.
|
||||||
/// <param name="mode">The mode.</param>
|
/// </summary>
|
||||||
[DllImport(WiringPiLibrary, EntryPoint = "pinMode", SetLastError = true)]
|
/// <param name="pin">The pin.</param>
|
||||||
public static extern void PinMode(int pin, int mode);
|
/// <param name="pud">The pud.</param>
|
||||||
|
[DllImport(WiringPiLibrary, EntryPoint = "pullUpDnControl", SetLastError = true)]
|
||||||
/// <summary>
|
public static extern void PullUpDnControl(Int32 pin, Int32 pud);
|
||||||
/// This sets the pull-up or pull-down resistor mode on the given pin, which should be set as an input.
|
|
||||||
/// Unlike the Arduino, the BCM2835 has both pull-up an down internal resistors. The parameter pud should be; PUD_OFF,
|
/// <summary>
|
||||||
/// (no pull up/down), PUD_DOWN (pull to ground) or PUD_UP (pull to 3.3v) The internal pull up/down resistors
|
/// 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.
|
||||||
/// have a value of approximately 50KΩ on the Raspberry Pi.
|
/// </summary>
|
||||||
///
|
/// <param name="pin">The pin.</param>
|
||||||
/// This function has no effect on the Raspberry Pi’s GPIO pins when in Sys mode.
|
/// <returns>The result code</returns>
|
||||||
/// If you need to activate a pull-up/pull-down, then you can do it with the gpio program in a script before you start your program.
|
[DllImport(WiringPiLibrary, EntryPoint = "digitalRead", SetLastError = true)]
|
||||||
/// </summary>
|
public static extern Int32 DigitalRead(Int32 pin);
|
||||||
/// <param name="pin">The pin.</param>
|
|
||||||
/// <param name="pud">The pud.</param>
|
/// <summary>
|
||||||
[DllImport(WiringPiLibrary, EntryPoint = "pullUpDnControl", SetLastError = true)]
|
/// Writes the value HIGH or LOW (1 or 0) to the given pin which must have been previously set as an output.
|
||||||
public static extern void PullUpDnControl(int pin, int pud);
|
/// WiringPi treats any non-zero number as HIGH, however 0 is the only representation of LOW.
|
||||||
|
/// </summary>
|
||||||
/// <summary>
|
/// <param name="pin">The pin.</param>
|
||||||
/// 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.
|
/// <param name="value">The value.</param>
|
||||||
/// </summary>
|
[DllImport(WiringPiLibrary, EntryPoint = "digitalWrite", SetLastError = true)]
|
||||||
/// <param name="pin">The pin.</param>
|
public static extern void DigitalWrite(Int32 pin, Int32 value);
|
||||||
/// <returns>The result code</returns>
|
|
||||||
[DllImport(WiringPiLibrary, EntryPoint = "digitalRead", SetLastError = true)]
|
/// <summary>
|
||||||
public static extern int DigitalRead(int pin);
|
/// Writes the value to the PWM register for the given pin. The Raspberry Pi has one
|
||||||
|
/// on-board PWM pin, pin 1 (BMC_GPIO 18, Phys 12) and the range is 0-1024.
|
||||||
/// <summary>
|
/// Other PWM devices may have other PWM ranges.
|
||||||
/// Writes the value HIGH or LOW (1 or 0) to the given pin which must have been previously set as an output.
|
/// This function is not able to control the Pi’s on-board PWM when in Sys mode.
|
||||||
/// WiringPi treats any non-zero number as HIGH, however 0 is the only representation of LOW.
|
/// </summary>
|
||||||
/// </summary>
|
/// <param name="pin">The pin.</param>
|
||||||
/// <param name="pin">The pin.</param>
|
/// <param name="value">The value.</param>
|
||||||
/// <param name="value">The value.</param>
|
[DllImport(WiringPiLibrary, EntryPoint = "pwmWrite", SetLastError = true)]
|
||||||
[DllImport(WiringPiLibrary, EntryPoint = "digitalWrite", SetLastError = true)]
|
public static extern void PwmWrite(Int32 pin, Int32 value);
|
||||||
public static extern void DigitalWrite(int pin, int value);
|
|
||||||
|
/// <summary>
|
||||||
/// <summary>
|
/// This returns the value read on the supplied analog input pin. You will need to
|
||||||
/// Writes the value to the PWM register for the given pin. The Raspberry Pi has one
|
/// register additional analog modules to enable this function for devices such as the Gertboard, quick2Wire analog board, etc.
|
||||||
/// on-board PWM pin, pin 1 (BMC_GPIO 18, Phys 12) and the range is 0-1024.
|
/// </summary>
|
||||||
/// Other PWM devices may have other PWM ranges.
|
/// <param name="pin">The pin.</param>
|
||||||
/// This function is not able to control the Pi’s on-board PWM when in Sys mode.
|
/// <returns>The result code</returns>
|
||||||
/// </summary>
|
[DllImport(WiringPiLibrary, EntryPoint = "analogRead", SetLastError = true)]
|
||||||
/// <param name="pin">The pin.</param>
|
public static extern Int32 AnalogRead(Int32 pin);
|
||||||
/// <param name="value">The value.</param>
|
|
||||||
[DllImport(WiringPiLibrary, EntryPoint = "pwmWrite", SetLastError = true)]
|
/// <summary>
|
||||||
public static extern void PwmWrite(int pin, int value);
|
/// This writes the given value to the supplied analog pin. You will need to register additional
|
||||||
|
/// analog modules to enable this function for devices such as the Gertboard.
|
||||||
/// <summary>
|
/// </summary>
|
||||||
/// This returns the value read on the supplied analog input pin. You will need to
|
/// <param name="pin">The pin.</param>
|
||||||
/// register additional analog modules to enable this function for devices such as the Gertboard, quick2Wire analog board, etc.
|
/// <param name="value">The value.</param>
|
||||||
/// </summary>
|
[DllImport(WiringPiLibrary, EntryPoint = "analogWrite", SetLastError = true)]
|
||||||
/// <param name="pin">The pin.</param>
|
public static extern void AnalogWrite(Int32 pin, Int32 value);
|
||||||
/// <returns>The result code</returns>
|
|
||||||
[DllImport(WiringPiLibrary, EntryPoint = "analogRead", SetLastError = true)]
|
/// <summary>
|
||||||
public static extern int AnalogRead(int pin);
|
/// 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
|
||||||
|
/// function when moving from board revision 1 to 2, so if you are using BCM_GPIO pin numbers, then you need to be aware of the differences.
|
||||||
/// <summary>
|
/// </summary>
|
||||||
/// This writes the given value to the supplied analog pin. You will need to register additional
|
/// <returns>The result code</returns>
|
||||||
/// analog modules to enable this function for devices such as the Gertboard.
|
[DllImport(WiringPiLibrary, EntryPoint = "piBoardRev", SetLastError = true)]
|
||||||
/// </summary>
|
public static extern Int32 PiBoardRev();
|
||||||
/// <param name="pin">The pin.</param>
|
|
||||||
/// <param name="value">The value.</param>
|
/// <summary>
|
||||||
[DllImport(WiringPiLibrary, EntryPoint = "analogWrite", SetLastError = true)]
|
/// This function is undocumented
|
||||||
public static extern void AnalogWrite(int pin, int value);
|
/// </summary>
|
||||||
|
/// <param name="model">The model.</param>
|
||||||
/// <summary>
|
/// <param name="mem">The memory.</param>
|
||||||
/// 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
|
/// <param name="maker">The maker.</param>
|
||||||
/// function when moving from board revision 1 to 2, so if you are using BCM_GPIO pin numbers, then you need to be aware of the differences.
|
/// <param name="overVolted">The over volted.</param>
|
||||||
/// </summary>
|
/// <returns>The result code</returns>
|
||||||
/// <returns>The result code</returns>
|
[DllImport(WiringPiLibrary, EntryPoint = "piBoardId", SetLastError = true)]
|
||||||
[DllImport(WiringPiLibrary, EntryPoint = "piBoardRev", SetLastError = true)]
|
public static extern Int32 PiBoardId(ref Int32 model, ref Int32 mem, ref Int32 maker, ref Int32 overVolted);
|
||||||
public static extern int PiBoardRev();
|
|
||||||
|
/// <summary>
|
||||||
/// <summary>
|
/// This returns the BCM_GPIO pin number of the supplied wiringPi pin. It takes the board revision into account.
|
||||||
/// This function is undocumented
|
/// </summary>
|
||||||
/// </summary>
|
/// <param name="wPiPin">The w pi pin.</param>
|
||||||
/// <param name="model">The model.</param>
|
/// <returns>The result code</returns>
|
||||||
/// <param name="mem">The memory.</param>
|
[DllImport(WiringPiLibrary, EntryPoint = "wpiPinToGpio", SetLastError = true)]
|
||||||
/// <param name="maker">The maker.</param>
|
public static extern Int32 WpiPinToGpio(Int32 wPiPin);
|
||||||
/// <param name="overVolted">The over volted.</param>
|
|
||||||
/// <returns>The result code</returns>
|
/// <summary>
|
||||||
[DllImport(WiringPiLibrary, EntryPoint = "piBoardId", SetLastError = true)]
|
/// This returns the BCM_GPIO pin number of the supplied physical pin on the P1 connector.
|
||||||
public static extern int PiBoardId(ref int model, ref int mem, ref int maker, ref int overVolted);
|
/// </summary>
|
||||||
|
/// <param name="physPin">The physical pin.</param>
|
||||||
/// <summary>
|
/// <returns>The result code</returns>
|
||||||
/// This returns the BCM_GPIO pin number of the supplied wiringPi pin. It takes the board revision into account.
|
[DllImport(WiringPiLibrary, EntryPoint = "physPinToGpio", SetLastError = true)]
|
||||||
/// </summary>
|
public static extern Int32 PhysPinToGpio(Int32 physPin);
|
||||||
/// <param name="wPiPin">The w pi pin.</param>
|
|
||||||
/// <returns>The result code</returns>
|
/// <summary>
|
||||||
[DllImport(WiringPiLibrary, EntryPoint = "wpiPinToGpio", SetLastError = true)]
|
/// This sets the “strength” of the pad drivers for a particular group of pins.
|
||||||
public static extern int WpiPinToGpio(int wPiPin);
|
/// There are 3 groups of pins and the drive strength is from 0 to 7. Do not use this unless you know what you are doing.
|
||||||
|
/// </summary>
|
||||||
/// <summary>
|
/// <param name="group">The group.</param>
|
||||||
/// This returns the BCM_GPIO pin number of the supplied physical pin on the P1 connector.
|
/// <param name="value">The value.</param>
|
||||||
/// </summary>
|
/// <returns>The result code</returns>
|
||||||
/// <param name="physPin">The physical pin.</param>
|
[DllImport(WiringPiLibrary, EntryPoint = "setPadDrive", SetLastError = true)]
|
||||||
/// <returns>The result code</returns>
|
public static extern Int32 SetPadDrive(Int32 group, Int32 value);
|
||||||
[DllImport(WiringPiLibrary, EntryPoint = "physPinToGpio", SetLastError = true)]
|
|
||||||
public static extern int PhysPinToGpio(int physPin);
|
/// <summary>
|
||||||
|
/// Undocumented function
|
||||||
/// <summary>
|
/// </summary>
|
||||||
/// This sets the “strength” of the pad drivers for a particular group of pins.
|
/// <param name="pin">The pin.</param>
|
||||||
/// There are 3 groups of pins and the drive strength is from 0 to 7. Do not use this unless you know what you are doing.
|
/// <returns>The result code</returns>
|
||||||
/// </summary>
|
[DllImport(WiringPiLibrary, EntryPoint = "getAlt", SetLastError = true)]
|
||||||
/// <param name="group">The group.</param>
|
public static extern Int32 GetAlt(Int32 pin);
|
||||||
/// <param name="value">The value.</param>
|
|
||||||
/// <returns>The result code</returns>
|
/// <summary>
|
||||||
[DllImport(WiringPiLibrary, EntryPoint = "setPadDrive", SetLastError = true)]
|
/// Undocumented function
|
||||||
public static extern int SetPadDrive(int group, int value);
|
/// </summary>
|
||||||
|
/// <param name="pin">The pin.</param>
|
||||||
/// <summary>
|
/// <param name="freq">The freq.</param>
|
||||||
/// Undocumented function
|
/// <returns>The result code</returns>
|
||||||
/// </summary>
|
[DllImport(WiringPiLibrary, EntryPoint = "pwmToneWrite", SetLastError = true)]
|
||||||
/// <param name="pin">The pin.</param>
|
public static extern Int32 PwmToneWrite(Int32 pin, Int32 freq);
|
||||||
/// <returns>The result code</returns>
|
|
||||||
[DllImport(WiringPiLibrary, EntryPoint = "getAlt", SetLastError = true)]
|
/// <summary>
|
||||||
public static extern int GetAlt(int pin);
|
/// This writes the 8-bit byte supplied to the first 8 GPIO pins.
|
||||||
|
/// It’s the fastest way to set all 8 bits at once to a particular value, although it still takes two write operations to the Pi’s GPIO hardware.
|
||||||
/// <summary>
|
/// </summary>
|
||||||
/// Undocumented function
|
/// <param name="value">The value.</param>
|
||||||
/// </summary>
|
[DllImport(WiringPiLibrary, EntryPoint = "digitalWriteByte", SetLastError = true)]
|
||||||
/// <param name="pin">The pin.</param>
|
public static extern void DigitalWriteByte(Int32 value);
|
||||||
/// <param name="freq">The freq.</param>
|
|
||||||
/// <returns>The result code</returns>
|
/// <summary>
|
||||||
[DllImport(WiringPiLibrary, EntryPoint = "pwmToneWrite", SetLastError = true)]
|
/// This writes the 8-bit byte supplied to the first 8 GPIO pins.
|
||||||
public static extern int PwmToneWrite(int pin, int freq);
|
/// It’s the fastest way to set all 8 bits at once to a particular value, although it still takes two write operations to the Pi’s GPIO hardware.
|
||||||
|
/// </summary>
|
||||||
/// <summary>
|
/// <param name="value">The value.</param>
|
||||||
/// This writes the 8-bit byte supplied to the first 8 GPIO pins.
|
[DllImport(WiringPiLibrary, EntryPoint = "digitalWriteByte2", SetLastError = true)]
|
||||||
/// It’s the fastest way to set all 8 bits at once to a particular value, although it still takes two write operations to the Pi’s GPIO hardware.
|
public static extern void DigitalWriteByte2(Int32 value);
|
||||||
/// </summary>
|
|
||||||
/// <param name="value">The value.</param>
|
/// <summary>
|
||||||
[DllImport(WiringPiLibrary, EntryPoint = "digitalWriteByte", SetLastError = true)]
|
/// Undocumented function
|
||||||
public static extern void DigitalWriteByte(int value);
|
/// This reads the 8-bit byte supplied to the first 8 GPIO pins.
|
||||||
|
/// It’s the fastest way to get all 8 bits at once to a particular value.
|
||||||
/// <summary>
|
/// </summary>
|
||||||
/// This writes the 8-bit byte supplied to the first 8 GPIO pins.
|
/// <returns>The result code</returns>
|
||||||
/// It’s the fastest way to set all 8 bits at once to a particular value, although it still takes two write operations to the Pi’s GPIO hardware.
|
[DllImport(WiringPiLibrary, EntryPoint = "digitalReadByte", SetLastError = true)]
|
||||||
/// </summary>
|
public static extern UInt32 DigitalReadByte();
|
||||||
/// <param name="value">The value.</param>
|
|
||||||
[DllImport(WiringPiLibrary, EntryPoint = "digitalWriteByte2", SetLastError = true)]
|
/// <summary>
|
||||||
public static extern void DigitalWriteByte2(int value);
|
/// Undocumented function
|
||||||
|
/// This reads the 8-bit byte supplied to the first 8 GPIO pins.
|
||||||
/// <summary>
|
/// It’s the fastest way to get all 8 bits at once to a particular value.
|
||||||
/// Undocumented function
|
/// </summary>
|
||||||
/// This reads the 8-bit byte supplied to the first 8 GPIO pins.
|
/// <returns>The result code</returns>
|
||||||
/// It’s the fastest way to get all 8 bits at once to a particular value.
|
[DllImport(WiringPiLibrary, EntryPoint = "digitalReadByte2", SetLastError = true)]
|
||||||
/// </summary>
|
public static extern UInt32 DigitalReadByte2();
|
||||||
/// <returns>The result code</returns>
|
|
||||||
[DllImport(WiringPiLibrary, EntryPoint = "digitalReadByte", SetLastError = true)]
|
/// <summary>
|
||||||
public static extern uint DigitalReadByte();
|
/// The PWM generator can run in 2 modes – “balanced” and “mark:space”. The mark:space mode is traditional,
|
||||||
|
/// however the default mode in the Pi is “balanced”. You can switch modes by supplying the parameter: PWM_MODE_BAL or PWM_MODE_MS.
|
||||||
/// <summary>
|
/// </summary>
|
||||||
/// Undocumented function
|
/// <param name="mode">The mode.</param>
|
||||||
/// This reads the 8-bit byte supplied to the first 8 GPIO pins.
|
[DllImport(WiringPiLibrary, EntryPoint = "pwmSetMode", SetLastError = true)]
|
||||||
/// It’s the fastest way to get all 8 bits at once to a particular value.
|
public static extern void PwmSetMode(Int32 mode);
|
||||||
/// </summary>
|
|
||||||
/// <returns>The result code</returns>
|
/// <summary>
|
||||||
[DllImport(WiringPiLibrary, EntryPoint = "digitalReadByte2", SetLastError = true)]
|
/// This sets the range register in the PWM generator. The default is 1024.
|
||||||
public static extern uint DigitalReadByte2();
|
/// </summary>
|
||||||
|
/// <param name="range">The range.</param>
|
||||||
/// <summary>
|
[DllImport(WiringPiLibrary, EntryPoint = "pwmSetRange", SetLastError = true)]
|
||||||
/// The PWM generator can run in 2 modes – “balanced” and “mark:space”. The mark:space mode is traditional,
|
public static extern void PwmSetRange(UInt32 range);
|
||||||
/// however the default mode in the Pi is “balanced”. You can switch modes by supplying the parameter: PWM_MODE_BAL or PWM_MODE_MS.
|
|
||||||
/// </summary>
|
/// <summary>
|
||||||
/// <param name="mode">The mode.</param>
|
/// This sets the divisor for the PWM clock.
|
||||||
[DllImport(WiringPiLibrary, EntryPoint = "pwmSetMode", SetLastError = true)]
|
/// Note: The PWM control functions can not be used when in Sys mode.
|
||||||
public static extern void PwmSetMode(int mode);
|
/// To understand more about the PWM system, you’ll need to read the Broadcom ARM peripherals manual.
|
||||||
|
/// </summary>
|
||||||
/// <summary>
|
/// <param name="divisor">The divisor.</param>
|
||||||
/// This sets the range register in the PWM generator. The default is 1024.
|
[DllImport(WiringPiLibrary, EntryPoint = "pwmSetClock", SetLastError = true)]
|
||||||
/// </summary>
|
public static extern void PwmSetClock(Int32 divisor);
|
||||||
/// <param name="range">The range.</param>
|
|
||||||
[DllImport(WiringPiLibrary, EntryPoint = "pwmSetRange", SetLastError = true)]
|
/// <summary>
|
||||||
public static extern void PwmSetRange(uint range);
|
/// Undocumented function
|
||||||
|
/// </summary>
|
||||||
/// <summary>
|
/// <param name="pin">The pin.</param>
|
||||||
/// This sets the divisor for the PWM clock.
|
/// <param name="freq">The freq.</param>
|
||||||
/// Note: The PWM control functions can not be used when in Sys mode.
|
[DllImport(WiringPiLibrary, EntryPoint = "gpioClockSet", SetLastError = true)]
|
||||||
/// To understand more about the PWM system, you’ll need to read the Broadcom ARM peripherals manual.
|
public static extern void GpioClockSet(Int32 pin, Int32 freq);
|
||||||
/// </summary>
|
|
||||||
/// <param name="divisor">The divisor.</param>
|
/// <summary>
|
||||||
[DllImport(WiringPiLibrary, EntryPoint = "pwmSetClock", SetLastError = true)]
|
/// Note: Jan 2013: The waitForInterrupt() function is deprecated – you should use the newer and easier to use wiringPiISR() function below.
|
||||||
public static extern void PwmSetClock(int divisor);
|
/// When called, it will wait for an interrupt event to happen on that pin and your program will be stalled. The timeOut parameter is given in milliseconds,
|
||||||
|
/// or can be -1 which means to wait forever.
|
||||||
/// <summary>
|
/// The return value is -1 if an error occurred (and errno will be set appropriately), 0 if it timed out, or 1 on a successful interrupt event.
|
||||||
/// Undocumented function
|
/// Before you call waitForInterrupt, you must first initialise the GPIO pin and at present the only way to do this is to use the gpio program, either
|
||||||
/// </summary>
|
/// in a script, or using the system() call from inside your program.
|
||||||
/// <param name="pin">The pin.</param>
|
/// e.g. We want to wait for a falling-edge interrupt on GPIO pin 0, so to setup the hardware, we need to run: gpio edge 0 falling
|
||||||
/// <param name="freq">The freq.</param>
|
/// before running the program.
|
||||||
[DllImport(WiringPiLibrary, EntryPoint = "gpioClockSet", SetLastError = true)]
|
/// </summary>
|
||||||
public static extern void GpioClockSet(int pin, int freq);
|
/// <param name="pin">The pin.</param>
|
||||||
|
/// <param name="timeout">The timeout.</param>
|
||||||
/// <summary>
|
/// <returns>The result code</returns>
|
||||||
/// Note: Jan 2013: The waitForInterrupt() function is deprecated – you should use the newer and easier to use wiringPiISR() function below.
|
[Obsolete]
|
||||||
/// When called, it will wait for an interrupt event to happen on that pin and your program will be stalled. The timeOut parameter is given in milliseconds,
|
[DllImport(WiringPiLibrary, EntryPoint = "waitForInterrupt", SetLastError = true)]
|
||||||
/// or can be -1 which means to wait forever.
|
public static extern Int32 WaitForInterrupt(Int32 pin, Int32 timeout);
|
||||||
/// The return value is -1 if an error occurred (and errno will be set appropriately), 0 if it timed out, or 1 on a successful interrupt event.
|
|
||||||
/// Before you call waitForInterrupt, you must first initialise the GPIO pin and at present the only way to do this is to use the gpio program, either
|
/// <summary>
|
||||||
/// in a script, or using the system() call from inside your program.
|
/// This function registers a function to received interrupts on the specified pin.
|
||||||
/// e.g. We want to wait for a falling-edge interrupt on GPIO pin 0, so to setup the hardware, we need to run: gpio edge 0 falling
|
/// The edgeType parameter is either INT_EDGE_FALLING, INT_EDGE_RISING, INT_EDGE_BOTH or INT_EDGE_SETUP.
|
||||||
/// before running the program.
|
/// If it is INT_EDGE_SETUP then no initialisation of the pin will happen – it’s assumed that you have already setup the pin elsewhere
|
||||||
/// </summary>
|
/// (e.g. with the gpio program), but if you specify one of the other types, then the pin will be exported and initialised as specified.
|
||||||
/// <param name="pin">The pin.</param>
|
/// This is accomplished via a suitable call to the gpio utility program, so it need to be available.
|
||||||
/// <param name="timeout">The timeout.</param>
|
/// The pin number is supplied in the current mode – native wiringPi, BCM_GPIO, physical or Sys modes.
|
||||||
/// <returns>The result code</returns>
|
/// This function will work in any mode, and does not need root privileges to work.
|
||||||
[Obsolete]
|
/// The function will be called when the interrupt triggers. When it is triggered, it’s cleared in the dispatcher before calling your function,
|
||||||
[DllImport(WiringPiLibrary, EntryPoint = "waitForInterrupt", SetLastError = true)]
|
/// so if a subsequent interrupt fires before you finish your handler, then it won’t be missed. (However it can only track one more interrupt,
|
||||||
public static extern int WaitForInterrupt(int pin, int timeout);
|
/// if more than one interrupt fires while one is being handled then they will be ignored)
|
||||||
|
/// This function is run at a high priority (if the program is run using sudo, or as root) and executes concurrently with the main program.
|
||||||
/// <summary>
|
/// It has full access to all the global variables, open file handles and so on.
|
||||||
/// This function registers a function to received interrupts on the specified pin.
|
/// </summary>
|
||||||
/// The edgeType parameter is either INT_EDGE_FALLING, INT_EDGE_RISING, INT_EDGE_BOTH or INT_EDGE_SETUP.
|
/// <param name="pin">The pin.</param>
|
||||||
/// If it is INT_EDGE_SETUP then no initialisation of the pin will happen – it’s assumed that you have already setup the pin elsewhere
|
/// <param name="mode">The mode.</param>
|
||||||
/// (e.g. with the gpio program), but if you specify one of the other types, then the pin will be exported and initialised as specified.
|
/// <param name="method">The method.</param>
|
||||||
/// This is accomplished via a suitable call to the gpio utility program, so it need to be available.
|
/// <returns>The result code</returns>
|
||||||
/// The pin number is supplied in the current mode – native wiringPi, BCM_GPIO, physical or Sys modes.
|
[DllImport(WiringPiLibrary, EntryPoint = "wiringPiISR", SetLastError = true)]
|
||||||
/// This function will work in any mode, and does not need root privileges to work.
|
public static extern Int32 WiringPiISR(Int32 pin, Int32 mode, InterruptServiceRoutineCallback method);
|
||||||
/// The function will be called when the interrupt triggers. When it is triggered, it’s cleared in the dispatcher before calling your function,
|
|
||||||
/// so if a subsequent interrupt fires before you finish your handler, then it won’t be missed. (However it can only track one more interrupt,
|
/// <summary>
|
||||||
/// if more than one interrupt fires while one is being handled then they will be ignored)
|
/// This function creates a thread which is another function in your program previously declared using the PI_THREAD declaration.
|
||||||
/// This function is run at a high priority (if the program is run using sudo, or as root) and executes concurrently with the main program.
|
/// This function is then run concurrently with your main program. An example may be to have this function wait for an interrupt while
|
||||||
/// It has full access to all the global variables, open file handles and so on.
|
/// your program carries on doing other tasks. The thread can indicate an event, or action by using global variables to
|
||||||
/// </summary>
|
/// communicate back to the main program, or other threads.
|
||||||
/// <param name="pin">The pin.</param>
|
/// </summary>
|
||||||
/// <param name="mode">The mode.</param>
|
/// <param name="method">The method.</param>
|
||||||
/// <param name="method">The method.</param>
|
/// <returns>The result code</returns>
|
||||||
/// <returns>The result code</returns>
|
[DllImport(WiringPiLibrary, EntryPoint = "piThreadCreate", SetLastError = true)]
|
||||||
[DllImport(WiringPiLibrary, EntryPoint = "wiringPiISR", SetLastError = true)]
|
public static extern Int32 PiThreadCreate(ThreadWorker method);
|
||||||
public static extern int WiringPiISR(int pin, int mode, InterruptServiceRoutineCallback method);
|
|
||||||
|
/// <summary>
|
||||||
/// <summary>
|
/// These allow you to synchronise variable updates from your main program to any threads running in your program. keyNum is a number from 0 to 3 and represents a key.
|
||||||
/// This function creates a thread which is another function in your program previously declared using the PI_THREAD declaration.
|
/// When another process tries to lock the same key, it will be stalled until the first process has unlocked the same key.
|
||||||
/// This function is then run concurrently with your main program. An example may be to have this function wait for an interrupt while
|
/// You may need to use these functions to ensure that you get valid data when exchanging data between your main program and a thread
|
||||||
/// your program carries on doing other tasks. The thread can indicate an event, or action by using global variables to
|
/// – otherwise it’s possible that the thread could wake-up halfway during your data copy and change the data –
|
||||||
/// communicate back to the main program, or other threads.
|
/// so the data you end up copying is incomplete, or invalid. See the wfi.c program in the examples directory for an example.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="method">The method.</param>
|
/// <param name="key">The key.</param>
|
||||||
/// <returns>The result code</returns>
|
[DllImport(WiringPiLibrary, EntryPoint = "piLock", SetLastError = true)]
|
||||||
[DllImport(WiringPiLibrary, EntryPoint = "piThreadCreate", SetLastError = true)]
|
public static extern void PiLock(Int32 key);
|
||||||
public static extern int PiThreadCreate(ThreadWorker method);
|
|
||||||
|
/// <summary>
|
||||||
/// <summary>
|
/// These allow you to synchronise variable updates from your main program to any threads running in your program. keyNum is a number from 0 to 3 and represents a key.
|
||||||
/// These allow you to synchronise variable updates from your main program to any threads running in your program. keyNum is a number from 0 to 3 and represents a key.
|
/// When another process tries to lock the same key, it will be stalled until the first process has unlocked the same key.
|
||||||
/// When another process tries to lock the same key, it will be stalled until the first process has unlocked the same key.
|
/// You may need to use these functions to ensure that you get valid data when exchanging data between your main program and a thread
|
||||||
/// You may need to use these functions to ensure that you get valid data when exchanging data between your main program and a thread
|
/// – otherwise it’s possible that the thread could wake-up halfway during your data copy and change the data –
|
||||||
/// – otherwise it’s possible that the thread could wake-up halfway during your data copy and change the data –
|
/// so the data you end up copying is incomplete, or invalid. See the wfi.c program in the examples directory for an example.
|
||||||
/// so the data you end up copying is incomplete, or invalid. See the wfi.c program in the examples directory for an example.
|
/// </summary>
|
||||||
/// </summary>
|
/// <param name="key">The key.</param>
|
||||||
/// <param name="key">The key.</param>
|
[DllImport(WiringPiLibrary, EntryPoint = "piUnlock", SetLastError = true)]
|
||||||
[DllImport(WiringPiLibrary, EntryPoint = "piLock", SetLastError = true)]
|
public static extern void PiUnlock(Int32 key);
|
||||||
public static extern void PiLock(int key);
|
|
||||||
|
/// <summary>
|
||||||
/// <summary>
|
/// This attempts to shift your program (or thread in a multi-threaded program) to a higher priority
|
||||||
/// 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.
|
/// and enables a real-time scheduling. The priority parameter should be from 0 (the default) to 99 (the maximum).
|
||||||
/// When another process tries to lock the same key, it will be stalled until the first process has unlocked the same key.
|
/// This won’t make your program go any faster, but it will give it a bigger slice of time when other programs are running.
|
||||||
/// You may need to use these functions to ensure that you get valid data when exchanging data between your main program and a thread
|
/// The priority parameter works relative to others – so you can make one program priority 1 and another priority 2
|
||||||
/// – otherwise it’s possible that the thread could wake-up halfway during your data copy and change the data –
|
/// and it will have the same effect as setting one to 10 and the other to 90 (as long as no other
|
||||||
/// so the data you end up copying is incomplete, or invalid. See the wfi.c program in the examples directory for an example.
|
/// programs are running with elevated priorities)
|
||||||
/// </summary>
|
/// The return value is 0 for success and -1 for error. If an error is returned, the program should then consult the errno global variable, as per the usual conventions.
|
||||||
/// <param name="key">The key.</param>
|
/// Note: Only programs running as root can change their priority. If called from a non-root program then nothing happens.
|
||||||
[DllImport(WiringPiLibrary, EntryPoint = "piUnlock", SetLastError = true)]
|
/// </summary>
|
||||||
public static extern void PiUnlock(int key);
|
/// <param name="priority">The priority.</param>
|
||||||
|
/// <returns>The result code</returns>
|
||||||
/// <summary>
|
[DllImport(WiringPiLibrary, EntryPoint = "piHiPri", SetLastError = true)]
|
||||||
/// This attempts to shift your program (or thread in a multi-threaded program) to a higher priority
|
public static extern Int32 PiHiPri(Int32 priority);
|
||||||
/// and enables a real-time scheduling. The priority parameter should be from 0 (the default) to 99 (the maximum).
|
|
||||||
/// This won’t make your program go any faster, but it will give it a bigger slice of time when other programs are running.
|
/// <summary>
|
||||||
/// The priority parameter works relative to others – so you can make one program priority 1 and another priority 2
|
/// This causes program execution to pause for at least howLong milliseconds.
|
||||||
/// and it will have the same effect as setting one to 10 and the other to 90 (as long as no other
|
/// Due to the multi-tasking nature of Linux it could be longer.
|
||||||
/// programs are running with elevated priorities)
|
/// Note that the maximum delay is an unsigned 32-bit integer or approximately 49 days.
|
||||||
/// The return value is 0 for success and -1 for error. If an error is returned, the program should then consult the errno global variable, as per the usual conventions.
|
/// </summary>
|
||||||
/// Note: Only programs running as root can change their priority. If called from a non-root program then nothing happens.
|
/// <param name="howLong">The how long.</param>
|
||||||
/// </summary>
|
[DllImport(WiringPiLibrary, EntryPoint = "delay", SetLastError = true)]
|
||||||
/// <param name="priority">The priority.</param>
|
public static extern void Delay(UInt32 howLong);
|
||||||
/// <returns>The result code</returns>
|
|
||||||
[DllImport(WiringPiLibrary, EntryPoint = "piHiPri", SetLastError = true)]
|
/// <summary>
|
||||||
public static extern int PiHiPri(int priority);
|
/// This causes program execution to pause for at least howLong microseconds.
|
||||||
|
/// Due to the multi-tasking nature of Linux it could be longer.
|
||||||
/// <summary>
|
/// Note that the maximum delay is an unsigned 32-bit integer microseconds or approximately 71 minutes.
|
||||||
/// This causes program execution to pause for at least howLong milliseconds.
|
/// Delays under 100 microseconds are timed using a hard-coded loop continually polling the system time,
|
||||||
/// Due to the multi-tasking nature of Linux it could be longer.
|
/// Delays over 100 microseconds are done using the system nanosleep() function – You may need to consider the implications
|
||||||
/// Note that the maximum delay is an unsigned 32-bit integer or approximately 49 days.
|
/// of very short delays on the overall performance of the system, especially if using threads.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="howLong">The how long.</param>
|
/// <param name="howLong">The how long.</param>
|
||||||
[DllImport(WiringPiLibrary, EntryPoint = "delay", SetLastError = true)]
|
[DllImport(WiringPiLibrary, EntryPoint = "delayMicroseconds", SetLastError = true)]
|
||||||
public static extern void Delay(uint howLong);
|
public static extern void DelayMicroseconds(UInt32 howLong);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// This causes program execution to pause for at least howLong microseconds.
|
/// This returns a number representing the number of milliseconds since your program called one of the wiringPiSetup functions.
|
||||||
/// Due to the multi-tasking nature of Linux it could be longer.
|
/// It returns an unsigned 32-bit number which wraps after 49 days.
|
||||||
/// Note that the maximum delay is an unsigned 32-bit integer microseconds or approximately 71 minutes.
|
/// </summary>
|
||||||
/// Delays under 100 microseconds are timed using a hard-coded loop continually polling the system time,
|
/// <returns>The result code</returns>
|
||||||
/// Delays over 100 microseconds are done using the system nanosleep() function – You may need to consider the implications
|
[DllImport(WiringPiLibrary, EntryPoint = "millis", SetLastError = true)]
|
||||||
/// of very short delays on the overall performance of the system, especially if using threads.
|
public static extern UInt32 Millis();
|
||||||
/// </summary>
|
|
||||||
/// <param name="howLong">The how long.</param>
|
/// <summary>
|
||||||
[DllImport(WiringPiLibrary, EntryPoint = "delayMicroseconds", SetLastError = true)]
|
/// This returns a number representing the number of microseconds since your program called one of
|
||||||
public static extern void DelayMicroseconds(uint howLong);
|
/// the wiringPiSetup functions. It returns an unsigned 32-bit number which wraps after approximately 71 minutes.
|
||||||
|
/// </summary>
|
||||||
/// <summary>
|
/// <returns>The result code</returns>
|
||||||
/// This returns a number representing the number of milliseconds since your program called one of the wiringPiSetup functions.
|
[DllImport(WiringPiLibrary, EntryPoint = "micros", SetLastError = true)]
|
||||||
/// It returns an unsigned 32-bit number which wraps after 49 days.
|
public static extern UInt32 Micros();
|
||||||
/// </summary>
|
|
||||||
/// <returns>The result code</returns>
|
#endregion
|
||||||
[DllImport(WiringPiLibrary, EntryPoint = "millis", SetLastError = true)]
|
}
|
||||||
public static extern uint Millis();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// This returns a number representing the number of microseconds since your program called one of
|
|
||||||
/// the wiringPiSetup functions. It returns an unsigned 32-bit number which wraps after approximately 71 minutes.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>The result code</returns>
|
|
||||||
[DllImport(WiringPiLibrary, EntryPoint = "micros", SetLastError = true)]
|
|
||||||
public static extern uint Micros();
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -1,110 +1,121 @@
|
|||||||
namespace Unosquare.RaspberryIO
|
using Unosquare.RaspberryIO.Camera;
|
||||||
{
|
using Unosquare.RaspberryIO.Computer;
|
||||||
using Camera;
|
using Unosquare.RaspberryIO.Gpio;
|
||||||
using Computer;
|
using Unosquare.RaspberryIO.Native;
|
||||||
using Gpio;
|
using System.Threading.Tasks;
|
||||||
using Native;
|
using Unosquare.Swan.Components;
|
||||||
using System.Threading.Tasks;
|
using System;
|
||||||
using Swan.Components;
|
|
||||||
|
namespace Unosquare.RaspberryIO {
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Our main character. Provides access to the Raspberry Pi's GPIO, system and board information and Camera
|
/// Our main character. Provides access to the Raspberry Pi's GPIO, system and board information and Camera
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static class Pi
|
public static class Pi {
|
||||||
{
|
private static readonly Object SyncLock = new Object();
|
||||||
private static readonly object SyncLock = new object();
|
|
||||||
|
/// <summary>
|
||||||
/// <summary>
|
/// Initializes static members of the <see cref="Pi" /> class.
|
||||||
/// Initializes static members of the <see cref="Pi" /> class.
|
/// </summary>
|
||||||
/// </summary>
|
static Pi() {
|
||||||
static Pi()
|
lock(SyncLock) {
|
||||||
{
|
// Extraction of embedded resources
|
||||||
lock (SyncLock)
|
Resources.EmbeddedResources.ExtractAll();
|
||||||
{
|
|
||||||
// Extraction of embedded resources
|
// Instance assignments
|
||||||
Resources.EmbeddedResources.ExtractAll();
|
Gpio = GpioController.Instance;
|
||||||
|
Info = SystemInfo.Instance;
|
||||||
// Instance assignments
|
Timing = Timing.Instance;
|
||||||
Gpio = GpioController.Instance;
|
Spi = SpiBus.Instance;
|
||||||
Info = SystemInfo.Instance;
|
I2C = I2CBus.Instance;
|
||||||
Timing = Timing.Instance;
|
Camera = CameraController.Instance;
|
||||||
Spi = SpiBus.Instance;
|
PiDisplay = DsiDisplay.Instance;
|
||||||
I2C = I2CBus.Instance;
|
}
|
||||||
Camera = CameraController.Instance;
|
}
|
||||||
PiDisplay = DsiDisplay.Instance;
|
|
||||||
}
|
#region Components
|
||||||
}
|
|
||||||
|
/// <summary>
|
||||||
#region Components
|
/// Provides access to the Raspberry Pi's GPIO as a collection of GPIO Pins.
|
||||||
|
/// </summary>
|
||||||
/// <summary>
|
public static GpioController Gpio {
|
||||||
/// Provides access to the Raspberry Pi's GPIO as a collection of GPIO Pins.
|
get;
|
||||||
/// </summary>
|
}
|
||||||
public static GpioController Gpio { get; }
|
|
||||||
|
/// <summary>
|
||||||
/// <summary>
|
/// Provides information on this Raspberry Pi's CPU and form factor.
|
||||||
/// Provides information on this Raspberry Pi's CPU and form factor.
|
/// </summary>
|
||||||
/// </summary>
|
public static SystemInfo Info {
|
||||||
public static SystemInfo Info { get; }
|
get;
|
||||||
|
}
|
||||||
/// <summary>
|
|
||||||
/// Provides access to The PI's Timing and threading API
|
/// <summary>
|
||||||
/// </summary>
|
/// Provides access to The PI's Timing and threading API
|
||||||
public static Timing Timing { get; }
|
/// </summary>
|
||||||
|
public static Timing Timing {
|
||||||
/// <summary>
|
get;
|
||||||
/// Provides access to the 2-channel SPI bus
|
}
|
||||||
/// </summary>
|
|
||||||
public static SpiBus Spi { get; }
|
/// <summary>
|
||||||
|
/// Provides access to the 2-channel SPI bus
|
||||||
/// <summary>
|
/// </summary>
|
||||||
/// Provides access to the functionality of the i2c bus.
|
public static SpiBus Spi {
|
||||||
/// </summary>
|
get;
|
||||||
public static I2CBus I2C { get; }
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Provides access to the official Raspberry Pi Camera
|
/// Provides access to the functionality of the i2c bus.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static CameraController Camera { get; }
|
public static I2CBus I2C {
|
||||||
|
get;
|
||||||
/// <summary>
|
}
|
||||||
/// Provides access to the official Raspberry Pi 7-inch DSI Display
|
|
||||||
/// </summary>
|
/// <summary>
|
||||||
public static DsiDisplay PiDisplay { get; }
|
/// Provides access to the official Raspberry Pi Camera
|
||||||
|
/// </summary>
|
||||||
/// <summary>
|
public static CameraController Camera {
|
||||||
/// Gets the logger source name.
|
get;
|
||||||
/// </summary>
|
}
|
||||||
internal static string LoggerSource => typeof(Pi).Namespace;
|
|
||||||
|
/// <summary>
|
||||||
#endregion
|
/// Provides access to the official Raspberry Pi 7-inch DSI Display
|
||||||
|
/// </summary>
|
||||||
#region Methods
|
public static DsiDisplay PiDisplay {
|
||||||
|
get;
|
||||||
/// <summary>
|
}
|
||||||
/// Restarts the Pi. Must be running as SU
|
|
||||||
/// </summary>
|
/// <summary>
|
||||||
/// <returns>The process result</returns>
|
/// Gets the logger source name.
|
||||||
public static async Task<ProcessResult> RestartAsync() => await ProcessRunner.GetProcessResultAsync("reboot", null, null);
|
/// </summary>
|
||||||
|
internal static String LoggerSource => typeof(Pi).Namespace;
|
||||||
/// <summary>
|
|
||||||
/// Restarts the Pi. Must be running as SU
|
#endregion
|
||||||
/// </summary>
|
|
||||||
/// <returns>The process result</returns>
|
#region Methods
|
||||||
public static ProcessResult Restart() => RestartAsync().GetAwaiter().GetResult();
|
|
||||||
|
/// <summary>
|
||||||
/// <summary>
|
/// Restarts the Pi. Must be running as SU
|
||||||
/// Halts the Pi. Must be running as SU
|
/// </summary>
|
||||||
/// </summary>
|
/// <returns>The process result</returns>
|
||||||
/// <returns>The process result</returns>
|
public static async Task<ProcessResult> RestartAsync() => await ProcessRunner.GetProcessResultAsync("reboot", null, null);
|
||||||
public static async Task<ProcessResult> ShutdownAsync() => await ProcessRunner.GetProcessResultAsync("halt", null, null);
|
|
||||||
|
/// <summary>
|
||||||
/// <summary>
|
/// Restarts the Pi. Must be running as SU
|
||||||
/// Halts the Pi. Must be running as SU
|
/// </summary>
|
||||||
/// </summary>
|
/// <returns>The process result</returns>
|
||||||
/// <returns>The process result</returns>
|
public static ProcessResult Restart() => RestartAsync().GetAwaiter().GetResult();
|
||||||
public static ProcessResult Shutdown() => ShutdownAsync().GetAwaiter().GetResult();
|
|
||||||
|
/// <summary>
|
||||||
#endregion
|
/// Halts the Pi. Must be running as SU
|
||||||
}
|
/// </summary>
|
||||||
}
|
/// <returns>The process result</returns>
|
||||||
|
public static async Task<ProcessResult> ShutdownAsync() => await ProcessRunner.GetProcessResultAsync("halt", null, null);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Halts the Pi. Must be running as SU
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The process result</returns>
|
||||||
|
public static ProcessResult Shutdown() => ShutdownAsync().GetAwaiter().GetResult();
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
@ -1,65 +1,55 @@
|
|||||||
namespace Unosquare.RaspberryIO.Resources
|
using Unosquare.RaspberryIO.Native;
|
||||||
{
|
using Unosquare.Swan;
|
||||||
using Native;
|
using System;
|
||||||
using Swan;
|
using System.Collections.ObjectModel;
|
||||||
using System;
|
using System.IO;
|
||||||
using System.Collections.ObjectModel;
|
|
||||||
using System.IO;
|
namespace Unosquare.RaspberryIO.Resources {
|
||||||
|
/// <summary>
|
||||||
|
/// Provides access to embedded assembly files
|
||||||
|
/// </summary>
|
||||||
|
internal static class EmbeddedResources {
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Provides access to embedded assembly files
|
/// Initializes static members of the <see cref="EmbeddedResources"/> class.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static class EmbeddedResources
|
static EmbeddedResources() => ResourceNames = new ReadOnlyCollection<String>(typeof(EmbeddedResources).Assembly().GetManifestResourceNames());
|
||||||
{
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes static members of the <see cref="EmbeddedResources"/> class.
|
/// Gets the resource names.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
static EmbeddedResources()
|
/// <value>
|
||||||
{
|
/// The resource names.
|
||||||
ResourceNames =
|
/// </value>
|
||||||
new ReadOnlyCollection<string>(typeof(EmbeddedResources).Assembly().GetManifestResourceNames());
|
public static ReadOnlyCollection<String> ResourceNames {
|
||||||
}
|
get;
|
||||||
|
}
|
||||||
/// <summary>
|
|
||||||
/// Gets the resource names.
|
/// <summary>
|
||||||
/// </summary>
|
/// Extracts all the file resources to the specified base path.
|
||||||
/// <value>
|
/// </summary>
|
||||||
/// The resource names.
|
public static void ExtractAll() {
|
||||||
/// </value>
|
String basePath = Runtime.EntryAssemblyDirectory;
|
||||||
public static ReadOnlyCollection<string> ResourceNames { get; }
|
Int32 executablePermissions = Standard.StringToInteger("0777", IntPtr.Zero, 8);
|
||||||
|
|
||||||
/// <summary>
|
foreach(String resourceName in ResourceNames) {
|
||||||
/// Extracts all the file resources to the specified base path.
|
String filename = resourceName.Substring($"{typeof(EmbeddedResources).Namespace}.".Length);
|
||||||
/// </summary>
|
String targetPath = Path.Combine(basePath, filename);
|
||||||
public static void ExtractAll()
|
if(File.Exists(targetPath)) {
|
||||||
{
|
return;
|
||||||
var basePath = Runtime.EntryAssemblyDirectory;
|
}
|
||||||
var executablePermissions = Standard.StringToInteger("0777", IntPtr.Zero, 8);
|
|
||||||
|
using(Stream stream = typeof(EmbeddedResources).Assembly().GetManifestResourceStream($"{typeof(EmbeddedResources).Namespace}.{filename}")) {
|
||||||
foreach (var resourceName in ResourceNames)
|
using(FileStream outputStream = File.OpenWrite(targetPath)) {
|
||||||
{
|
stream?.CopyTo(outputStream);
|
||||||
var filename = resourceName.Substring($"{typeof(EmbeddedResources).Namespace}.".Length);
|
}
|
||||||
var targetPath = Path.Combine(basePath, filename);
|
|
||||||
if (File.Exists(targetPath)) return;
|
try {
|
||||||
|
_ = Standard.Chmod(targetPath, (UInt32)executablePermissions);
|
||||||
using (var stream = typeof(EmbeddedResources).Assembly()
|
} catch {
|
||||||
.GetManifestResourceStream($"{typeof(EmbeddedResources).Namespace}.{filename}"))
|
/* Ignore */
|
||||||
{
|
}
|
||||||
using (var outputStream = File.OpenWrite(targetPath))
|
}
|
||||||
{
|
}
|
||||||
stream?.CopyTo(outputStream);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Standard.Chmod(targetPath, (uint)executablePermissions);
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
/* Ignore */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user