Coding styles
This commit is contained in:
@@ -1,80 +1,66 @@
|
||||
namespace Unosquare.RaspberryIO.Computer
|
||||
{
|
||||
using Swan.Abstractions;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
|
||||
using Unosquare.Swan.Abstractions;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System;
|
||||
|
||||
namespace Unosquare.RaspberryIO.Computer {
|
||||
/// <summary>
|
||||
/// The Official Raspberry Pi 7-inch touch display from the foundation
|
||||
/// Some docs available here:
|
||||
/// http://forums.pimoroni.com/t/official-7-raspberry-pi-touch-screen-faq/959
|
||||
/// </summary>
|
||||
public class DsiDisplay : SingletonBase<DsiDisplay> {
|
||||
private const String BacklightFilename = "/sys/class/backlight/rpi_backlight/bl_power";
|
||||
private const String BrightnessFilename = "/sys/class/backlight/rpi_backlight/brightness";
|
||||
|
||||
/// <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
|
||||
/// Prevents a default instance of the <see cref="DsiDisplay"/> class from being created.
|
||||
/// </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>
|
||||
/// Prevents a default instance of the <see cref="DsiDisplay"/> class from being created.
|
||||
/// </summary>
|
||||
private DsiDisplay()
|
||||
{
|
||||
// placeholder
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the Pi Foundation Display files are present.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// <c>true</c> if this instance is present; otherwise, <c>false</c>.
|
||||
/// </value>
|
||||
public bool IsPresent => File.Exists(BrightnessFilename);
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the brightness of the DSI display via filesystem.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The brightness.
|
||||
/// </value>
|
||||
public byte Brightness
|
||||
{
|
||||
get
|
||||
{
|
||||
if (IsPresent == false) return 0;
|
||||
|
||||
return byte.TryParse(File.ReadAllText(BrightnessFilename).Trim(), out var brightness) ? brightness : (byte)0;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (IsPresent == false) return;
|
||||
File.WriteAllText(BrightnessFilename, value.ToString(CultureInfo.InvariantCulture));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the backlight of the DSI display on.
|
||||
/// 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");
|
||||
}
|
||||
}
|
||||
}
|
||||
private DsiDisplay() {
|
||||
// placeholder
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the Pi Foundation Display files are present.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// <c>true</c> if this instance is present; otherwise, <c>false</c>.
|
||||
/// </value>
|
||||
public Boolean IsPresent => File.Exists(BrightnessFilename);
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the brightness of the DSI display via filesystem.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The brightness.
|
||||
/// </value>
|
||||
public Byte Brightness {
|
||||
get => this.IsPresent == false ? (Byte)0 : Byte.TryParse(File.ReadAllText(BrightnessFilename).Trim(), out Byte brightness) ? brightness : (Byte)0;
|
||||
set {
|
||||
if(this.IsPresent == false) {
|
||||
return;
|
||||
}
|
||||
|
||||
File.WriteAllText(BrightnessFilename, value.ToString(CultureInfo.InvariantCulture));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the backlight of the DSI display on.
|
||||
/// 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 Boolean IsBacklightOn {
|
||||
get => this.IsPresent == false ? false : Int32.TryParse(File.ReadAllText(BacklightFilename).Trim(), out Int32 backlight) ? backlight == 0 : false;
|
||||
set {
|
||||
if(this.IsPresent == false) {
|
||||
return;
|
||||
}
|
||||
|
||||
File.WriteAllText(BacklightFilename, value ? "0" : "1");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,40 +1,51 @@
|
||||
namespace Unosquare.RaspberryIO.Computer
|
||||
{
|
||||
using System.Net;
|
||||
|
||||
using System;
|
||||
using System.Net;
|
||||
|
||||
namespace Unosquare.RaspberryIO.Computer {
|
||||
/// <summary>
|
||||
/// Represents a Network Adapter
|
||||
/// </summary>
|
||||
public class NetworkAdapterInfo {
|
||||
/// <summary>
|
||||
/// Represents a Network Adapter
|
||||
/// Gets the name.
|
||||
/// </summary>
|
||||
public class NetworkAdapterInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the name.
|
||||
/// </summary>
|
||||
public string Name { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the IP V4 address.
|
||||
/// </summary>
|
||||
public IPAddress IPv4 { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the IP V6 address.
|
||||
/// </summary>
|
||||
public IPAddress IPv6 { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of the access point.
|
||||
/// </summary>
|
||||
public string AccessPointName { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the MAC (Physical) address.
|
||||
/// </summary>
|
||||
public string MacAddress { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this instance is wireless.
|
||||
/// </summary>
|
||||
public bool IsWireless { get; internal set; }
|
||||
}
|
||||
public String Name {
|
||||
get; internal set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the IP V4 address.
|
||||
/// </summary>
|
||||
public IPAddress IPv4 {
|
||||
get; internal set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the IP V6 address.
|
||||
/// </summary>
|
||||
public IPAddress IPv6 {
|
||||
get; internal set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the name of the access point.
|
||||
/// </summary>
|
||||
public String AccessPointName {
|
||||
get; internal set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the MAC (Physical) address.
|
||||
/// </summary>
|
||||
public String MacAddress {
|
||||
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 Swan;
|
||||
using Swan.Abstractions;
|
||||
using Swan.Components;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
|
||||
using Unosquare.Swan;
|
||||
using Unosquare.Swan.Abstractions;
|
||||
using Unosquare.Swan.Components;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
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>
|
||||
/// Represents the network information
|
||||
/// Gets the local machine Host Name.
|
||||
/// </summary>
|
||||
public class NetworkSettings : SingletonBase<NetworkSettings>
|
||||
{
|
||||
private const string EssidTag = "ESSID:";
|
||||
|
||||
/// <summary>
|
||||
/// Gets the local machine Host Name.
|
||||
/// </summary>
|
||||
public string HostName => Network.HostName;
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the wireless networks.
|
||||
/// </summary>
|
||||
/// <param name="adapter">The adapter.</param>
|
||||
/// <returns>A list of WiFi networks</returns>
|
||||
public List<WirelessNetworkInfo> RetrieveWirelessNetworks(string adapter) => RetrieveWirelessNetworks(new[] { adapter });
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the wireless networks.
|
||||
/// </summary>
|
||||
/// <param name="adapters">The adapters.</param>
|
||||
/// <returns>A list of WiFi networks</returns>
|
||||
public List<WirelessNetworkInfo> RetrieveWirelessNetworks(string[] adapters = null)
|
||||
{
|
||||
var result = new List<WirelessNetworkInfo>();
|
||||
|
||||
foreach (var networkAdapter in adapters ?? RetrieveAdapters().Where(x => x.IsWireless).Select(x => x.Name))
|
||||
{
|
||||
var wirelessOutput = ProcessRunner.GetProcessOutputAsync("iwlist", $"{networkAdapter} scanning").Result;
|
||||
var outputLines =
|
||||
wirelessOutput.Split('\n')
|
||||
.Select(x => x.Trim())
|
||||
.Where(x => string.IsNullOrWhiteSpace(x) == false)
|
||||
.ToArray();
|
||||
|
||||
for (var i = 0; i < outputLines.Length; i++)
|
||||
{
|
||||
var line = outputLines[i];
|
||||
|
||||
if (line.StartsWith(EssidTag) == false) continue;
|
||||
|
||||
var network = new WirelessNetworkInfo()
|
||||
{
|
||||
Name = line.Replace(EssidTag, string.Empty).Replace("\"", string.Empty)
|
||||
};
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (i + 1 >= outputLines.Length) break;
|
||||
|
||||
// should look for two lines before the ESSID acording to the scan
|
||||
line = outputLines[i - 2];
|
||||
|
||||
if (line.StartsWith("Quality="))
|
||||
{
|
||||
network.Quality = line.Replace("Quality=", string.Empty);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (i + 1 >= outputLines.Length) break;
|
||||
|
||||
// should look for a line before the ESSID acording to the scan
|
||||
line = outputLines[i - 1];
|
||||
|
||||
if (line.StartsWith("Encryption key:"))
|
||||
{
|
||||
network.IsEncrypted = line.Replace("Encryption key:", string.Empty).Trim() == "on";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (result.Any(x => x.Name == network.Name) == false)
|
||||
result.Add(network);
|
||||
}
|
||||
}
|
||||
|
||||
return result.OrderBy(x => x.Name).ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Setups the wireless network.
|
||||
/// </summary>
|
||||
/// <param name="adapterName">Name of the adapter.</param>
|
||||
/// <param name="networkSsid">The network ssid.</param>
|
||||
/// <param name="password">The password.</param>
|
||||
/// <param name="countryCode">The 2-letter country code in uppercase. Default is US.</param>
|
||||
/// <returns>True if successful. Otherwise, false.</returns>
|
||||
public bool SetupWirelessNetwork(string adapterName, string networkSsid, string password = null, string countryCode = "US")
|
||||
{
|
||||
// TODO: Get the country where the device is located to set 'country' param in payload var
|
||||
var payload = $"country={countryCode}\nctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev\nupdate_config=1\n";
|
||||
payload += string.IsNullOrEmpty(password)
|
||||
? $"network={{\n\tssid=\"{networkSsid}\"\n\t}}\n"
|
||||
: $"network={{\n\tssid=\"{networkSsid}\"\n\tpsk=\"{password}\"\n\t}}\n";
|
||||
try
|
||||
{
|
||||
File.WriteAllText("/etc/wpa_supplicant/wpa_supplicant.conf", payload);
|
||||
ProcessRunner.GetProcessOutputAsync("pkill", "-f wpa_supplicant").Wait();
|
||||
ProcessRunner.GetProcessOutputAsync("ifdown", adapterName).Wait();
|
||||
ProcessRunner.GetProcessOutputAsync("ifup", adapterName).Wait();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
ex.Log(nameof(NetworkSettings));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the network adapters.
|
||||
/// </summary>
|
||||
/// <returns>A list of network adapters.</returns>
|
||||
public List<NetworkAdapterInfo> RetrieveAdapters()
|
||||
{
|
||||
const string hWaddr = "HWaddr ";
|
||||
const string ether = "ether ";
|
||||
|
||||
var result = new List<NetworkAdapterInfo>();
|
||||
var interfacesOutput = ProcessRunner.GetProcessOutputAsync("ifconfig").Result;
|
||||
var wlanOutput = ProcessRunner.GetProcessOutputAsync("iwconfig")
|
||||
.Result.Split('\n')
|
||||
.Where(x => x.Contains("no wireless extensions.") == false)
|
||||
.ToArray();
|
||||
|
||||
var outputLines = interfacesOutput.Split('\n').Where(x => string.IsNullOrWhiteSpace(x) == false).ToArray();
|
||||
|
||||
for (var i = 0; i < outputLines.Length; i++)
|
||||
{
|
||||
// grab the current line
|
||||
var line = outputLines[i];
|
||||
|
||||
// skip if the line is indented
|
||||
if (char.IsLetterOrDigit(line[0]) == false)
|
||||
continue;
|
||||
|
||||
// Read the line as an adatper
|
||||
var adapter = new NetworkAdapterInfo
|
||||
{
|
||||
Name = line.Substring(0, line.IndexOf(' ')).TrimEnd(':')
|
||||
};
|
||||
|
||||
// Parse the MAC address in old version of ifconfig; it comes in the first line
|
||||
if (line.IndexOf(hWaddr) >= 0)
|
||||
{
|
||||
var startIndexHwd = line.IndexOf(hWaddr) + hWaddr.Length;
|
||||
adapter.MacAddress = line.Substring(startIndexHwd, 17).Trim();
|
||||
}
|
||||
|
||||
// Parse the info in lines other than the first
|
||||
for (var j = i + 1; j < outputLines.Length; j++)
|
||||
{
|
||||
// Get the contents of the indented line
|
||||
var indentedLine = outputLines[j];
|
||||
|
||||
// We have hit the next adapter info
|
||||
if (char.IsLetterOrDigit(indentedLine[0]))
|
||||
{
|
||||
i = j - 1;
|
||||
break;
|
||||
}
|
||||
|
||||
// Parse the MAC address in new versions of ifconfig; it no longer comes in the first line
|
||||
if (indentedLine.IndexOf(ether) >= 0 && string.IsNullOrWhiteSpace(adapter.MacAddress))
|
||||
{
|
||||
var startIndexHwd = indentedLine.IndexOf(ether) + ether.Length;
|
||||
adapter.MacAddress = indentedLine.Substring(startIndexHwd, 17).Trim();
|
||||
}
|
||||
|
||||
// Parse the IPv4 Address
|
||||
{
|
||||
var addressText = ParseOutputTagFromLine(indentedLine, "inet addr:") ?? ParseOutputTagFromLine(indentedLine, "inet ");
|
||||
|
||||
if (addressText != null)
|
||||
{
|
||||
if (IPAddress.TryParse(addressText, out var outValue))
|
||||
adapter.IPv4 = outValue;
|
||||
}
|
||||
}
|
||||
|
||||
// Parse the IPv6 Address
|
||||
{
|
||||
var addressText = ParseOutputTagFromLine(indentedLine, "inet6 addr:") ?? ParseOutputTagFromLine(indentedLine, "inet6 ");
|
||||
|
||||
if (addressText != null)
|
||||
{
|
||||
if (IPAddress.TryParse(addressText, out var outValue))
|
||||
adapter.IPv6 = outValue;
|
||||
}
|
||||
}
|
||||
|
||||
// we have hit the end of the output in an indented line
|
||||
if (j >= outputLines.Length - 1)
|
||||
i = outputLines.Length;
|
||||
}
|
||||
|
||||
// Retrieve the wireless LAN info
|
||||
var wlanInfo = wlanOutput.FirstOrDefault(x => x.StartsWith(adapter.Name));
|
||||
|
||||
if (wlanInfo != null)
|
||||
{
|
||||
adapter.IsWireless = true;
|
||||
var essidParts = wlanInfo.Split(new[] { EssidTag }, StringSplitOptions.RemoveEmptyEntries);
|
||||
if (essidParts.Length >= 2)
|
||||
{
|
||||
adapter.AccessPointName = essidParts[1].Replace("\"", string.Empty).Trim();
|
||||
}
|
||||
}
|
||||
|
||||
// Add the current adapter to the result
|
||||
result.Add(adapter);
|
||||
}
|
||||
|
||||
return result.OrderBy(x => x.Name).ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves current wireless connected network name.
|
||||
/// </summary>
|
||||
/// <returns>The connected network name.</returns>
|
||||
public string GetWirelessNetworkName() => ProcessRunner.GetProcessOutputAsync("iwgetid", "-r").Result;
|
||||
|
||||
/// <summary>
|
||||
/// Parses the output tag from the given line.
|
||||
/// </summary>
|
||||
/// <param name="indentedLine">The indented line.</param>
|
||||
/// <param name="tagName">Name of the tag.</param>
|
||||
/// <returns>The value after the tag identifier</returns>
|
||||
private static string ParseOutputTagFromLine(string indentedLine, string tagName)
|
||||
{
|
||||
if (indentedLine.IndexOf(tagName) < 0)
|
||||
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();
|
||||
}
|
||||
}
|
||||
public String HostName => Network.HostName;
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the wireless networks.
|
||||
/// </summary>
|
||||
/// <param name="adapter">The adapter.</param>
|
||||
/// <returns>A list of WiFi networks</returns>
|
||||
public List<WirelessNetworkInfo> RetrieveWirelessNetworks(String adapter) => this.RetrieveWirelessNetworks(new[] { adapter });
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the wireless networks.
|
||||
/// </summary>
|
||||
/// <param name="adapters">The adapters.</param>
|
||||
/// <returns>A list of WiFi networks</returns>
|
||||
public List<WirelessNetworkInfo> RetrieveWirelessNetworks(String[] adapters = null) {
|
||||
List<WirelessNetworkInfo> result = new List<WirelessNetworkInfo>();
|
||||
|
||||
foreach(String networkAdapter in adapters ?? this.RetrieveAdapters().Where(x => x.IsWireless).Select(x => x.Name)) {
|
||||
String wirelessOutput = ProcessRunner.GetProcessOutputAsync("iwlist", $"{networkAdapter} scanning").Result;
|
||||
String[] outputLines =
|
||||
wirelessOutput.Split('\n')
|
||||
.Select(x => x.Trim())
|
||||
.Where(x => String.IsNullOrWhiteSpace(x) == false)
|
||||
.ToArray();
|
||||
|
||||
for(Int32 i = 0; i < outputLines.Length; i++) {
|
||||
String line = outputLines[i];
|
||||
|
||||
if(line.StartsWith(EssidTag) == false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
WirelessNetworkInfo network = new WirelessNetworkInfo() {
|
||||
Name = line.Replace(EssidTag, String.Empty).Replace("\"", String.Empty)
|
||||
};
|
||||
|
||||
while(true) {
|
||||
if(i + 1 >= outputLines.Length) {
|
||||
break;
|
||||
}
|
||||
|
||||
// should look for two lines before the ESSID acording to the scan
|
||||
line = outputLines[i - 2];
|
||||
|
||||
if(line.StartsWith("Quality=")) {
|
||||
network.Quality = line.Replace("Quality=", String.Empty);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
while(true) {
|
||||
if(i + 1 >= outputLines.Length) {
|
||||
break;
|
||||
}
|
||||
|
||||
// should look for a line before the ESSID acording to the scan
|
||||
line = outputLines[i - 1];
|
||||
|
||||
if(line.StartsWith("Encryption key:")) {
|
||||
network.IsEncrypted = line.Replace("Encryption key:", String.Empty).Trim() == "on";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(result.Any(x => x.Name == network.Name) == false) {
|
||||
result.Add(network);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result.OrderBy(x => x.Name).ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Setups the wireless network.
|
||||
/// </summary>
|
||||
/// <param name="adapterName">Name of the adapter.</param>
|
||||
/// <param name="networkSsid">The network ssid.</param>
|
||||
/// <param name="password">The password.</param>
|
||||
/// <param name="countryCode">The 2-letter country code in uppercase. Default is US.</param>
|
||||
/// <returns>True if successful. Otherwise, false.</returns>
|
||||
public Boolean SetupWirelessNetwork(String adapterName, String networkSsid, String password = null, String countryCode = "US") {
|
||||
// TODO: Get the country where the device is located to set 'country' param in payload var
|
||||
String payload = $"country={countryCode}\nctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev\nupdate_config=1\n";
|
||||
payload += String.IsNullOrEmpty(password)
|
||||
? $"network={{\n\tssid=\"{networkSsid}\"\n\t}}\n"
|
||||
: $"network={{\n\tssid=\"{networkSsid}\"\n\tpsk=\"{password}\"\n\t}}\n";
|
||||
try {
|
||||
File.WriteAllText("/etc/wpa_supplicant/wpa_supplicant.conf", payload);
|
||||
ProcessRunner.GetProcessOutputAsync("pkill", "-f wpa_supplicant").Wait();
|
||||
ProcessRunner.GetProcessOutputAsync("ifdown", adapterName).Wait();
|
||||
ProcessRunner.GetProcessOutputAsync("ifup", adapterName).Wait();
|
||||
} catch(Exception ex) {
|
||||
ex.Log(nameof(NetworkSettings));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the network adapters.
|
||||
/// </summary>
|
||||
/// <returns>A list of network adapters.</returns>
|
||||
public List<NetworkAdapterInfo> RetrieveAdapters() {
|
||||
const String hWaddr = "HWaddr ";
|
||||
const String ether = "ether ";
|
||||
|
||||
List<NetworkAdapterInfo> result = new List<NetworkAdapterInfo>();
|
||||
String interfacesOutput = ProcessRunner.GetProcessOutputAsync("ifconfig").Result;
|
||||
String[] wlanOutput = ProcessRunner.GetProcessOutputAsync("iwconfig")
|
||||
.Result.Split('\n')
|
||||
.Where(x => x.Contains("no wireless extensions.") == false)
|
||||
.ToArray();
|
||||
|
||||
String[] outputLines = interfacesOutput.Split('\n').Where(x => String.IsNullOrWhiteSpace(x) == false).ToArray();
|
||||
|
||||
for(Int32 i = 0; i < outputLines.Length; i++) {
|
||||
// grab the current line
|
||||
String line = outputLines[i];
|
||||
|
||||
// skip if the line is indented
|
||||
if(Char.IsLetterOrDigit(line[0]) == false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Read the line as an adatper
|
||||
NetworkAdapterInfo adapter = new NetworkAdapterInfo {
|
||||
Name = line.Substring(0, line.IndexOf(' ')).TrimEnd(':')
|
||||
};
|
||||
|
||||
// Parse the MAC address in old version of ifconfig; it comes in the first line
|
||||
if(line.IndexOf(hWaddr) >= 0) {
|
||||
Int32 startIndexHwd = line.IndexOf(hWaddr) + hWaddr.Length;
|
||||
adapter.MacAddress = line.Substring(startIndexHwd, 17).Trim();
|
||||
}
|
||||
|
||||
// Parse the info in lines other than the first
|
||||
for(Int32 j = i + 1; j < outputLines.Length; j++) {
|
||||
// Get the contents of the indented line
|
||||
String indentedLine = outputLines[j];
|
||||
|
||||
// We have hit the next adapter info
|
||||
if(Char.IsLetterOrDigit(indentedLine[0])) {
|
||||
i = j - 1;
|
||||
break;
|
||||
}
|
||||
|
||||
// Parse the MAC address in new versions of ifconfig; it no longer comes in the first line
|
||||
if(indentedLine.IndexOf(ether) >= 0 && String.IsNullOrWhiteSpace(adapter.MacAddress)) {
|
||||
Int32 startIndexHwd = indentedLine.IndexOf(ether) + ether.Length;
|
||||
adapter.MacAddress = indentedLine.Substring(startIndexHwd, 17).Trim();
|
||||
}
|
||||
|
||||
// Parse the IPv4 Address
|
||||
{
|
||||
String addressText = ParseOutputTagFromLine(indentedLine, "inet addr:") ?? ParseOutputTagFromLine(indentedLine, "inet ");
|
||||
|
||||
if(addressText != null) {
|
||||
if(IPAddress.TryParse(addressText, out IPAddress outValue)) {
|
||||
adapter.IPv4 = outValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Parse the IPv6 Address
|
||||
{
|
||||
String addressText = ParseOutputTagFromLine(indentedLine, "inet6 addr:") ?? ParseOutputTagFromLine(indentedLine, "inet6 ");
|
||||
|
||||
if(addressText != null) {
|
||||
if(IPAddress.TryParse(addressText, out IPAddress outValue)) {
|
||||
adapter.IPv6 = outValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// we have hit the end of the output in an indented line
|
||||
if(j >= outputLines.Length - 1) {
|
||||
i = outputLines.Length;
|
||||
}
|
||||
}
|
||||
|
||||
// Retrieve the wireless LAN info
|
||||
String wlanInfo = wlanOutput.FirstOrDefault(x => x.StartsWith(adapter.Name));
|
||||
|
||||
if(wlanInfo != null) {
|
||||
adapter.IsWireless = true;
|
||||
String[] essidParts = wlanInfo.Split(new[] { EssidTag }, StringSplitOptions.RemoveEmptyEntries);
|
||||
if(essidParts.Length >= 2) {
|
||||
adapter.AccessPointName = essidParts[1].Replace("\"", String.Empty).Trim();
|
||||
}
|
||||
}
|
||||
|
||||
// Add the current adapter to the result
|
||||
result.Add(adapter);
|
||||
}
|
||||
|
||||
return result.OrderBy(x => x.Name).ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves current wireless connected network name.
|
||||
/// </summary>
|
||||
/// <returns>The connected network name.</returns>
|
||||
public String GetWirelessNetworkName() => ProcessRunner.GetProcessOutputAsync("iwgetid", "-r").Result;
|
||||
|
||||
/// <summary>
|
||||
/// Parses the output tag from the given line.
|
||||
/// </summary>
|
||||
/// <param name="indentedLine">The indented line.</param>
|
||||
/// <param name="tagName">Name of the tag.</param>
|
||||
/// <returns>The value after the tag identifier</returns>
|
||||
private static String ParseOutputTagFromLine(String indentedLine, String tagName) {
|
||||
if(indentedLine.IndexOf(tagName) < 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Int32 startIndex = indentedLine.IndexOf(tagName) + tagName.Length;
|
||||
StringBuilder builder = new StringBuilder(1024);
|
||||
for(Int32 c = startIndex; c < indentedLine.Length; c++) {
|
||||
Char currentChar = indentedLine[c];
|
||||
if(!Char.IsPunctuation(currentChar) && !Char.IsLetterOrDigit(currentChar)) {
|
||||
break;
|
||||
}
|
||||
|
||||
_ = builder.Append(currentChar);
|
||||
}
|
||||
|
||||
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>
|
||||
/// Represents the OS Information
|
||||
/// System name
|
||||
/// </summary>
|
||||
public class OsInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// System name
|
||||
/// </summary>
|
||||
public string SysName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Node name
|
||||
/// </summary>
|
||||
public string NodeName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Release level
|
||||
/// </summary>
|
||||
public string Release { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Version level
|
||||
/// </summary>
|
||||
public string Version { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Hardware level
|
||||
/// </summary>
|
||||
public string Machine { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Domain name
|
||||
/// </summary>
|
||||
public string DomainName { get; set; }
|
||||
|
||||
/// <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() => $"{SysName} {Release} {Version}";
|
||||
}
|
||||
public String SysName {
|
||||
get; set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Node name
|
||||
/// </summary>
|
||||
public String NodeName {
|
||||
get; set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Release level
|
||||
/// </summary>
|
||||
public String Release {
|
||||
get; set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Version level
|
||||
/// </summary>
|
||||
public String Version {
|
||||
get; set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Hardware level
|
||||
/// </summary>
|
||||
public String Machine {
|
||||
get; set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Domain name
|
||||
/// </summary>
|
||||
public String DomainName {
|
||||
get; set;
|
||||
}
|
||||
|
||||
/// <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>
|
||||
/// 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/
|
||||
/// The unknown version
|
||||
/// </summary>
|
||||
public enum PiVersion
|
||||
{
|
||||
/// <summary>
|
||||
/// The unknown version
|
||||
/// </summary>
|
||||
Unknown = 0,
|
||||
|
||||
/// <summary>
|
||||
/// The model b rev1
|
||||
/// </summary>
|
||||
ModelBRev1 = 0x0002,
|
||||
|
||||
/// <summary>
|
||||
/// The model b rev1 ec N0001
|
||||
/// </summary>
|
||||
ModelBRev1ECN0001 = 0x0003,
|
||||
|
||||
/// <summary>
|
||||
/// The model b rev2x04
|
||||
/// </summary>
|
||||
ModelBRev2x04 = 0x0004,
|
||||
|
||||
/// <summary>
|
||||
/// The model b rev2x05
|
||||
/// </summary>
|
||||
ModelBRev2x05 = 0x0005,
|
||||
|
||||
/// <summary>
|
||||
/// The model b rev2x06
|
||||
/// </summary>
|
||||
ModelBRev2x06 = 0x0006,
|
||||
|
||||
/// <summary>
|
||||
/// The model ax07
|
||||
/// </summary>
|
||||
ModelAx07 = 0x0007,
|
||||
|
||||
/// <summary>
|
||||
/// The model ax08
|
||||
/// </summary>
|
||||
ModelAx08 = 0x0008,
|
||||
|
||||
/// <summary>
|
||||
/// The model ax09
|
||||
/// </summary>
|
||||
ModelAx09 = 0x0009,
|
||||
|
||||
/// <summary>
|
||||
/// The model b rev2x0d
|
||||
/// </summary>
|
||||
ModelBRev2x0d,
|
||||
|
||||
/// <summary>
|
||||
/// The model b rev2x0e
|
||||
/// </summary>
|
||||
ModelBRev2x0e,
|
||||
|
||||
/// <summary>
|
||||
/// The model b rev2x0f
|
||||
/// </summary>
|
||||
ModelBRev2x0f = 0x000f,
|
||||
|
||||
/// <summary>
|
||||
/// The model b plus0x10
|
||||
/// </summary>
|
||||
ModelBPlus0x10 = 0x0010,
|
||||
|
||||
/// <summary>
|
||||
/// The model b plus0x13
|
||||
/// </summary>
|
||||
ModelBPlus0x13 = 0x0013,
|
||||
|
||||
/// <summary>
|
||||
/// The compute module0x11
|
||||
/// </summary>
|
||||
ComputeModule0x11 = 0x0011,
|
||||
|
||||
/// <summary>
|
||||
/// The compute module0x14
|
||||
/// </summary>
|
||||
ComputeModule0x14 = 0x0014,
|
||||
|
||||
/// <summary>
|
||||
/// The model a plus0x12
|
||||
/// </summary>
|
||||
ModelAPlus0x12 = 0x0012,
|
||||
|
||||
/// <summary>
|
||||
/// The model a plus0x15
|
||||
/// </summary>
|
||||
ModelAPlus0x15 = 0x0015,
|
||||
|
||||
/// <summary>
|
||||
/// The pi2 model B1V1 sony
|
||||
/// </summary>
|
||||
Pi2ModelB1v1Sony = 0xa01041,
|
||||
|
||||
/// <summary>
|
||||
/// The pi2 model B1V1 embest
|
||||
/// </summary>
|
||||
Pi2ModelB1v1Embest = 0xa21041,
|
||||
|
||||
/// <summary>
|
||||
/// The pi2 model B1V2
|
||||
/// </summary>
|
||||
Pi2ModelB1v2 = 0xa22042,
|
||||
|
||||
/// <summary>
|
||||
/// The pi zero1v2
|
||||
/// </summary>
|
||||
PiZero1v2 = 0x900092,
|
||||
|
||||
/// <summary>
|
||||
/// The pi zero1v3
|
||||
/// </summary>
|
||||
PiZero1v3 = 0x900093,
|
||||
|
||||
/// <summary>
|
||||
/// The pi3 model b sony
|
||||
/// </summary>
|
||||
Pi3ModelBSony = 0xa02082,
|
||||
|
||||
/// <summary>
|
||||
/// The pi3 model b embest
|
||||
/// </summary>
|
||||
Pi3ModelBEmbest = 0xa22082
|
||||
}
|
||||
Unknown = 0,
|
||||
|
||||
/// <summary>
|
||||
/// The model b rev1
|
||||
/// </summary>
|
||||
ModelBRev1 = 0x0002,
|
||||
|
||||
/// <summary>
|
||||
/// The model b rev1 ec N0001
|
||||
/// </summary>
|
||||
ModelBRev1ECN0001 = 0x0003,
|
||||
|
||||
/// <summary>
|
||||
/// The model b rev2x04
|
||||
/// </summary>
|
||||
ModelBRev2x04 = 0x0004,
|
||||
|
||||
/// <summary>
|
||||
/// The model b rev2x05
|
||||
/// </summary>
|
||||
ModelBRev2x05 = 0x0005,
|
||||
|
||||
/// <summary>
|
||||
/// The model b rev2x06
|
||||
/// </summary>
|
||||
ModelBRev2x06 = 0x0006,
|
||||
|
||||
/// <summary>
|
||||
/// The model ax07
|
||||
/// </summary>
|
||||
ModelAx07 = 0x0007,
|
||||
|
||||
/// <summary>
|
||||
/// The model ax08
|
||||
/// </summary>
|
||||
ModelAx08 = 0x0008,
|
||||
|
||||
/// <summary>
|
||||
/// The model ax09
|
||||
/// </summary>
|
||||
ModelAx09 = 0x0009,
|
||||
|
||||
/// <summary>
|
||||
/// The model b rev2x0d
|
||||
/// </summary>
|
||||
ModelBRev2x0d,
|
||||
|
||||
/// <summary>
|
||||
/// The model b rev2x0e
|
||||
/// </summary>
|
||||
ModelBRev2x0e,
|
||||
|
||||
/// <summary>
|
||||
/// The model b rev2x0f
|
||||
/// </summary>
|
||||
ModelBRev2x0f = 0x000f,
|
||||
|
||||
/// <summary>
|
||||
/// The model b plus0x10
|
||||
/// </summary>
|
||||
ModelBPlus0x10 = 0x0010,
|
||||
|
||||
/// <summary>
|
||||
/// The model b plus0x13
|
||||
/// </summary>
|
||||
ModelBPlus0x13 = 0x0013,
|
||||
|
||||
/// <summary>
|
||||
/// The compute module0x11
|
||||
/// </summary>
|
||||
ComputeModule0x11 = 0x0011,
|
||||
|
||||
/// <summary>
|
||||
/// The compute module0x14
|
||||
/// </summary>
|
||||
ComputeModule0x14 = 0x0014,
|
||||
|
||||
/// <summary>
|
||||
/// The model a plus0x12
|
||||
/// </summary>
|
||||
ModelAPlus0x12 = 0x0012,
|
||||
|
||||
/// <summary>
|
||||
/// The model a plus0x15
|
||||
/// </summary>
|
||||
ModelAPlus0x15 = 0x0015,
|
||||
|
||||
/// <summary>
|
||||
/// The pi2 model B1V1 sony
|
||||
/// </summary>
|
||||
Pi2ModelB1v1Sony = 0xa01041,
|
||||
|
||||
/// <summary>
|
||||
/// The pi2 model B1V1 embest
|
||||
/// </summary>
|
||||
Pi2ModelB1v1Embest = 0xa21041,
|
||||
|
||||
/// <summary>
|
||||
/// The pi2 model B1V2
|
||||
/// </summary>
|
||||
Pi2ModelB1v2 = 0xa22042,
|
||||
|
||||
/// <summary>
|
||||
/// The pi zero1v2
|
||||
/// </summary>
|
||||
PiZero1v2 = 0x900092,
|
||||
|
||||
/// <summary>
|
||||
/// The pi zero1v3
|
||||
/// </summary>
|
||||
PiZero1v3 = 0x900093,
|
||||
|
||||
/// <summary>
|
||||
/// The pi3 model b sony
|
||||
/// </summary>
|
||||
Pi3ModelBSony = 0xa02082,
|
||||
|
||||
/// <summary>
|
||||
/// The pi3 model b embest
|
||||
/// </summary>
|
||||
Pi3ModelBEmbest = 0xa22082
|
||||
}
|
||||
}
|
||||
@@ -1,344 +1,343 @@
|
||||
namespace Unosquare.RaspberryIO.Computer
|
||||
{
|
||||
using Native;
|
||||
using Swan.Abstractions;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
using Unosquare.RaspberryIO.Native;
|
||||
using Unosquare.Swan.Abstractions;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
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>
|
||||
/// http://raspberry-pi-guide.readthedocs.io/en/latest/system.html
|
||||
/// Prevents a default instance of the <see cref="SystemInfo"/> class from being created.
|
||||
/// </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;
|
||||
|
||||
private static readonly object SyncRoot = new object();
|
||||
|
||||
/// <summary>
|
||||
/// Prevents a default instance of the <see cref="SystemInfo"/> class from being created.
|
||||
/// </summary>
|
||||
/// <exception cref="NotSupportedException">Could not initialize the GPIO controller</exception>
|
||||
private SystemInfo()
|
||||
{
|
||||
#region Obtain and format a property dictionary
|
||||
|
||||
var properties =
|
||||
typeof(SystemInfo).GetTypeInfo()
|
||||
.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
|
||||
.Where(
|
||||
p =>
|
||||
p.CanWrite && p.CanRead &&
|
||||
(p.PropertyType == typeof(string) || p.PropertyType == typeof(string[])))
|
||||
.ToArray();
|
||||
var propDictionary = new Dictionary<string, PropertyInfo>(StringComparer);
|
||||
|
||||
foreach (var prop in properties)
|
||||
{
|
||||
propDictionary[prop.Name.Replace(" ", string.Empty).ToLowerInvariant().Trim()] = prop;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Extract CPU information
|
||||
|
||||
if (File.Exists(CpuInfoFilePath))
|
||||
{
|
||||
var cpuInfoLines = File.ReadAllLines(CpuInfoFilePath);
|
||||
|
||||
foreach (var line in cpuInfoLines)
|
||||
{
|
||||
var lineParts = line.Split(new[] { ':' }, 2);
|
||||
if (lineParts.Length != 2)
|
||||
continue;
|
||||
|
||||
var propertyKey = lineParts[0].Trim().Replace(" ", string.Empty);
|
||||
var propertyStringValue = lineParts[1].Trim();
|
||||
|
||||
if (!propDictionary.ContainsKey(propertyKey)) continue;
|
||||
|
||||
var property = propDictionary[propertyKey];
|
||||
if (property.PropertyType == typeof(string))
|
||||
{
|
||||
property.SetValue(this, propertyStringValue);
|
||||
}
|
||||
else if (property.PropertyType == typeof(string[]))
|
||||
{
|
||||
var propertyArrayAvalue = propertyStringValue.Split(' ');
|
||||
property.SetValue(this, propertyArrayAvalue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Extract Memory Information
|
||||
|
||||
if (File.Exists(MemInfoFilePath))
|
||||
{
|
||||
var memInfoLines = File.ReadAllLines(MemInfoFilePath);
|
||||
foreach (var line in memInfoLines)
|
||||
{
|
||||
var lineParts = line.Split(new[] { ':' }, 2);
|
||||
if (lineParts.Length != 2)
|
||||
continue;
|
||||
|
||||
if (lineParts[0].ToLowerInvariant().Trim().Equals("memtotal") == false)
|
||||
continue;
|
||||
|
||||
var memKb = lineParts[1].ToLowerInvariant().Trim().Replace("kb", string.Empty).Trim();
|
||||
|
||||
if (int.TryParse(memKb, out var parsedMem))
|
||||
{
|
||||
InstalledRam = parsedMem * 1024;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Board Version and Form Factor
|
||||
|
||||
try
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(Revision) == false &&
|
||||
int.TryParse(
|
||||
Revision.ToUpperInvariant(),
|
||||
NumberStyles.HexNumber,
|
||||
CultureInfo.InvariantCulture,
|
||||
out var boardVersion))
|
||||
{
|
||||
RaspberryPiVersion = PiVersion.Unknown;
|
||||
if (Enum.GetValues(typeof(PiVersion)).Cast<int>().Contains(boardVersion))
|
||||
{
|
||||
RaspberryPiVersion = (PiVersion)boardVersion;
|
||||
}
|
||||
}
|
||||
|
||||
WiringPiBoardRevision = WiringPi.PiBoardRev();
|
||||
}
|
||||
catch
|
||||
{
|
||||
/* Ignore */
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Version Information
|
||||
|
||||
{
|
||||
var libParts = WiringPi.WiringPiLibrary.Split('.');
|
||||
var major = int.Parse(libParts[libParts.Length - 2]);
|
||||
var minor = int.Parse(libParts[libParts.Length - 1]);
|
||||
var version = new Version(major, minor);
|
||||
WiringPiVersion = version;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Extract OS Info
|
||||
|
||||
try
|
||||
{
|
||||
Standard.Uname(out var unameInfo);
|
||||
OperatingSystem = new OsInfo
|
||||
{
|
||||
DomainName = unameInfo.DomainName,
|
||||
Machine = unameInfo.Machine,
|
||||
NodeName = unameInfo.NodeName,
|
||||
Release = unameInfo.Release,
|
||||
SysName = unameInfo.SysName,
|
||||
Version = unameInfo.Version
|
||||
};
|
||||
}
|
||||
catch
|
||||
{
|
||||
OperatingSystem = new OsInfo();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the wiring pi library version.
|
||||
/// </summary>
|
||||
public Version WiringPiVersion { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the OS information.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The os information.
|
||||
/// </value>
|
||||
public OsInfo OperatingSystem { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Raspberry Pi version.
|
||||
/// </summary>
|
||||
public PiVersion RaspberryPiVersion { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Wiring Pi board revision (1 or 2).
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The wiring pi board revision.
|
||||
/// </value>
|
||||
public int WiringPiBoardRevision { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of processor cores.
|
||||
/// </summary>
|
||||
public int ProcessorCount
|
||||
{
|
||||
get
|
||||
{
|
||||
if (int.TryParse(Processor, out var outIndex))
|
||||
{
|
||||
return outIndex + 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the installed ram in bytes.
|
||||
/// </summary>
|
||||
public int InstalledRam { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this CPU is little endian.
|
||||
/// </summary>
|
||||
public bool IsLittleEndian => BitConverter.IsLittleEndian;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the CPU model name.
|
||||
/// </summary>
|
||||
public string ModelName { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of supported CPU features.
|
||||
/// </summary>
|
||||
public string[] Features { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the CPU implementer hex code.
|
||||
/// </summary>
|
||||
public string CpuImplementer { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the CPU architecture code.
|
||||
/// </summary>
|
||||
public string CpuArchitecture { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the CPU variant code.
|
||||
/// </summary>
|
||||
public string CpuVariant { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the CPU part code.
|
||||
/// </summary>
|
||||
public string CpuPart { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the CPU revision code.
|
||||
/// </summary>
|
||||
public string CpuRevision { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the hardware model number.
|
||||
/// </summary>
|
||||
public string Hardware { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the hardware revision number.
|
||||
/// </summary>
|
||||
public string Revision { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the serial number.
|
||||
/// </summary>
|
||||
public string Serial { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the system uptime (in seconds).
|
||||
/// </summary>
|
||||
public double Uptime
|
||||
{
|
||||
get
|
||||
{
|
||||
try
|
||||
{
|
||||
if (File.Exists(UptimeFilePath) == false) return 0;
|
||||
var parts = File.ReadAllText(UptimeFilePath).Trim().Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
if (parts.Length >= 1 && float.TryParse(parts[0], out var result))
|
||||
return result;
|
||||
}
|
||||
catch
|
||||
{
|
||||
/* Ignore */
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the uptime in TimeSpan.
|
||||
/// </summary>
|
||||
public TimeSpan UptimeTimeSpan => TimeSpan.FromSeconds(Uptime);
|
||||
|
||||
/// <summary>
|
||||
/// Placeholder for processor index
|
||||
/// </summary>
|
||||
private string Processor { get; set; }
|
||||
|
||||
/// <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()
|
||||
{
|
||||
var properties = typeof(SystemInfo).GetTypeInfo().GetProperties(BindingFlags.Instance | BindingFlags.Public)
|
||||
.Where(p => p.CanRead && (
|
||||
p.PropertyType == typeof(string) ||
|
||||
p.PropertyType == typeof(string[]) ||
|
||||
p.PropertyType == typeof(int) ||
|
||||
p.PropertyType == typeof(bool) ||
|
||||
p.PropertyType == typeof(TimeSpan)))
|
||||
.ToArray();
|
||||
|
||||
var properyValues = new List<string>
|
||||
{
|
||||
/// <exception cref="NotSupportedException">Could not initialize the GPIO controller</exception>
|
||||
private SystemInfo() {
|
||||
#region Obtain and format a property dictionary
|
||||
|
||||
PropertyInfo[] properties =
|
||||
typeof(SystemInfo).GetTypeInfo()
|
||||
.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)
|
||||
.Where(
|
||||
p =>
|
||||
p.CanWrite && p.CanRead &&
|
||||
(p.PropertyType == typeof(String) || p.PropertyType == typeof(String[])))
|
||||
.ToArray();
|
||||
Dictionary<String, PropertyInfo> propDictionary = new Dictionary<String, PropertyInfo>(StringComparer);
|
||||
|
||||
foreach(PropertyInfo prop in properties) {
|
||||
propDictionary[prop.Name.Replace(" ", String.Empty).ToLowerInvariant().Trim()] = prop;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Extract CPU information
|
||||
|
||||
if(File.Exists(CpuInfoFilePath)) {
|
||||
String[] cpuInfoLines = File.ReadAllLines(CpuInfoFilePath);
|
||||
|
||||
foreach(String line in cpuInfoLines) {
|
||||
String[] lineParts = line.Split(new[] { ':' }, 2);
|
||||
if(lineParts.Length != 2) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String propertyKey = lineParts[0].Trim().Replace(" ", String.Empty);
|
||||
String propertyStringValue = lineParts[1].Trim();
|
||||
|
||||
if(!propDictionary.ContainsKey(propertyKey)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
PropertyInfo property = propDictionary[propertyKey];
|
||||
if(property.PropertyType == typeof(String)) {
|
||||
property.SetValue(this, propertyStringValue);
|
||||
} else if(property.PropertyType == typeof(String[])) {
|
||||
String[] propertyArrayAvalue = propertyStringValue.Split(' ');
|
||||
property.SetValue(this, propertyArrayAvalue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Extract Memory Information
|
||||
|
||||
if(File.Exists(MemInfoFilePath)) {
|
||||
String[] memInfoLines = File.ReadAllLines(MemInfoFilePath);
|
||||
foreach(String line in memInfoLines) {
|
||||
String[] lineParts = line.Split(new[] { ':' }, 2);
|
||||
if(lineParts.Length != 2) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(lineParts[0].ToLowerInvariant().Trim().Equals("memtotal") == false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String memKb = lineParts[1].ToLowerInvariant().Trim().Replace("kb", String.Empty).Trim();
|
||||
|
||||
if(Int32.TryParse(memKb, out Int32 parsedMem)) {
|
||||
this.InstalledRam = parsedMem * 1024;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Board Version and Form Factor
|
||||
|
||||
try {
|
||||
if(String.IsNullOrWhiteSpace(this.Revision) == false &&
|
||||
Int32.TryParse(
|
||||
this.Revision.ToUpperInvariant(),
|
||||
NumberStyles.HexNumber,
|
||||
CultureInfo.InvariantCulture,
|
||||
out Int32 boardVersion)) {
|
||||
this.RaspberryPiVersion = PiVersion.Unknown;
|
||||
if(Enum.GetValues(typeof(PiVersion)).Cast<Int32>().Contains(boardVersion)) {
|
||||
this.RaspberryPiVersion = (PiVersion)boardVersion;
|
||||
}
|
||||
}
|
||||
|
||||
this.WiringPiBoardRevision = WiringPi.PiBoardRev();
|
||||
} catch {
|
||||
/* Ignore */
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Version Information
|
||||
|
||||
{
|
||||
String[] libParts = WiringPi.WiringPiLibrary.Split('.');
|
||||
Int32 major = Int32.Parse(libParts[libParts.Length - 2]);
|
||||
Int32 minor = Int32.Parse(libParts[libParts.Length - 1]);
|
||||
Version version = new Version(major, minor);
|
||||
this.WiringPiVersion = version;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Extract OS Info
|
||||
|
||||
try {
|
||||
_ = Standard.Uname(out SystemName unameInfo);
|
||||
this.OperatingSystem = new OsInfo {
|
||||
DomainName = unameInfo.DomainName,
|
||||
Machine = unameInfo.Machine,
|
||||
NodeName = unameInfo.NodeName,
|
||||
Release = unameInfo.Release,
|
||||
SysName = unameInfo.SysName,
|
||||
Version = unameInfo.Version
|
||||
};
|
||||
} catch {
|
||||
this.OperatingSystem = new OsInfo();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the wiring pi library version.
|
||||
/// </summary>
|
||||
public Version WiringPiVersion {
|
||||
get;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the OS information.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The os information.
|
||||
/// </value>
|
||||
public OsInfo OperatingSystem {
|
||||
get;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Raspberry Pi version.
|
||||
/// </summary>
|
||||
public PiVersion RaspberryPiVersion {
|
||||
get;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Wiring Pi board revision (1 or 2).
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The wiring pi board revision.
|
||||
/// </value>
|
||||
public Int32 WiringPiBoardRevision {
|
||||
get;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the number of processor cores.
|
||||
/// </summary>
|
||||
public Int32 ProcessorCount => Int32.TryParse(this.Processor, out Int32 outIndex) ? outIndex + 1 : 0;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the installed ram in bytes.
|
||||
/// </summary>
|
||||
public Int32 InstalledRam {
|
||||
get;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this CPU is little endian.
|
||||
/// </summary>
|
||||
public Boolean IsLittleEndian => BitConverter.IsLittleEndian;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the CPU model name.
|
||||
/// </summary>
|
||||
public String ModelName {
|
||||
get; private set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of supported CPU features.
|
||||
/// </summary>
|
||||
public String[] Features {
|
||||
get; private set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the CPU implementer hex code.
|
||||
/// </summary>
|
||||
public String CpuImplementer {
|
||||
get; private set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the CPU architecture code.
|
||||
/// </summary>
|
||||
public String CpuArchitecture {
|
||||
get; private set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the CPU variant code.
|
||||
/// </summary>
|
||||
public String CpuVariant {
|
||||
get; private set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the CPU part code.
|
||||
/// </summary>
|
||||
public String CpuPart {
|
||||
get; private set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the CPU revision code.
|
||||
/// </summary>
|
||||
public String CpuRevision {
|
||||
get; private set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the hardware model number.
|
||||
/// </summary>
|
||||
public String Hardware {
|
||||
get; private set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the hardware revision number.
|
||||
/// </summary>
|
||||
public String Revision {
|
||||
get; private set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the serial number.
|
||||
/// </summary>
|
||||
public String Serial {
|
||||
get; private set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the system uptime (in seconds).
|
||||
/// </summary>
|
||||
public Double Uptime {
|
||||
get {
|
||||
try {
|
||||
if(File.Exists(UptimeFilePath) == false) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
String[] parts = File.ReadAllText(UptimeFilePath).Trim().Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
if(parts.Length >= 1 && Single.TryParse(parts[0], out Single result)) {
|
||||
return result;
|
||||
}
|
||||
} catch {
|
||||
/* Ignore */
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the uptime in TimeSpan.
|
||||
/// </summary>
|
||||
public TimeSpan UptimeTimeSpan => TimeSpan.FromSeconds(this.Uptime);
|
||||
|
||||
/// <summary>
|
||||
/// Placeholder for processor index
|
||||
/// </summary>
|
||||
private String Processor {
|
||||
get; set;
|
||||
}
|
||||
|
||||
/// <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() {
|
||||
PropertyInfo[] properties = typeof(SystemInfo).GetTypeInfo().GetProperties(BindingFlags.Instance | BindingFlags.Public)
|
||||
.Where(p => p.CanRead && (
|
||||
p.PropertyType == typeof(String) ||
|
||||
p.PropertyType == typeof(String[]) ||
|
||||
p.PropertyType == typeof(Int32) ||
|
||||
p.PropertyType == typeof(Boolean) ||
|
||||
p.PropertyType == typeof(TimeSpan)))
|
||||
.ToArray();
|
||||
|
||||
List<String> properyValues = new List<String>
|
||||
{
|
||||
"System Information",
|
||||
$"\t{nameof(WiringPiVersion),-22}: {WiringPiVersion}",
|
||||
$"\t{nameof(RaspberryPiVersion),-22}: {RaspberryPiVersion}"
|
||||
};
|
||||
|
||||
foreach (var property in properties)
|
||||
{
|
||||
if (property.PropertyType != typeof(string[]))
|
||||
{
|
||||
properyValues.Add($"\t{property.Name,-22}: {property.GetValue(this)}");
|
||||
}
|
||||
else if (property.GetValue(this) is string[] allValues)
|
||||
{
|
||||
var concatValues = string.Join(" ", allValues);
|
||||
properyValues.Add($"\t{property.Name,-22}: {concatValues}");
|
||||
}
|
||||
}
|
||||
|
||||
return string.Join(Environment.NewLine, properyValues.ToArray());
|
||||
}
|
||||
}
|
||||
$"\t{nameof(this.WiringPiVersion),-22}: {this.WiringPiVersion}",
|
||||
$"\t{nameof(this.RaspberryPiVersion),-22}: {this.RaspberryPiVersion}"
|
||||
};
|
||||
|
||||
foreach(PropertyInfo property in properties) {
|
||||
if(property.PropertyType != typeof(String[])) {
|
||||
properyValues.Add($"\t{property.Name,-22}: {property.GetValue(this)}");
|
||||
} else if(property.GetValue(this) is String[] allValues) {
|
||||
String concatValues = String.Join(" ", allValues);
|
||||
properyValues.Add($"\t{property.Name,-22}: {concatValues}");
|
||||
}
|
||||
}
|
||||
|
||||
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>
|
||||
/// Represents a wireless network information
|
||||
/// Gets the ESSID of the Wireless network.
|
||||
/// </summary>
|
||||
public class WirelessNetworkInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the ESSID of the Wireless network.
|
||||
/// </summary>
|
||||
public string Name { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the network quality.
|
||||
/// </summary>
|
||||
public string Quality { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this instance is encrypted.
|
||||
/// </summary>
|
||||
public bool IsEncrypted { get; internal set; }
|
||||
}
|
||||
public String Name {
|
||||
get; internal set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the network quality.
|
||||
/// </summary>
|
||||
public String Quality {
|
||||
get; internal set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this instance is encrypted.
|
||||
/// </summary>
|
||||
public Boolean IsEncrypted {
|
||||
get; internal set;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user