| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package RPi::SysInfo; |
|
2
|
|
|
|
|
|
|
|
|
3
|
11
|
|
|
11
|
|
401587
|
use strict; |
|
|
11
|
|
|
|
|
20
|
|
|
|
11
|
|
|
|
|
376
|
|
|
4
|
11
|
|
|
11
|
|
91
|
use warnings; |
|
|
11
|
|
|
|
|
21
|
|
|
|
11
|
|
|
|
|
601
|
|
|
5
|
|
|
|
|
|
|
|
|
6
|
11
|
|
|
11
|
|
59
|
use Carp qw(croak); |
|
|
11
|
|
|
|
|
14
|
|
|
|
11
|
|
|
|
|
1184
|
|
|
7
|
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
our $VERSION = '1.02'; |
|
9
|
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
require XSLoader; |
|
11
|
|
|
|
|
|
|
XSLoader::load('RPi::SysInfo', $VERSION); |
|
12
|
|
|
|
|
|
|
|
|
13
|
11
|
|
|
11
|
|
61
|
use Exporter qw(import); |
|
|
11
|
|
|
|
|
31
|
|
|
|
11
|
|
|
|
|
30291
|
|
|
14
|
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
our @EXPORT_OK = qw( |
|
16
|
|
|
|
|
|
|
core_temp |
|
17
|
|
|
|
|
|
|
cpu_percent |
|
18
|
|
|
|
|
|
|
mem_percent |
|
19
|
|
|
|
|
|
|
gpio_info |
|
20
|
|
|
|
|
|
|
raspi_config |
|
21
|
|
|
|
|
|
|
network_info |
|
22
|
|
|
|
|
|
|
file_system |
|
23
|
|
|
|
|
|
|
pi_details |
|
24
|
|
|
|
|
|
|
pi_model |
|
25
|
|
|
|
|
|
|
); |
|
26
|
|
|
|
|
|
|
|
|
27
|
|
|
|
|
|
|
our %EXPORT_TAGS; |
|
28
|
|
|
|
|
|
|
$EXPORT_TAGS{all} = [@EXPORT_OK]; |
|
29
|
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
sub new { |
|
31
|
0
|
|
|
0
|
1
|
0
|
return bless {}, shift; |
|
32
|
|
|
|
|
|
|
} |
|
33
|
|
|
|
|
|
|
sub core_temp { |
|
34
|
19
|
50
|
66
|
19
|
1
|
7825
|
shift if $_[0] && $_[0] =~ /RPi::/; |
|
35
|
|
|
|
|
|
|
|
|
36
|
19
|
|
|
|
|
68
|
my ($degree) = @_; |
|
37
|
|
|
|
|
|
|
|
|
38
|
19
|
|
100
|
|
|
74
|
$degree //= 'c'; |
|
39
|
|
|
|
|
|
|
|
|
40
|
19
|
|
|
|
|
43
|
my $temp = _core_temp_c(); |
|
41
|
|
|
|
|
|
|
|
|
42
|
19
|
100
|
|
|
|
58
|
return '' if ! defined $temp; |
|
43
|
|
|
|
|
|
|
|
|
44
|
18
|
100
|
100
|
|
|
74
|
if ($degree eq 'f' || $degree eq 'F'){ |
|
45
|
9
|
|
|
|
|
75
|
$temp = ($temp * 1.8) + 32; |
|
46
|
|
|
|
|
|
|
} |
|
47
|
|
|
|
|
|
|
|
|
48
|
18
|
|
|
|
|
82
|
chomp $temp; |
|
49
|
18
|
|
|
|
|
123
|
return $temp; |
|
50
|
|
|
|
|
|
|
} |
|
51
|
|
|
|
|
|
|
sub cpu_percent { |
|
52
|
0
|
|
|
0
|
1
|
0
|
return _format(cpuPercent()); |
|
53
|
|
|
|
|
|
|
} |
|
54
|
|
|
|
|
|
|
sub gpio_info { |
|
55
|
11
|
50
|
66
|
11
|
1
|
7039
|
shift if $_[0] && $_[0] =~ /RPi::/; |
|
56
|
|
|
|
|
|
|
|
|
57
|
11
|
|
|
|
|
35
|
my ($pins) = @_; |
|
58
|
|
|
|
|
|
|
|
|
59
|
11
|
100
|
|
|
|
84
|
$pins = ! defined $pins |
|
60
|
|
|
|
|
|
|
? '' |
|
61
|
|
|
|
|
|
|
: join ",", @$pins; |
|
62
|
|
|
|
|
|
|
|
|
63
|
|
|
|
|
|
|
# raspi-gpio was removed from current Raspberry Pi OS in favour of pinctrl, |
|
64
|
|
|
|
|
|
|
# and never existed for the Pi 5 / RP1. Prefer pinctrl, falling back to |
|
65
|
|
|
|
|
|
|
# raspi-gpio on older systems that still ship it. Both accept the same |
|
66
|
|
|
|
|
|
|
# "get [pin[,pin...]]" invocation. |
|
67
|
|
|
|
|
|
|
|
|
68
|
11
|
|
|
|
|
42
|
my $tool = _gpio_tool(); |
|
69
|
|
|
|
|
|
|
|
|
70
|
11
|
100
|
|
|
|
67
|
return '' if ! defined $tool; |
|
71
|
|
|
|
|
|
|
|
|
72
|
10
|
|
|
|
|
37
|
my $info = _run("$tool get $pins"); |
|
73
|
|
|
|
|
|
|
|
|
74
|
10
|
|
|
|
|
1204
|
chomp $info; |
|
75
|
10
|
|
|
|
|
45
|
return $info; |
|
76
|
|
|
|
|
|
|
} |
|
77
|
|
|
|
|
|
|
sub file_system { |
|
78
|
3
|
|
|
3
|
1
|
11
|
my $fs_info = _run('df') . "\n"; |
|
79
|
3
|
|
50
|
|
|
498
|
$fs_info .= _slurp('/proc/swaps') // ''; |
|
80
|
3
|
|
|
|
|
356
|
return $fs_info; |
|
81
|
|
|
|
|
|
|
} |
|
82
|
|
|
|
|
|
|
sub mem_percent { |
|
83
|
0
|
|
|
0
|
1
|
0
|
return _format(memPercent()); |
|
84
|
|
|
|
|
|
|
} |
|
85
|
|
|
|
|
|
|
sub network_info { |
|
86
|
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
# ifconfig (net-tools) is the legacy default, but modern Raspberry Pi OS |
|
88
|
|
|
|
|
|
|
# Lite ships without it, so fall back to `ip addr`, which is always present. |
|
89
|
|
|
|
|
|
|
# Both forms carry inet/inet6 lines. |
|
90
|
|
|
|
|
|
|
|
|
91
|
4
|
|
|
4
|
1
|
8078
|
my $tool = _net_tool(); |
|
92
|
|
|
|
|
|
|
|
|
93
|
4
|
100
|
|
|
|
37
|
return '' if ! defined $tool; |
|
94
|
|
|
|
|
|
|
|
|
95
|
3
|
|
|
|
|
14
|
my $netinfo = _run($tool); |
|
96
|
|
|
|
|
|
|
|
|
97
|
3
|
|
|
|
|
479
|
chomp $netinfo; |
|
98
|
3
|
|
|
|
|
36
|
return $netinfo; |
|
99
|
|
|
|
|
|
|
} |
|
100
|
|
|
|
|
|
|
sub pi_details { |
|
101
|
|
|
|
|
|
|
|
|
102
|
3
|
|
|
3
|
1
|
7465
|
my $details; |
|
103
|
|
|
|
|
|
|
|
|
104
|
3
|
|
|
|
|
16
|
$details = "\n" |
|
105
|
|
|
|
|
|
|
. _run('cat /sys/firmware/devicetree/base/model') |
|
106
|
|
|
|
|
|
|
. "\n\n" |
|
107
|
|
|
|
|
|
|
. _run('cat /etc/os-release | head -4') |
|
108
|
|
|
|
|
|
|
. "\n" |
|
109
|
|
|
|
|
|
|
. _run('uname -a') |
|
110
|
|
|
|
|
|
|
. "\n" |
|
111
|
|
|
|
|
|
|
. _run('cat /proc/cpuinfo | tail -3') |
|
112
|
|
|
|
|
|
|
. "Board : " . pi_model() . "\n" |
|
113
|
|
|
|
|
|
|
. "SoC / RAM : " . _board_summary() . "\n" |
|
114
|
|
|
|
|
|
|
. "Throttled flag : " . _run('vcgencmd get_throttled') |
|
115
|
|
|
|
|
|
|
. "Camera : " . _camera_info() . "\n"; |
|
116
|
|
|
|
|
|
|
|
|
117
|
3
|
|
|
|
|
15
|
return $details; |
|
118
|
|
|
|
|
|
|
} |
|
119
|
|
|
|
|
|
|
sub pi_model { |
|
120
|
9
|
50
|
33
|
9
|
1
|
214740
|
shift if $_[0] && $_[0] =~ /RPi::/; |
|
121
|
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
# Normalized Raspberry Pi marketing name, e.g. "Raspberry Pi 5 Model B Rev |
|
123
|
|
|
|
|
|
|
# 1.1". The devicetree model is authoritative on the Pi 0-5, so prefer it, |
|
124
|
|
|
|
|
|
|
# falling back to a /proc/cpuinfo Revision-code decode, then to 'Unknown'. |
|
125
|
|
|
|
|
|
|
|
|
126
|
9
|
|
|
|
|
48
|
my $model = _slurp('/sys/firmware/devicetree/base/model'); |
|
127
|
|
|
|
|
|
|
|
|
128
|
9
|
100
|
|
|
|
893
|
if (defined $model){ |
|
129
|
7
|
|
|
|
|
33
|
$model =~ s/\0//g; # Devicetree strings are NUL-terminated. |
|
130
|
7
|
|
|
|
|
127
|
$model =~ s/^\s+|\s+$//g; |
|
131
|
7
|
50
|
|
|
|
68
|
return $model if length $model; |
|
132
|
|
|
|
|
|
|
} |
|
133
|
|
|
|
|
|
|
|
|
134
|
2
|
|
|
|
|
14
|
my $info = _decode_revision(_cpuinfo_field('Revision')); |
|
135
|
|
|
|
|
|
|
|
|
136
|
2
|
100
|
|
|
|
17
|
return $info->{name} if defined $info->{name}; |
|
137
|
|
|
|
|
|
|
|
|
138
|
1
|
|
|
|
|
10
|
return 'Unknown'; |
|
139
|
|
|
|
|
|
|
} |
|
140
|
|
|
|
|
|
|
sub raspi_config { |
|
141
|
3
|
|
|
3
|
1
|
12257
|
my $config = _run('vcgencmd get_config int'); |
|
142
|
3
|
|
|
|
|
477
|
$config .= _run('vcgencmd get_config str'); |
|
143
|
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
# config.txt moved from /boot to /boot/firmware on Bookworm and later (the |
|
145
|
|
|
|
|
|
|
# old path now holds only a "this file has moved" stub), so resolve the |
|
146
|
|
|
|
|
|
|
# real location before appending the user's non-comment directives. |
|
147
|
|
|
|
|
|
|
|
|
148
|
3
|
|
|
|
|
362
|
my $config_file = _config_file(); |
|
149
|
|
|
|
|
|
|
|
|
150
|
3
|
50
|
|
|
|
23
|
if (defined $config_file){ |
|
151
|
3
|
|
|
|
|
14
|
$config .= _run("grep -E -v '^\\s*(#|^\$)' $config_file"); |
|
152
|
|
|
|
|
|
|
} |
|
153
|
|
|
|
|
|
|
|
|
154
|
3
|
|
|
|
|
335
|
chomp $config; |
|
155
|
3
|
|
|
|
|
12
|
return $config; |
|
156
|
|
|
|
|
|
|
} |
|
157
|
|
|
|
|
|
|
|
|
158
|
|
|
|
|
|
|
sub _board_summary { |
|
159
|
|
|
|
|
|
|
# Human-readable decode of the SoC, RAM and RP1 presence pulled from the |
|
160
|
|
|
|
|
|
|
# /proc/cpuinfo Revision code. Used to enrich pi_details(). Returns |
|
161
|
|
|
|
|
|
|
# 'unknown' when the revision can't be decoded. |
|
162
|
|
|
|
|
|
|
|
|
163
|
6
|
|
|
6
|
|
25
|
my $info = _decode_revision(_cpuinfo_field('Revision')); |
|
164
|
|
|
|
|
|
|
|
|
165
|
6
|
|
|
|
|
25
|
my @parts; |
|
166
|
|
|
|
|
|
|
|
|
167
|
6
|
50
|
|
|
|
49
|
push @parts, $info->{soc} if defined $info->{soc}; |
|
168
|
6
|
50
|
|
|
|
22
|
push @parts, $info->{mem} if defined $info->{mem}; |
|
169
|
6
|
100
|
|
|
|
18
|
push @parts, 'RP1' if $info->{rp1}; |
|
170
|
6
|
50
|
|
|
|
19
|
push @parts, $info->{manufacturer} if defined $info->{manufacturer}; |
|
171
|
|
|
|
|
|
|
|
|
172
|
6
|
50
|
|
|
|
60
|
return @parts ? join(', ', @parts) : 'unknown'; |
|
173
|
|
|
|
|
|
|
} |
|
174
|
|
|
|
|
|
|
sub _camera_info { |
|
175
|
|
|
|
|
|
|
# Legacy firmware (Pi 0-4 on Bullseye and earlier) answered |
|
176
|
|
|
|
|
|
|
# `vcgencmd get_camera` with "supported=N detected=N". On Bookworm and the |
|
177
|
|
|
|
|
|
|
# Pi 5 that command was removed and camera support moved to libcamera, so |
|
178
|
|
|
|
|
|
|
# fall back to a libcamera probe. Returns a one-line string (no newline). |
|
179
|
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
local $SIG{__WARN__} = sub { |
|
181
|
0
|
|
|
0
|
|
0
|
my $warning = shift; |
|
182
|
0
|
0
|
|
|
|
0
|
warn $warning if $warning !~ /Can't exec "vcgencmd"/; |
|
183
|
7
|
|
|
7
|
|
4184
|
}; |
|
184
|
|
|
|
|
|
|
|
|
185
|
7
|
|
|
|
|
26
|
my $legacy = _run('vcgencmd get_camera'); |
|
186
|
|
|
|
|
|
|
|
|
187
|
7
|
100
|
|
|
|
357
|
if ($legacy =~ /supported=/){ |
|
188
|
2
|
|
|
|
|
18
|
$legacy =~ s/\s+$//; |
|
189
|
2
|
|
|
|
|
19
|
return $legacy; |
|
190
|
|
|
|
|
|
|
} |
|
191
|
|
|
|
|
|
|
|
|
192
|
5
|
|
|
|
|
16
|
my $tool = _camera_tool(); |
|
193
|
|
|
|
|
|
|
|
|
194
|
5
|
100
|
|
|
|
49
|
if (defined $tool){ |
|
195
|
4
|
|
|
|
|
15
|
my $list = _run("$tool --list-cameras 2>/dev/null"); |
|
196
|
|
|
|
|
|
|
|
|
197
|
4
|
100
|
|
|
|
289
|
return 'detected (libcamera)' if $list =~ /Available cameras/i; |
|
198
|
2
|
|
|
|
|
24
|
return 'none detected (libcamera)'; |
|
199
|
|
|
|
|
|
|
} |
|
200
|
|
|
|
|
|
|
|
|
201
|
1
|
|
|
|
|
27
|
return 'not detected'; |
|
202
|
|
|
|
|
|
|
} |
|
203
|
|
|
|
|
|
|
sub _camera_tool { |
|
204
|
|
|
|
|
|
|
# libcamera's listing utility: rpicam-hello on Bookworm and later, renamed |
|
205
|
|
|
|
|
|
|
# from the Bullseye-era libcamera-hello. |
|
206
|
|
|
|
|
|
|
|
|
207
|
3
|
|
|
3
|
|
1591
|
return _first_tool(qw(rpicam-hello libcamera-hello)); |
|
208
|
|
|
|
|
|
|
} |
|
209
|
|
|
|
|
|
|
sub _config_file { |
|
210
|
|
|
|
|
|
|
# Locate the active config.txt. Bookworm and later moved it to |
|
211
|
|
|
|
|
|
|
# /boot/firmware/config.txt; older systems keep it at /boot/config.txt. |
|
212
|
|
|
|
|
|
|
|
|
213
|
0
|
|
|
0
|
|
0
|
for my $file ('/boot/firmware/config.txt', '/boot/config.txt'){ |
|
214
|
0
|
0
|
|
|
|
0
|
return $file if -f $file; |
|
215
|
|
|
|
|
|
|
} |
|
216
|
|
|
|
|
|
|
|
|
217
|
0
|
|
|
|
|
0
|
return undef; |
|
218
|
|
|
|
|
|
|
} |
|
219
|
|
|
|
|
|
|
sub _core_temp_c { |
|
220
|
|
|
|
|
|
|
# Core temperature in Celsius as a number, or undef if unavailable. Prefers |
|
221
|
|
|
|
|
|
|
# vcgencmd (the value the Pi tooling reports), falling back to the kernel |
|
222
|
|
|
|
|
|
|
# thermal zone on systems without vcgencmd. |
|
223
|
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
local $SIG{__WARN__} = sub { |
|
225
|
0
|
|
|
0
|
|
0
|
my $warning = shift; |
|
226
|
0
|
0
|
|
|
|
0
|
warn $warning if $warning !~ /Can't exec "vcgencmd"/; |
|
227
|
22
|
|
|
22
|
|
2833
|
}; |
|
228
|
|
|
|
|
|
|
|
|
229
|
22
|
|
|
|
|
68
|
my $temp = _run('vcgencmd measure_temp'); |
|
230
|
|
|
|
|
|
|
|
|
231
|
22
|
100
|
|
|
|
1584
|
return $1 if $temp =~ /temp=([\d.]+)/; |
|
232
|
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
# /sys/class/thermal/thermal_zone0/temp reports millidegrees Celsius. |
|
234
|
|
|
|
|
|
|
|
|
235
|
4
|
|
|
|
|
7
|
my $milli = _slurp('/sys/class/thermal/thermal_zone0/temp'); |
|
236
|
|
|
|
|
|
|
|
|
237
|
4
|
100
|
66
|
|
|
32
|
return $1 / 1000 if defined $milli && $milli =~ /^(\d+)/; |
|
238
|
|
|
|
|
|
|
|
|
239
|
2
|
|
|
|
|
9
|
return undef; |
|
240
|
|
|
|
|
|
|
} |
|
241
|
|
|
|
|
|
|
sub _cpuinfo_field { |
|
242
|
15
|
|
|
15
|
|
577
|
my ($field) = @_; |
|
243
|
|
|
|
|
|
|
|
|
244
|
15
|
100
|
|
|
|
265
|
croak "_cpuinfo_field() requires a field name\n" if ! defined $field; |
|
245
|
|
|
|
|
|
|
|
|
246
|
14
|
|
|
|
|
54
|
my $cpuinfo = _slurp('/proc/cpuinfo'); |
|
247
|
|
|
|
|
|
|
|
|
248
|
14
|
100
|
|
|
|
770
|
return undef if ! defined $cpuinfo; |
|
249
|
|
|
|
|
|
|
|
|
250
|
12
|
|
|
|
|
97
|
for my $line (split /\n/, $cpuinfo){ |
|
251
|
141
|
100
|
|
|
|
1295
|
return $1 if $line =~ /^\Q$field\E\s*:\s*(.+?)\s*$/; |
|
252
|
|
|
|
|
|
|
} |
|
253
|
|
|
|
|
|
|
|
|
254
|
1
|
|
|
|
|
7
|
return undef; |
|
255
|
|
|
|
|
|
|
} |
|
256
|
|
|
|
|
|
|
sub _decode_revision { |
|
257
|
24
|
|
|
24
|
|
229919
|
my ($rev) = @_; |
|
258
|
|
|
|
|
|
|
|
|
259
|
24
|
100
|
|
|
|
103
|
return {} if ! defined $rev; |
|
260
|
|
|
|
|
|
|
|
|
261
|
22
|
|
|
|
|
145
|
$rev =~ s/^\s+|\s+$//g; |
|
262
|
|
|
|
|
|
|
|
|
263
|
22
|
100
|
|
|
|
141
|
return {} if $rev !~ /^[0-9a-fA-F]+$/; |
|
264
|
|
|
|
|
|
|
|
|
265
|
19
|
|
|
|
|
87
|
$rev = hex($rev); |
|
266
|
|
|
|
|
|
|
|
|
267
|
19
|
|
|
|
|
40
|
my %info; |
|
268
|
|
|
|
|
|
|
|
|
269
|
19
|
100
|
|
|
|
63
|
if ($rev & 0x800000){ |
|
270
|
|
|
|
|
|
|
# New-style revision code (Pi 2 and later, plus late Pi 1 boards). |
|
271
|
17
|
|
|
|
|
42
|
my $type = ($rev >> 4) & 0xff; |
|
272
|
17
|
|
|
|
|
34
|
my $proc = ($rev >> 12) & 0x0f; |
|
273
|
17
|
|
|
|
|
61
|
my $mfr = ($rev >> 16) & 0x0f; |
|
274
|
17
|
|
|
|
|
37
|
my $mem = ($rev >> 20) & 0x07; |
|
275
|
17
|
|
|
|
|
37
|
my $minor = $rev & 0x0f; |
|
276
|
|
|
|
|
|
|
|
|
277
|
17
|
|
|
|
|
418
|
my %types = ( |
|
278
|
|
|
|
|
|
|
0x00 => 'A', 0x01 => 'B', 0x02 => 'A+', |
|
279
|
|
|
|
|
|
|
0x03 => 'B+', 0x04 => '2 Model B', 0x06 => 'Compute Module 1', |
|
280
|
|
|
|
|
|
|
0x08 => '3 Model B', 0x09 => 'Zero', 0x0a => 'Compute Module 3', |
|
281
|
|
|
|
|
|
|
0x0c => 'Zero W', 0x0d => '3 Model B+', 0x0e => '3 Model A+', |
|
282
|
|
|
|
|
|
|
0x10 => 'Compute Module 3+', 0x11 => '4 Model B', |
|
283
|
|
|
|
|
|
|
0x12 => 'Zero 2 W', 0x13 => '400', 0x14 => 'Compute Module 4', |
|
284
|
|
|
|
|
|
|
0x15 => 'Compute Module 4S', 0x17 => '5 Model B', |
|
285
|
|
|
|
|
|
|
0x18 => 'Compute Module 5', 0x19 => '500', |
|
286
|
|
|
|
|
|
|
); |
|
287
|
17
|
|
|
|
|
82
|
my %procs = ( |
|
288
|
|
|
|
|
|
|
0 => 'BCM2835', 1 => 'BCM2836', 2 => 'BCM2837', |
|
289
|
|
|
|
|
|
|
3 => 'BCM2711', 4 => 'BCM2712', |
|
290
|
|
|
|
|
|
|
); |
|
291
|
17
|
|
|
|
|
89
|
my %mfrs = ( |
|
292
|
|
|
|
|
|
|
0 => 'Sony UK', 1 => 'Egoman', 2 => 'Embest', |
|
293
|
|
|
|
|
|
|
3 => 'Sony Japan', 4 => 'Embest', 5 => 'Stadium', |
|
294
|
|
|
|
|
|
|
); |
|
295
|
|
|
|
|
|
|
|
|
296
|
17
|
|
|
|
|
54
|
$info{new_style} = 1; |
|
297
|
17
|
|
|
|
|
46
|
$info{type} = $types{$type}; |
|
298
|
17
|
|
|
|
|
47
|
$info{soc} = $procs{$proc}; |
|
299
|
17
|
|
|
|
|
37
|
$info{manufacturer} = $mfrs{$mfr}; |
|
300
|
17
|
|
|
|
|
56
|
$info{revision} = $minor; |
|
301
|
17
|
|
|
|
|
57
|
$info{mem} = _mem_human(256 << $mem); |
|
302
|
17
|
100
|
|
|
|
75
|
$info{rp1} = $proc == 4 ? 1 : 0; |
|
303
|
17
|
100
|
|
|
|
207
|
$info{name} = defined $types{$type} |
|
304
|
|
|
|
|
|
|
? "Raspberry Pi $types{$type}" |
|
305
|
|
|
|
|
|
|
: undef; |
|
306
|
|
|
|
|
|
|
} |
|
307
|
|
|
|
|
|
|
else { |
|
308
|
|
|
|
|
|
|
# Old-style revision code (original Pi 1 / early boards). A small |
|
309
|
|
|
|
|
|
|
# lookup of the common ones; everything else is left to the devicetree |
|
310
|
|
|
|
|
|
|
# model. All old-style boards are BCM2835, pre-RP1. |
|
311
|
2
|
|
|
|
|
54
|
my %old = ( |
|
312
|
|
|
|
|
|
|
0x0002 => ['B', '256MB'], 0x0003 => ['B', '256MB'], |
|
313
|
|
|
|
|
|
|
0x0004 => ['B', '256MB'], 0x0005 => ['B', '256MB'], |
|
314
|
|
|
|
|
|
|
0x0006 => ['B', '256MB'], 0x0007 => ['A', '256MB'], |
|
315
|
|
|
|
|
|
|
0x0008 => ['A', '256MB'], 0x0009 => ['A', '256MB'], |
|
316
|
|
|
|
|
|
|
0x000d => ['B', '512MB'], 0x000e => ['B', '512MB'], |
|
317
|
|
|
|
|
|
|
0x000f => ['B', '512MB'], 0x0010 => ['B+', '512MB'], |
|
318
|
|
|
|
|
|
|
0x0011 => ['Compute Module 1', '512MB'], |
|
319
|
|
|
|
|
|
|
0x0012 => ['A+', '256MB'], 0x0013 => ['B+', '512MB'], |
|
320
|
|
|
|
|
|
|
0x0014 => ['Compute Module 1', '512MB'], |
|
321
|
|
|
|
|
|
|
0x0015 => ['A+', '256MB'], |
|
322
|
|
|
|
|
|
|
); |
|
323
|
|
|
|
|
|
|
|
|
324
|
2
|
|
|
|
|
7
|
$info{new_style} = 0; |
|
325
|
2
|
|
|
|
|
5
|
$info{soc} = 'BCM2835'; |
|
326
|
2
|
|
|
|
|
4
|
$info{rp1} = 0; |
|
327
|
|
|
|
|
|
|
|
|
328
|
2
|
100
|
|
|
|
15
|
if (my $entry = $old{$rev}){ |
|
329
|
1
|
|
|
|
|
4
|
$info{type} = $entry->[0]; |
|
330
|
1
|
|
|
|
|
3
|
$info{mem} = $entry->[1]; |
|
331
|
1
|
|
|
|
|
10
|
$info{name} = "Raspberry Pi $entry->[0]"; |
|
332
|
|
|
|
|
|
|
} |
|
333
|
|
|
|
|
|
|
} |
|
334
|
|
|
|
|
|
|
|
|
335
|
19
|
|
|
|
|
73
|
return \%info; |
|
336
|
|
|
|
|
|
|
} |
|
337
|
|
|
|
|
|
|
sub _first_tool { |
|
338
|
|
|
|
|
|
|
# Returns the first of the given executable names found on PATH, else undef. |
|
339
|
|
|
|
|
|
|
|
|
340
|
4
|
|
|
4
|
|
2281
|
for my $tool (@_){ |
|
341
|
5
|
|
50
|
|
|
54
|
for my $dir (split /:/, $ENV{PATH} // ''){ |
|
342
|
4
|
100
|
|
|
|
144
|
return $tool if -x "$dir/$tool"; |
|
343
|
|
|
|
|
|
|
} |
|
344
|
|
|
|
|
|
|
} |
|
345
|
|
|
|
|
|
|
|
|
346
|
2
|
|
|
|
|
13
|
return undef; |
|
347
|
|
|
|
|
|
|
} |
|
348
|
|
|
|
|
|
|
sub _format { |
|
349
|
5
|
100
|
|
5
|
|
1073
|
croak "_format() requires a float/double sent in\n" if ! defined $_[0]; |
|
350
|
4
|
|
|
|
|
52
|
return sprintf("%.2f", $_[0]); |
|
351
|
|
|
|
|
|
|
} |
|
352
|
|
|
|
|
|
|
sub _gpio_tool { |
|
353
|
|
|
|
|
|
|
# Locate a GPIO query tool on PATH. pinctrl is the current Raspberry Pi OS |
|
354
|
|
|
|
|
|
|
# utility; raspi-gpio is the legacy one kept here as a fallback. |
|
355
|
|
|
|
|
|
|
|
|
356
|
3
|
|
|
3
|
|
2533
|
return _first_tool(qw(pinctrl raspi-gpio)); |
|
357
|
|
|
|
|
|
|
} |
|
358
|
|
|
|
|
|
|
sub _mem_human { |
|
359
|
25
|
|
|
25
|
|
7471
|
my ($mb) = @_; |
|
360
|
|
|
|
|
|
|
|
|
361
|
25
|
100
|
|
|
|
98
|
return undef if ! defined $mb; |
|
362
|
|
|
|
|
|
|
|
|
363
|
24
|
100
|
|
|
|
292
|
return $mb % 1024 == 0 |
|
364
|
|
|
|
|
|
|
? ($mb / 1024) . 'GB' |
|
365
|
|
|
|
|
|
|
: $mb . 'MB'; |
|
366
|
|
|
|
|
|
|
} |
|
367
|
|
|
|
|
|
|
sub _net_tool { |
|
368
|
|
|
|
|
|
|
# Locate a network-interface query command. ifconfig (net-tools) is the |
|
369
|
|
|
|
|
|
|
# legacy default; fall back to `ip addr` on systems without it. |
|
370
|
|
|
|
|
|
|
|
|
371
|
3
|
100
|
|
3
|
|
515
|
return 'ifconfig' if defined _first_tool('ifconfig'); |
|
372
|
2
|
100
|
|
|
|
21
|
return 'ip addr' if defined _first_tool('ip'); |
|
373
|
|
|
|
|
|
|
|
|
374
|
1
|
|
|
|
|
9
|
return undef; |
|
375
|
|
|
|
|
|
|
} |
|
376
|
|
|
|
|
|
|
sub _run { |
|
377
|
4
|
|
|
4
|
|
1052
|
my ($cmd) = @_; |
|
378
|
|
|
|
|
|
|
|
|
379
|
4
|
100
|
|
|
|
346
|
croak "_run() requires a command string\n" if ! defined $cmd; |
|
380
|
|
|
|
|
|
|
|
|
381
|
3
|
|
|
|
|
19451
|
my $out = `$cmd`; |
|
382
|
|
|
|
|
|
|
|
|
383
|
3
|
50
|
|
|
|
269
|
return defined $out ? $out : ''; |
|
384
|
|
|
|
|
|
|
} |
|
385
|
|
|
|
|
|
|
sub _slurp { |
|
386
|
3
|
|
|
3
|
|
1663
|
my ($file) = @_; |
|
387
|
|
|
|
|
|
|
|
|
388
|
3
|
100
|
|
|
|
145
|
croak "_slurp() requires a file path\n" if ! defined $file; |
|
389
|
|
|
|
|
|
|
|
|
390
|
2
|
100
|
|
|
|
97
|
open my $fh, '<', $file or return undef; |
|
391
|
1
|
|
|
|
|
9
|
local $/; |
|
392
|
1
|
|
|
|
|
14
|
my $data = <$fh>; |
|
393
|
1
|
|
|
|
|
8
|
close $fh; |
|
394
|
|
|
|
|
|
|
|
|
395
|
1
|
|
|
|
|
16
|
return $data; |
|
396
|
|
|
|
|
|
|
} |
|
397
|
|
|
|
|
|
|
|
|
398
|
|
|
|
|
|
|
1; |
|
399
|
|
|
|
|
|
|
__END__ |