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 {
///
/// http://raspberry-pi-guide.readthedocs.io/en/latest/system.html
///
public sealed class SystemInfo : SingletonBase {
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 = "")]
private static readonly Object SyncRoot = new Object();
///
/// Prevents a default instance of the class from being created.
///
/// Could not initialize the GPIO controller
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 propDictionary = new Dictionary(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().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
}
///
/// Gets the wiring pi library version.
///
public Version WiringPiVersion {
get;
}
///
/// Gets the OS information.
///
///
/// The os information.
///
public OsInfo OperatingSystem {
get;
}
///
/// Gets the Raspberry Pi version.
///
public PiVersion RaspberryPiVersion {
get;
}
///
/// Gets the Wiring Pi board revision (1 or 2).
///
///
/// The wiring pi board revision.
///
public Int32 WiringPiBoardRevision {
get;
}
///
/// Gets the number of processor cores.
///
public Int32 ProcessorCount => Int32.TryParse(this.Processor, out Int32 outIndex) ? outIndex + 1 : 0;
///
/// Gets the installed ram in bytes.
///
public Int32 InstalledRam {
get;
}
///
/// Gets a value indicating whether this CPU is little endian.
///
public Boolean IsLittleEndian => BitConverter.IsLittleEndian;
///
/// Gets the CPU model name.
///
public String ModelName {
get; private set;
}
///
/// Gets a list of supported CPU features.
///
public String[] Features {
get; private set;
}
///
/// Gets the CPU implementer hex code.
///
public String CpuImplementer {
get; private set;
}
///
/// Gets the CPU architecture code.
///
public String CpuArchitecture {
get; private set;
}
///
/// Gets the CPU variant code.
///
public String CpuVariant {
get; private set;
}
///
/// Gets the CPU part code.
///
public String CpuPart {
get; private set;
}
///
/// Gets the CPU revision code.
///
public String CpuRevision {
get; private set;
}
///
/// Gets the hardware model number.
///
public String Hardware {
get; private set;
}
///
/// Gets the hardware revision number.
///
public String Revision {
get; private set;
}
///
/// Gets the serial number.
///
public String Serial {
get; private set;
}
///
/// Gets the system uptime (in seconds).
///
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;
}
}
///
/// Gets the uptime in TimeSpan.
///
public TimeSpan UptimeTimeSpan => TimeSpan.FromSeconds(this.Uptime);
///
/// Placeholder for processor index
///
private String Processor {
get; set;
}
///
/// Returns a that represents this instance.
///
///
/// A that represents this instance.
///
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 properyValues = new List
{
"System Information",
$"\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());
}
}
}