1
+ #region References
2
+
3
+ using System ;
4
+ using System . Collections . Generic ;
5
+ using System . Globalization ;
6
+ using System . IO ;
7
+
8
+ #endregion
9
+
10
+ namespace Raspberry
11
+ {
12
+ /// <summary>
13
+ /// Represents the Raspberry Pi mainboard.
14
+ /// </summary>
15
+ /// <remarks>
16
+ /// Version and revisions are based on <see cref="http://raspberryalphaomega.org.uk/2013/02/06/automatic-raspberry-pi-board-revision-detection-model-a-b1-and-b2/"/>.
17
+ /// <see cref="http://www.raspberrypi-spy.co.uk/2012/09/checking-your-raspberry-pi-board-version/"/> for information.
18
+ /// </remarks>
19
+ public class Board
20
+ {
21
+ #region Fields
22
+
23
+ private static readonly Lazy < Board > board = new Lazy < Board > ( LoadBoard ) ;
24
+
25
+ private readonly Dictionary < string , string > settings ;
26
+ private readonly Lazy < Model > model ;
27
+ private readonly Lazy < ConnectorPinout > connectorPinout ;
28
+
29
+ #endregion
30
+
31
+ #region Instance Management
32
+
33
+ private Board ( Dictionary < string , string > settings )
34
+ {
35
+ model = new Lazy < Model > ( LoadModel ) ;
36
+ connectorPinout = new Lazy < ConnectorPinout > ( LoadConnectorPinout ) ;
37
+
38
+ this . settings = settings ;
39
+ }
40
+
41
+ #endregion
42
+
43
+ #region Properties
44
+
45
+ /// <summary>
46
+ /// Gets the current mainboard configuration.
47
+ /// </summary>
48
+ public static Board Current
49
+ {
50
+ get { return board . Value ; }
51
+ }
52
+
53
+ /// <summary>
54
+ /// Gets a value indicating whether this instance is a Raspberry Pi.
55
+ /// </summary>
56
+ /// <value>
57
+ /// <c>true</c> if this instance is a Raspberry Pi; otherwise, <c>false</c>.
58
+ /// </value>
59
+ public bool IsRaspberryPi
60
+ {
61
+ get
62
+ {
63
+ return Processor != Processor . Unknown ;
64
+ }
65
+ }
66
+
67
+ /// <summary>
68
+ /// Gets the processor name.
69
+ /// </summary>
70
+ /// <value>
71
+ /// The name of the processor.
72
+ /// </value>
73
+ public string ProcessorName
74
+ {
75
+ get
76
+ {
77
+ string hardware ;
78
+ return settings . TryGetValue ( "Hardware" , out hardware ) ? hardware : null ;
79
+ }
80
+ }
81
+
82
+ /// <summary>
83
+ /// Gets the processor.
84
+ /// </summary>
85
+ /// <value>
86
+ /// The processor.
87
+ /// </value>
88
+ public Processor Processor
89
+ {
90
+ get
91
+ {
92
+ Processor processor ;
93
+ if ( Enum . TryParse ( ProcessorName , true , out processor ) )
94
+ {
95
+ // Check to see if we're dealing with a Pi 4 Model B
96
+ // The Pi 4 Model B currently lies to us and tells us that it's a BCM2835
97
+ if ( processor == Processor . Bcm2835 && Model == Model . Pi4 )
98
+ processor = Processor . Bcm2711 ;
99
+
100
+ return processor ;
101
+ }
102
+
103
+ return Processor . Unknown ;
104
+ }
105
+ }
106
+
107
+ /// <summary>
108
+ /// Gets the board firmware version.
109
+ /// </summary>
110
+ public int Firmware
111
+ {
112
+ get
113
+ {
114
+ string revision ;
115
+ int firmware ;
116
+ if ( settings . TryGetValue ( "Revision" , out revision )
117
+ && ! string . IsNullOrEmpty ( revision )
118
+ && int . TryParse ( revision , NumberStyles . HexNumber , CultureInfo . InvariantCulture , out firmware ) )
119
+ return firmware ;
120
+
121
+ return 0 ;
122
+ }
123
+ }
124
+
125
+ /// <summary>
126
+ /// Gets the serial number.
127
+ /// </summary>
128
+ public string SerialNumber
129
+ {
130
+ get
131
+ {
132
+ string serial ;
133
+ if ( settings . TryGetValue ( "Serial" , out serial )
134
+ && ! string . IsNullOrEmpty ( serial ) )
135
+ return serial ;
136
+
137
+ return null ;
138
+ }
139
+ }
140
+
141
+ /// <summary>
142
+ /// Gets a value indicating whether Raspberry Pi board is overclocked.
143
+ /// </summary>
144
+ /// <value>
145
+ /// <c>true</c> if Raspberry Pi is overclocked; otherwise, <c>false</c>.
146
+ /// </value>
147
+ public bool IsOverclocked
148
+ {
149
+ get
150
+ {
151
+ var firmware = Firmware ;
152
+ return ( firmware & 0xFFFF0000 ) != 0 ;
153
+ }
154
+ }
155
+
156
+ /// <summary>
157
+ /// Gets the model.
158
+ /// </summary>
159
+ /// <value>
160
+ /// The model.
161
+ /// </value>
162
+ public Model Model
163
+ {
164
+ get { return model . Value ; }
165
+ }
166
+
167
+ /// <summary>
168
+ /// Gets the connector revision.
169
+ /// </summary>
170
+ /// <value>
171
+ /// The connector revision.
172
+ /// </value>
173
+ /// <remarks>See <see cref="http://raspi.tv/2014/rpi-gpio-quick-reference-updated-for-raspberry-pi-b"/> for more information.</remarks>
174
+ public ConnectorPinout ConnectorPinout
175
+ {
176
+ get { return connectorPinout . Value ; }
177
+ }
178
+
179
+ #endregion
180
+
181
+ #region Private Helpers
182
+
183
+ private static Board LoadBoard ( )
184
+ {
185
+ try
186
+ {
187
+ const string filePath = "/proc/cpuinfo" ;
188
+
189
+ var cpuInfo = File . ReadAllLines ( filePath ) ;
190
+ var settings = new Dictionary < string , string > ( ) ;
191
+ var suffix = string . Empty ;
192
+
193
+ foreach ( var l in cpuInfo )
194
+ {
195
+ var separator = l . IndexOf ( ':' ) ;
196
+
197
+ if ( ! string . IsNullOrWhiteSpace ( l ) && separator > 0 )
198
+ {
199
+ var key = l . Substring ( 0 , separator ) . Trim ( ) ;
200
+ var val = l . Substring ( separator + 1 ) . Trim ( ) ;
201
+ if ( string . Equals ( key , "processor" , StringComparison . InvariantCultureIgnoreCase ) )
202
+ suffix = "." + val ;
203
+
204
+ settings . Add ( key + suffix , val ) ;
205
+ }
206
+ else
207
+ suffix = "" ;
208
+ }
209
+
210
+ return new Board ( settings ) ;
211
+ }
212
+ catch
213
+ {
214
+ return new Board ( new Dictionary < string , string > ( ) ) ;
215
+ }
216
+ }
217
+
218
+ private Model LoadModel ( )
219
+ {
220
+ var firmware = Firmware ;
221
+ switch ( firmware & 0xFFFF )
222
+ {
223
+ case 0x2 :
224
+ case 0x3 :
225
+ return Model . BRev1 ;
226
+
227
+ case 0x4 :
228
+ case 0x5 :
229
+ case 0x6 :
230
+ case 0xd :
231
+ case 0xe :
232
+ case 0xf :
233
+ return Model . BRev2 ;
234
+
235
+ case 0x7 :
236
+ case 0x8 :
237
+ case 0x9 :
238
+ return Model . A ;
239
+
240
+ case 0x10 :
241
+ return Model . BPlus ;
242
+
243
+ case 0x11 :
244
+ return Model . ComputeModule ;
245
+
246
+ case 0x12 :
247
+ return Model . APlus ;
248
+
249
+ case 0x1040 :
250
+ case 0x1041 :
251
+ return Model . B2 ;
252
+
253
+ case 0x0092 :
254
+ case 0x0093 :
255
+ return Model . Zero ;
256
+
257
+ case 0x2082 :
258
+ return Model . B3 ;
259
+ case 0x03111 :
260
+ return Model . Pi4 ;
261
+ default :
262
+ return Model . Unknown ;
263
+ }
264
+ }
265
+
266
+ private ConnectorPinout LoadConnectorPinout ( )
267
+ {
268
+ switch ( Model )
269
+ {
270
+ case Model . BRev1 :
271
+ return ConnectorPinout . Rev1 ;
272
+
273
+ case Model . BRev2 :
274
+ case Model . A :
275
+ return ConnectorPinout . Rev2 ;
276
+
277
+ case Model . BPlus :
278
+ case Model . ComputeModule :
279
+ case Model . APlus :
280
+ case Model . B2 :
281
+ case Model . Zero :
282
+ case Model . B3 :
283
+ case Model . Pi4 :
284
+ return ConnectorPinout . Plus ;
285
+
286
+ default :
287
+ return ConnectorPinout . Unknown ;
288
+ }
289
+ }
290
+
291
+ #endregion
292
+ }
293
+ }
0 commit comments