diff --git a/.gitignore b/.gitignore
index fcb74bf..0056bec 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,6 +9,7 @@ TestResults
**.user
**.suo
**.sdf
+.vs/*
# resharper
/_[Rr]e[Ss]harper.*
@@ -19,4 +20,8 @@ TestResults
[Tt]humbs.db
[Dd]esktop.ini
-RaspberrySharp.System.userprefs
\ No newline at end of file
+RaspberrySharp.System.userprefs
+
+# Nuget packages
+packages/*
+!packages/repositories.config
diff --git a/Icon.png b/Icon.png
index 5db0375..1dc39dd 100644
Binary files a/Icon.png and b/Icon.png differ
diff --git a/README.md b/README.md
index 57fc772..44bd2bf 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,6 @@
+
+[](https://bettercodehub.com/)
+
Raspberry# System
=================
@@ -15,8 +18,8 @@ Features
### Raspberry.System
Raspberry.System provides utilities for Raspberry Pi boards, while using .NET concepts, syntax and case.
-You can easily add a reference to it in your Visual Studio projects using the **[Raspberry.System Nuget](https://www.nuget.org/packages/Raspberry.System)**.
+You can easily add a reference to it in your Visual Studio projects using the **[Raspberry.System Nuget](https://www.nuget.org/packages/Raspberry.System3)**.
It currently support the following features:
-+ Automatic detection of various Raspberry Pi revisions, as of 2013-09, **Raspberry Pi model B rev1 and rev2 and Raspberry Pi model A**
-+ High resolution (about 1�s) timers
++ Automatic detection of various Raspberry Pi revisions, as of 2017-11: **Raspberry Pi model B rev1 up to Pi 3 model B**
++ High resolution (about 1µs) timers
diff --git a/Raspberry.System.3.0.0.nupkg b/Raspberry.System.3.0.0.nupkg
new file mode 100644
index 0000000..0539e37
Binary files /dev/null and b/Raspberry.System.3.0.0.nupkg differ
diff --git a/Raspberry.System.nuspec b/Raspberry.System.nuspec
deleted file mode 100644
index 23ffa1d..0000000
--- a/Raspberry.System.nuspec
+++ /dev/null
@@ -1,33 +0,0 @@
-
-
-
- Raspberry.System
- 0.0.0
- Raspberry.System
- Eric Bézine
- Raspberry-Sharp
- http://opensource.org/licenses/GPL-2.0
- https://github.com/raspberry-sharp/raspberry-sharp-system/wiki
- https://raw.github.com/raspberry-sharp/raspberry-sharp-system/master/Icon.png
- true
-
- Raspberry.System is a Mono/.NET assembly providing access to Raspberry Pi system features.
-
- It is an initiative of the Raspberry# Community, aimed at providing tools and information concerning use of Raspberry Pi boards with Mono/.NET framework.
- Visit project [Github site](https://github.com/raspberry-sharp/raspberry-sharp-system/) for documentation and samples.
-
- Raspberry.System is a Mono/.NET assembly providing access to Raspberry Pi system features.
- en-US
- Raspberry Pi Mono System Timers
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/Raspberry.System/Board.cs b/Raspberry.System/Board.cs
index 4595242..327f484 100644
--- a/Raspberry.System/Board.cs
+++ b/Raspberry.System/Board.cs
@@ -1,9 +1,11 @@
#region References
using System;
+using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
+using System.Text;
#endregion
@@ -13,29 +15,31 @@ namespace Raspberry
/// Represents the Raspberry Pi mainboard.
///
///
- /// Version and revisions are based on .
+ /// Version and revisions are based on .
/// for information.
+ /// NOTES on V3.1.2:
+ ///
+ /// - IsOverClocked has been removed. This used the "warranty" flag (i.e. void if overclocked) but this policy was changed.
+ /// - Firmware has been changed to RevisionCode.
+ /// - Details about the cores are also loaded.
+ ///
///
public class Board
{
+
#region Fields
- private static readonly Lazy board = new Lazy(LoadBoard);
-
- private readonly Dictionary settings;
- private readonly Lazy model;
- private readonly Lazy connectorPinout;
+ private static Board board;
+ private uint revisionCode;
+ private IList cores = new List();
#endregion
#region Instance Management
- private Board(Dictionary settings)
+ private Board()
{
- model = new Lazy(LoadModel);
- connectorPinout = new Lazy(LoadConnectorPinout);
-
- this.settings = settings;
+ LoadBoard();
}
#endregion
@@ -45,10 +49,7 @@ private Board(Dictionary settings)
///
/// Gets the current mainboard configuration.
///
- public static Board Current
- {
- get { return board.Value; }
- }
+ public static Board Current => board ?? ( board = new Board() );
///
/// Gets a value indicating whether this instance is a Raspberry Pi.
@@ -56,28 +57,7 @@ public static Board Current
///
/// true if this instance is a Raspberry Pi; otherwise, false.
///
- public bool IsRaspberryPi
- {
- get
- {
- return Processor != Processor.Unknown;
- }
- }
-
- ///
- /// Gets the processor name.
- ///
- ///
- /// The name of the processor.
- ///
- public string ProcessorName
- {
- get
- {
- string hardware;
- return settings.TryGetValue("Hardware", out hardware) ? hardware : null;
- }
- }
+ public bool IsRaspberryPi { get; private set; }
///
/// Gets the processor.
@@ -85,73 +65,41 @@ public string ProcessorName
///
/// The processor.
///
- public Processor Processor
- {
- get
- {
- Processor processor;
- return Enum.TryParse(ProcessorName, true, out processor) ? processor : Processor.Unknown;
- }
- }
+ public Processor Processor { get; private set; }
///
- /// Gets the board firmware version.
+ /// Gets the board revision code. This is the number from cpuinfo containing many details about the board.
///
- public int Firmware
+ public uint RevisionCode
{
- get
+ get => revisionCode;
+ private set
{
- string revision;
- int firmware;
- if (settings.TryGetValue("Revision", out revision)
- && !string.IsNullOrEmpty(revision)
- && int.TryParse(revision, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out firmware))
- return firmware;
-
- return 0;
+ revisionCode = value;
+ ParseRevisionCode( value, SetBoardParams );
+ ConnectorPinout = LoadConnectorPinout();
}
}
///
- /// Gets the serial number.
+ /// Gets the board revision, i.e. 1.1 etc.
///
- public string SerialNumber
- {
- get {
- string serial;
- if (settings.TryGetValue("Serial", out serial)
- && !string.IsNullOrEmpty(serial))
- return serial;
+ public Version Revision { get; private set; }
- return null;
- }
- }
+ ///
+ /// Gets the memory size in MB.
+ ///
+ public int MemorySize { get; private set; }
///
- /// Gets a value indicating whether Raspberry Pi board is overclocked.
+ /// Gets the serial number.
///
- ///
- /// true if Raspberry Pi is overclocked; otherwise, false.
- ///
- public bool IsOverclocked
- {
- get
- {
- var firmware = Firmware;
- return (firmware & 0xFFFF0000) != 0;
- }
- }
+ public string SerialNumber { get; private set; }
///
/// Gets the model.
///
- ///
- /// The model.
- ///
- public Model Model
- {
- get { return model.Value; }
- }
+ public Model Model { get; private set; }
///
/// Gets the connector revision.
@@ -160,97 +108,238 @@ public Model Model
/// The connector revision.
///
/// See for more information.
- public ConnectorPinout ConnectorPinout
+ public ConnectorPinout ConnectorPinout { get; private set; }
+
+ ///
+ /// Gets the list of cores on this board.
+ ///
+ public IList Cores => cores;
+
+ ///
+ /// Pretty prints the board info.
+ ///
+ public override string ToString()
{
- get { return connectorPinout.Value; }
+ var sb = new StringBuilder( $"Board:\t\t{Model.GetDisplayName()}\n" +
+ $"Revision code:\t0x{RevisionCode:X}\n" +
+ $"Model:\t\t{Model}\n" +
+ $"Revision:\t{Revision}\n" +
+ $"Processor:\t{Processor}\n" +
+ $"Memory size:\t{MemorySize} MB\n" +
+ $"Connector:\t{ConnectorPinout}\n" +
+ $"Serial#:\t{SerialNumber}\n" );
+
+ foreach ( var core in Cores ) sb.Append( "\n" + core );
+
+ return sb.ToString();
}
#endregion
#region Private Helpers
- private static Board LoadBoard()
+ private void LoadBoard()
{
+ IsRaspberryPi = true;
+ string[] cpuInfo;
try
{
const string filePath = "/proc/cpuinfo";
-
- var cpuInfo = File.ReadAllLines(filePath);
- var settings = new Dictionary();
- var suffix = string.Empty;
-
- foreach(var l in cpuInfo)
- {
- var separator = l.IndexOf(':');
+ Tracing.TraceInfo( $"Loading board information from '{filePath}'." );
+ cpuInfo = File.ReadAllLines( filePath );
+ }
+ catch ( Exception ex )
+ {
+ Tracing.TraceError( "Unable to read cpuinfo - are you sure this is a Pi? " + ex.Message );
+ IsRaspberryPi = false;
+ return;
+ }
- if (!string.IsNullOrWhiteSpace(l) && separator > 0)
- {
- var key = l.Substring(0, separator).Trim();
- var val = l.Substring(separator + 1).Trim();
- if (string.Equals(key, "processor", StringComparison.InvariantCultureIgnoreCase))
- suffix = "." + val;
+ Core currentCore = null;
+ foreach ( var l in cpuInfo )
+ {
+ var separator = l.IndexOf( ':' );
- settings.Add(key + suffix, val);
+ if ( !string.IsNullOrWhiteSpace( l ) && separator > 0 )
+ {
+ var key = l.Substring( 0, separator ).Trim().ToLower();
+ var val = l.Substring( separator + 1 ).Trim();
+ switch ( key )
+ {
+ case "revision":
+ uint revision;
+ if ( uint.TryParse( val, NumberStyles.HexNumber, null, out revision ) )
+ {
+ RevisionCode = revision;
+ }
+ else
+ {
+ Tracing.TraceError( $"Unable to parse revision number string - {val}." );
+ }
+ break;
+
+ case "serial":
+ SerialNumber = val;
+ break;
+
+ case "processor":
+ int coreNum;
+ if ( int.TryParse( val, out coreNum ) )
+ {
+ currentCore = new Core( coreNum );
+ cores.Add( currentCore );
+ }
+ else
+ {
+ currentCore = null;
+ }
+ break;
+
+ default:
+ currentCore?.SetState( key, val );
+ break;
}
- else
- suffix = "";
}
+ }
+ Tracing.TraceInfo( "Board information loading complete." );
+ }
+
+ ///
+ /// Parses the Pi's revision code.
+ ///
+ public static void ParseRevisionCode( uint revisionCode, Action setBoardParams )
+ {
+ var oldStyle = ( revisionCode & 0x00800000 ) == 0; // Bit 24
+ if ( oldStyle )
+ {
+ ParseOldRevisionCode( revisionCode, setBoardParams );
+ return;
+ }
+
+ var memSizeBits = ( revisionCode & 0x00700000 ) >> 20; // Bits 21-23
+ var memSize = 256;
+ switch ( memSizeBits )
+ {
+ case 1:
+ memSize = 512;
+ break;
+ case 2:
+ memSize = 1024;
+ break;
+ }
- return new Board(settings);
+ var procBits = ( revisionCode & 0x000F000 ) >> 12; // Bits 13-16
+ var proc = Processor.Bcm2835;
+ switch ( procBits )
+ {
+ case 1:
+ proc = Processor.Bcm2836;
+ break;
+ case 2:
+ proc = Processor.Bcm2837;
+ break;
}
- catch
+
+ var typeBits = ( revisionCode & 0x0000FF0 ) >> 4; // Bits 5-12
+ var type = Model.Unknown;
+ switch ( typeBits )
{
- return new Board(new Dictionary());
+ case 0x00:
+ type = Model.A;
+ break;
+ case 0x02:
+ type = Model.APlus;
+ break;
+ case 0x03:
+ type = Model.BPlus;
+ break;
+ case 0x04:
+ type = Model.B2;
+ break;
+ case 0x06:
+ type = Model.ComputeModule;
+ break;
+ case 0x08:
+ type = Model.B3;
+ break;
+ case 0x09:
+ type = Model.Zero;
+ break;
+ case 0x0a:
+ type = Model.ComputeModule3;
+ break;
+ case 0x0c:
+ type = Model.ZeroW;
+ break;
}
+
+ var revisionBits = revisionCode & 0x000000F; // Bottom 4 bits
+ var revision = new Version( 1, (int)revisionBits );
+ setBoardParams( type, revision, memSize, proc );
}
- private Model LoadModel()
+ private static void ParseOldRevisionCode( uint revisionCode, Action setBoardParams )
{
- var firmware = Firmware;
- switch (firmware & 0xFFFF)
+ switch ( revisionCode & 0xFFFF )
{
case 0x2:
case 0x3:
- return Model.BRev1;
+ setBoardParams( Model.BRev1, new Version( 1, 0 ), 256, Processor.Bcm2835 );
+ break;
case 0x4:
case 0x5:
case 0x6:
- case 0xd:
- case 0xe:
- case 0xf:
- return Model.BRev2;
+ setBoardParams( Model.BRev2, new Version( 2, 0 ), 256, Processor.Bcm2835 );
+ break;
case 0x7:
case 0x8:
case 0x9:
- return Model.A;
+ setBoardParams( Model.A, new Version( 2, 0 ), 256, Processor.Bcm2835 );
+ break;
+
+ case 0xd:
+ case 0xe:
+ case 0xf:
+ setBoardParams( Model.BRev2, new Version( 2, 0 ), 512, Processor.Bcm2835 );
+ break;
case 0x10:
- return Model.BPlus;
+ setBoardParams( Model.BPlus, new Version( 1, 0 ), 512, Processor.Bcm2835 );
+ break;
case 0x11:
- return Model.ComputeModule;
+ case 0x14:
+ setBoardParams( Model.ComputeModule, new Version( 1, 0 ), 512, Processor.Bcm2835 );
+ break;
case 0x12:
- return Model.APlus;
+ setBoardParams( Model.APlus, new Version( 1, 1 ), 256, Processor.Bcm2835 );
+ break;
- case 0x1040:
- case 0x1041:
- return Model.B2;
+ case 0x13:
+ setBoardParams( Model.BPlus, new Version( 1, 2 ), 512, Processor.Bcm2835 );
+ break;
- case 0x0092:
- case 0x0093:
- return Model.Zero;
-
- case 0x2082:
- return Model.B3;
+ case 0x15:
+ setBoardParams( Model.APlus, new Version( 1, 1 ), 512, Processor.Bcm2835 ); // Ambiguous - could have 256MB.
+ break;
default:
- return Model.Unknown;
+ setBoardParams( Model.Unknown, new Version( 0, 0 ), 0, Processor.Bcm2835 );
+ break;
}
}
+ private void SetBoardParams(Model model, Version revision, int memSize, Processor proc )
+ {
+ Model = model;
+ Revision = revision;
+ MemorySize = memSize;
+ Processor = proc;
+ }
+
private ConnectorPinout LoadConnectorPinout()
{
switch (Model)
@@ -267,7 +356,9 @@ private ConnectorPinout LoadConnectorPinout()
case Model.APlus:
case Model.B2:
case Model.Zero:
+ case Model.ZeroW:
case Model.B3:
+ case Model.ComputeModule3:
return ConnectorPinout.Plus;
default:
@@ -277,4 +368,4 @@ private ConnectorPinout LoadConnectorPinout()
#endregion
}
-}
\ No newline at end of file
+}
diff --git a/Raspberry.System/Core.cs b/Raspberry.System/Core.cs
new file mode 100644
index 0000000..8cd8712
--- /dev/null
+++ b/Raspberry.System/Core.cs
@@ -0,0 +1,122 @@
+
+using System.Globalization;
+
+namespace Raspberry
+{
+ ///
+ /// Contains information about an R-Pi core.
+ ///
+ public class Core
+ {
+ public Core( int procNumber )
+ {
+ ProcessorNumber = procNumber;
+ }
+
+ ///
+ /// The number of this core.
+ ///
+ public int ProcessorNumber { get; }
+
+ ///
+ /// The model name of this core.
+ ///
+ public string ModelName { get; internal set; }
+
+ ///
+ /// Bogus MIPS estimate for this core.
+ ///
+ public double BogoMips { get; internal set; }
+
+ ///
+ /// Features of this core.
+ ///
+ public string Features { get; internal set; }
+
+ ///
+ /// Gets the APU implementer code
+ ///
+ public int CpuImplementer { get; internal set; }
+
+ ///
+ /// Gets the CPU architecture code.
+ ///
+ public int CpuArchitecture { get; internal set; }
+
+ ///
+ /// Gets the CPU variant code.
+ ///
+ public int CpuVariant { get; internal set; }
+
+ ///
+ /// Gets the CPU part code.
+ ///
+ public int CpuPart { get; internal set; }
+
+ ///
+ /// Gets the CPU revision code.
+ ///
+ public int CpuRevision { get; internal set; }
+
+ ///
+ /// Converts core information to string format.
+ ///
+ public override string ToString()
+ {
+ return $"Core:\t\t{ProcessorNumber}\n" +
+ $" -> Model:\t{ModelName}\n" +
+ $" -> BogoMIPS:\t{BogoMips}\n" +
+ $" -> Features:\t{Features}\n" +
+ $" -> CPU:\timplementer=0x{CpuImplementer:X}, arch={CpuArchitecture}, variant=0x{CpuVariant:X}, " +
+ $"part=0x{CpuPart:X}, rev={CpuRevision}\n";
+ }
+
+ internal void SetState( string key, string val )
+ {
+ switch ( key )
+ {
+ case "model name":
+ ModelName = val;
+ break;
+
+ case "bogomips":
+ double bmips;
+ if ( double.TryParse( val, out bmips ) )
+ {
+ BogoMips = bmips;
+ }
+ break;
+
+ case "features":
+ Features = val;
+ break;
+
+ case "cpu implementer":
+ CpuImplementer = ParseInt( val, NumberStyles.HexNumber );
+ break;
+
+ case "cpu architecture":
+ CpuArchitecture = ParseInt( val );
+ break;
+
+ case "cpu variant":
+ CpuVariant = ParseInt( val, NumberStyles.HexNumber );
+ break;
+
+ case "cpu part":
+ CpuPart = ParseInt( val, NumberStyles.HexNumber );
+ break;
+
+ case "cpu revision":
+ CpuRevision = ParseInt( val );
+ break;
+ }
+ }
+
+ private int ParseInt( string val, NumberStyles numberStyle = NumberStyles.Integer )
+ {
+ int.TryParse( val, numberStyle, null, out int ret );
+ return ret;
+ }
+ }
+}
diff --git a/Raspberry.System/Model.cs b/Raspberry.System/Model.cs
index c16174b..f621c74 100644
--- a/Raspberry.System/Model.cs
+++ b/Raspberry.System/Model.cs
@@ -53,10 +53,20 @@ public enum Model
///
Zero,
+ ///
+ /// Pi Zero W.
+ ///
+ ZeroW,
+
///
/// Pi 3 Model B.
///
- B3
+ B3,
+
+ ///
+ /// Compute module 3.
+ ///
+ ComputeModule3,
}
///
@@ -74,7 +84,7 @@ public static string GetDisplayName(this Model model)
switch (model)
{
case Model.Unknown:
- return null;
+ return "Unknown - not a Pi!";
case Model.A:
return "Raspberry Pi Model A";
case Model.APlus:
@@ -91,12 +101,16 @@ public static string GetDisplayName(this Model model)
return "Raspberry Pi 2 Model B";
case Model.Zero:
return "Raspberry Pi Zero";
+ case Model.ZeroW:
+ return "Raspberry Pi Zero W";
case Model.B3:
return "Raspberry Pi 3 Model B";
-
+ case Model.ComputeModule3:
+ return "Raspberry Pi Compute Module 3";
+
default:
throw new ArgumentOutOfRangeException("model");
}
}
}
-}
\ No newline at end of file
+}
diff --git a/Raspberry.System/Processor.cs b/Raspberry.System/Processor.cs
index 01e2b69..fd91c05 100644
--- a/Raspberry.System/Processor.cs
+++ b/Raspberry.System/Processor.cs
@@ -11,13 +11,18 @@ public enum Processor
Unknown,
///
- /// Processor is a BCM2708.
+ /// Processor is a BCM2835. (Used to be referred to as BCM2708.)
///
- Bcm2708,
+ Bcm2835,
///
- /// Processor is a BCM2709.
+ /// Processor is a BCM2836. (Used to be referred to as BCM2709.)
///
- Bcm2709
+ Bcm2836,
+
+ ///
+ /// Processor is BCM2837
+ ///
+ Bcm2837
}
}
\ No newline at end of file
diff --git a/Raspberry.System/Properties/AssemblyInfo.cs b/Raspberry.System/Properties/AssemblyInfo.cs
index e57f5af..bd74171 100644
--- a/Raspberry.System/Properties/AssemblyInfo.cs
+++ b/Raspberry.System/Properties/AssemblyInfo.cs
@@ -31,5 +31,5 @@
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("1.2.0.0")]
-[assembly: AssemblyFileVersion("1.2.0.0")]
+[assembly: AssemblyVersion("3.1.2.0")]
+[assembly: AssemblyFileVersion("3.1.2.0")]
diff --git a/Raspberry.System/Raspberry.System.csproj b/Raspberry.System/Raspberry.System.csproj
index d5982b7..04116f5 100644
--- a/Raspberry.System/Raspberry.System.csproj
+++ b/Raspberry.System/Raspberry.System.csproj
@@ -39,6 +39,7 @@
+
@@ -48,6 +49,7 @@
+