Skip to content

Commit 2a99aab

Browse files
committed
decode new revision automatically
1 parent 77e1cd5 commit 2a99aab

File tree

5 files changed

+335
-22
lines changed

5 files changed

+335
-22
lines changed

dist/index.js

Lines changed: 124 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,60 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
55
Object.defineProperty(exports, "__esModule", { value: true });
66
exports.RaspberryPiInfo = exports.revisions = void 0;
77
const fs_1 = __importDefault(require("fs"));
8-
/** @see https://www.raspberrypi.com/documentation/computers/raspberry-pi.html#new-style-revision-codes */
8+
/** Lookup table for model type field (bits 4-11) */
9+
const modelTypes = {
10+
0x00: 'A',
11+
0x01: 'B',
12+
0x02: 'A+',
13+
0x03: 'B+',
14+
0x04: '2B',
15+
0x05: 'Alpha',
16+
0x06: 'CM1',
17+
0x08: '3B',
18+
0x09: 'Zero',
19+
0x0a: 'CM3',
20+
0x0c: 'Zero W',
21+
0x0d: '3B+',
22+
0x0e: '3A+',
23+
0x10: 'CM3+',
24+
0x11: '4B',
25+
0x12: 'Zero 2 W',
26+
0x13: 'Pi 400',
27+
0x14: 'CM4',
28+
0x15: 'CM4S',
29+
0x17: '5',
30+
0x18: 'CM5',
31+
0x19: '500',
32+
0x1a: 'CM5 Lite',
33+
};
34+
/** Lookup table for processor field (bits 12-15) */
35+
const processorTypes = {
36+
0: 'BCM2835',
37+
1: 'BCM2836',
38+
2: 'BCM2837',
39+
3: 'BCM2711',
40+
4: 'BCM2712',
41+
};
42+
/** Lookup table for manufacturer field (bits 16-19) */
43+
const manufacturerTypes = {
44+
0: 'Sony UK',
45+
1: 'Egoman',
46+
2: 'Embest',
47+
3: 'Sony Japan',
48+
4: 'Embest',
49+
5: 'Stadium',
50+
};
51+
/** Lookup table for memory size field (bits 20-22) */
52+
const memoryTypes = {
53+
0: '256MB',
54+
1: '512MB',
55+
2: '1GB',
56+
3: '2GB',
57+
4: '4GB',
58+
5: '8GB',
59+
6: '16GB',
60+
};
61+
/** @see https://www.raspberrypi.com/documentation/computers/raspberry-pi.html#new-style-revision-codes-in-use */
962
exports.revisions = {
1063
'900021': { model: 'A+', ram: '512MB', manufacturer: 'Sony UK' },
1164
'900032': { model: 'B+', ram: '512MB', manufacturer: 'Sony UK' },
@@ -50,7 +103,18 @@ exports.revisions = {
50103
'd03140': { model: 'CM4', ram: '8GB', manufacturer: 'Sony UK' },
51104
'902120': { model: 'Zero 2 W', ram: '512MB', manufacturer: 'Sony UK' },
52105
'c04170': { model: '5', ram: '4GB', manufacturer: 'Sony UK' },
53-
'd04170': { model: '5', ram: '8GB', manufacturer: 'Sony UK' }
106+
'd04170': { model: '5', ram: '8GB', manufacturer: 'Sony UK' },
107+
'b04171': { model: '5', revision: '1.1', ram: '2GB', manufacturer: 'Sony UK' },
108+
'c04171': { model: '5', revision: '1.1', ram: '4GB', manufacturer: 'Sony UK' },
109+
'd04171': { model: '5', revision: '1.1', ram: '8GB', manufacturer: 'Sony UK' },
110+
'e04171': { model: '5', revision: '1.1', ram: '16GB', manufacturer: 'Sony UK' },
111+
'b04180': { model: 'CM5', revision: '1.0', ram: '2GB', manufacturer: 'Sony UK' },
112+
'c04180': { model: 'CM5', revision: '1.0', ram: '4GB', manufacturer: 'Sony UK' },
113+
'd04180': { model: 'CM5', revision: '1.0', ram: '8GB', manufacturer: 'Sony UK' },
114+
'd04190': { model: '500', revision: '1.0', ram: '8GB', manufacturer: 'Sony UK' },
115+
'b041a0': { model: 'CM5 Lite', revision: '1.0', ram: '2GB', manufacturer: 'Sony UK' },
116+
'c041a0': { model: 'CM5 Lite', revision: '1.0', ram: '4GB', manufacturer: 'Sony UK' },
117+
'd041a0': { model: 'CM5 Lite', revision: '1.0', ram: '8GB', manufacturer: 'Sony UK' },
54118
};
55119
class RaspberryPiInfo {
56120
constructor(additionalRevisions = {}, raspberryPiBaseName = 'Raspberry Pi') {
@@ -72,24 +136,74 @@ class RaspberryPiInfo {
72136
if (revisionCode === null) {
73137
return info;
74138
}
139+
// First try the static revision map
75140
const revision = this.revisions[revisionCode];
76-
if (!revision) {
141+
if (revision) {
142+
info.isRaspberry = true;
143+
info.model = revision.model;
144+
info.fullModelName = `${this.raspberryPiBaseName} ${info.model}`;
145+
info.fullModelNameWithRam = `${this.raspberryPiBaseName} ${info.model} - ${revision.ram}`;
146+
info.ram = revision.ram;
147+
info.manufacturer = revision.manufacturer;
148+
info.revisionCode = revisionCode;
149+
return info;
150+
}
151+
// Fallback: decode the revision code using bit fields
152+
const decoded = this.decodeRevisionCode(revisionCode);
153+
if (decoded) {
154+
info.isRaspberry = true;
155+
info.model = decoded.model;
156+
info.fullModelName = `${this.raspberryPiBaseName} ${info.model}`;
157+
info.fullModelNameWithRam = `${this.raspberryPiBaseName} ${info.model} - ${decoded.ram}`;
158+
info.ram = decoded.ram;
159+
info.manufacturer = decoded.manufacturer;
160+
info.revisionCode = revisionCode;
77161
return info;
78162
}
79-
info.isRaspberry = true;
80-
info.model = revision.model;
81-
info.fullModelName = `${this.raspberryPiBaseName} ${info.model}`;
82-
info.fullModelNameWithRam = `${this.raspberryPiBaseName} ${info.model} - ${revision.ram}`;
83-
info.ram = revision.ram;
84-
info.manufacturer = revision.manufacturer;
85-
info.revisionCode = revisionCode;
86163
return info;
87164
}
88165
catch (e) {
89166
// cpuinfo not found, prob not rpi
90167
return info;
91168
}
92169
}
170+
/**
171+
* Decode a new-style revision code by extracting bit fields.
172+
* This handles unknown revision codes that aren't in the static map,
173+
* so new board revisions are automatically supported.
174+
*
175+
* Bit layout (new-style, bit 23 = 1):
176+
* Bits 0-3: Board revision
177+
* Bits 4-11: Model type
178+
* Bits 12-15: Processor
179+
* Bits 16-19: Manufacturer
180+
* Bits 20-22: Memory size
181+
* Bit 23: New flag (must be 1)
182+
*
183+
* @see https://www.raspberrypi.com/documentation/computers/raspberry-pi.html#new-style-revision-codes-in-use
184+
*/
185+
decodeRevisionCode(revisionCode) {
186+
var _a, _b;
187+
const code = parseInt(revisionCode, 16);
188+
if (isNaN(code)) {
189+
return null;
190+
}
191+
// Check bit 23 — must be 1 for new-style revision codes
192+
const isNewStyle = (code >> 23) & 0x1;
193+
if (!isNewStyle) {
194+
return null;
195+
}
196+
const modelType = (code >> 4) & 0xff;
197+
const manufacturerId = (code >> 16) & 0xf;
198+
const memoryId = (code >> 20) & 0x7;
199+
const model = modelTypes[modelType];
200+
if (!model) {
201+
return null;
202+
}
203+
const ram = (_a = memoryTypes[memoryId]) !== null && _a !== void 0 ? _a : 'Unknown';
204+
const manufacturer = (_b = manufacturerTypes[manufacturerId]) !== null && _b !== void 0 ? _b : 'Unknown';
205+
return { model, ram, manufacturer };
206+
}
93207
readRevisionCode() {
94208
const cpuInfo = fs_1.default.readFileSync('/proc/cpuinfo', { encoding: 'utf8' });
95209
const revisionLine = cpuInfo.split('\n')

index.ts

Lines changed: 122 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,63 @@ type RevisionsData = {
1212
[key: string]: PiModel;
1313
}
1414

15+
/** Lookup table for model type field (bits 4-11) */
16+
const modelTypes: { [key: number]: string } = {
17+
0x00: 'A',
18+
0x01: 'B',
19+
0x02: 'A+',
20+
0x03: 'B+',
21+
0x04: '2B',
22+
0x05: 'Alpha',
23+
0x06: 'CM1',
24+
0x08: '3B',
25+
0x09: 'Zero',
26+
0x0a: 'CM3',
27+
0x0c: 'Zero W',
28+
0x0d: '3B+',
29+
0x0e: '3A+',
30+
0x10: 'CM3+',
31+
0x11: '4B',
32+
0x12: 'Zero 2 W',
33+
0x13: 'Pi 400',
34+
0x14: 'CM4',
35+
0x15: 'CM4S',
36+
0x17: '5',
37+
0x18: 'CM5',
38+
0x19: '500',
39+
0x1a: 'CM5 Lite',
40+
};
41+
42+
/** Lookup table for processor field (bits 12-15) */
43+
const processorTypes: { [key: number]: string } = {
44+
0: 'BCM2835',
45+
1: 'BCM2836',
46+
2: 'BCM2837',
47+
3: 'BCM2711',
48+
4: 'BCM2712',
49+
};
50+
51+
/** Lookup table for manufacturer field (bits 16-19) */
52+
const manufacturerTypes: { [key: number]: string } = {
53+
0: 'Sony UK',
54+
1: 'Egoman',
55+
2: 'Embest',
56+
3: 'Sony Japan',
57+
4: 'Embest',
58+
5: 'Stadium',
59+
};
60+
61+
/** Lookup table for memory size field (bits 20-22) */
62+
const memoryTypes: { [key: number]: string } = {
63+
0: '256MB',
64+
1: '512MB',
65+
2: '1GB',
66+
3: '2GB',
67+
4: '4GB',
68+
5: '8GB',
69+
6: '16GB',
70+
};
71+
1572
/** @see https://www.raspberrypi.com/documentation/computers/raspberry-pi.html#new-style-revision-codes-in-use */
1673
export const revisions: RevisionsData = {
1774
'900021': { model: 'A+', ram: '512MB', manufacturer: 'Sony UK' },
@@ -107,25 +164,81 @@ export class RaspberryPiInfo {
107164
return info;
108165
}
109166

167+
// First try the static revision map
110168
const revision = this.revisions[revisionCode];
111-
if ( ! revision) {
169+
if (revision) {
170+
info.isRaspberry = true;
171+
info.model = revision.model;
172+
info.fullModelName = `${this.raspberryPiBaseName} ${info.model}`;
173+
info.fullModelNameWithRam = `${this.raspberryPiBaseName} ${info.model} - ${revision.ram}`;
174+
info.ram = revision.ram;
175+
info.manufacturer = revision.manufacturer;
176+
info.revisionCode = revisionCode;
177+
return info;
178+
}
179+
180+
// Fallback: decode the revision code using bit fields
181+
const decoded = this.decodeRevisionCode(revisionCode);
182+
if (decoded) {
183+
info.isRaspberry = true;
184+
info.model = decoded.model;
185+
info.fullModelName = `${this.raspberryPiBaseName} ${info.model}`;
186+
info.fullModelNameWithRam = `${this.raspberryPiBaseName} ${info.model} - ${decoded.ram}`;
187+
info.ram = decoded.ram;
188+
info.manufacturer = decoded.manufacturer;
189+
info.revisionCode = revisionCode;
112190
return info;
113191
}
114192

115-
info.isRaspberry = true;
116-
info.model = revision.model;
117-
info.fullModelName = `${this.raspberryPiBaseName} ${info.model}`;
118-
info.fullModelNameWithRam = `${this.raspberryPiBaseName} ${info.model} - ${revision.ram}`;
119-
info.ram = revision.ram;
120-
info.manufacturer = revision.manufacturer;
121-
info.revisionCode = revisionCode;
122-
return info;
193+
return info;
123194
} catch (e) {
124195
// cpuinfo not found, prob not rpi
125196
return info;
126197
}
127198
}
128199

200+
/**
201+
* Decode a new-style revision code by extracting bit fields.
202+
* This handles unknown revision codes that aren't in the static map,
203+
* so new board revisions are automatically supported.
204+
*
205+
* Bit layout (new-style, bit 23 = 1):
206+
* Bits 0-3: Board revision
207+
* Bits 4-11: Model type
208+
* Bits 12-15: Processor
209+
* Bits 16-19: Manufacturer
210+
* Bits 20-22: Memory size
211+
* Bit 23: New flag (must be 1)
212+
*
213+
* @see https://www.raspberrypi.com/documentation/computers/raspberry-pi.html#new-style-revision-codes-in-use
214+
*/
215+
private decodeRevisionCode(revisionCode: string): PiModel | null {
216+
const code = parseInt(revisionCode, 16);
217+
if (isNaN(code)) {
218+
return null;
219+
}
220+
221+
// Check bit 23 — must be 1 for new-style revision codes
222+
const isNewStyle = (code >> 23) & 0x1;
223+
if (!isNewStyle) {
224+
return null;
225+
}
226+
227+
const modelType = (code >> 4) & 0xff;
228+
const manufacturerId = (code >> 16) & 0xf;
229+
const memoryId = (code >> 20) & 0x7;
230+
231+
const model = modelTypes[modelType];
232+
if (!model) {
233+
return null;
234+
}
235+
236+
const ram = memoryTypes[memoryId] ?? 'Unknown';
237+
const manufacturer = manufacturerTypes[manufacturerId] ?? 'Unknown';
238+
239+
return { model, ram, manufacturer };
240+
}
241+
129242
private readRevisionCode(): string|null {
130243
const cpuInfo = fs.readFileSync('/proc/cpuinfo', { encoding: 'utf8' });
131244
const revisionLine = cpuInfo.split('\n')

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@alexkratky/rpi-info",
3-
"version": "1.0.5",
3+
"version": "1.1.0",
44
"description": "Detect Raspberry Pi model",
55
"main": "dist/index.js",
66
"types": "dist/index.d.ts",

0 commit comments

Comments
 (0)