001package com.pi4j.system.impl; 002 003/* 004 * #%L 005 * ********************************************************************** 006 * ORGANIZATION : Pi4J 007 * PROJECT : Pi4J :: Java Library (Core) 008 * FILENAME : RaspiSystemInfoProvider.java 009 * 010 * This file is part of the Pi4J project. More information about 011 * this project can be found here: https://www.pi4j.com/ 012 * ********************************************************************** 013 * %% 014 * Copyright (C) 2012 - 2021 Pi4J 015 * %% 016 * This program is free software: you can redistribute it and/or modify 017 * it under the terms of the GNU Lesser General Public License as 018 * published by the Free Software Foundation, either version 3 of the 019 * License, or (at your option) any later version. 020 * 021 * This program is distributed in the hope that it will be useful, 022 * but WITHOUT ANY WARRANTY; without even the implied warranty of 023 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 024 * GNU General Lesser Public License for more details. 025 * 026 * You should have received a copy of the GNU General Lesser Public 027 * License along with this program. If not, see 028 * <http://www.gnu.org/licenses/lgpl-3.0.html>. 029 * #L% 030 */ 031 032import com.pi4j.system.SystemInfo; 033import com.pi4j.system.SystemInfoProvider; 034import com.pi4j.util.ExecUtil; 035 036import java.io.IOException; 037import java.text.ParseException; 038 039/** 040 * Raspberry Pi platform specific implementation of the SystemInfoProvider interface. 041 */ 042public class RaspiSystemInfoProvider extends DefaultSystemInfoProvider implements SystemInfoProvider { 043 044 private long getClockFrequency(String target) throws IOException, InterruptedException { 045 String result[] = ExecUtil.execute("/opt/vc/bin/vcgencmd measure_clock " + target.trim()); 046 if(result != null && result.length > 0){ 047 for(String line : result) { 048 String parts[] = line.split("=", 2); 049 return Long.parseLong(parts[1].trim()); 050 } 051 } 052 throw new UnsupportedOperationException("Invalid command or response."); 053 } 054 055 private boolean getCodecEnabled(String codec) throws IOException, InterruptedException { 056 String result[] = ExecUtil.execute("/opt/vc/bin/vcgencmd codec_enabled " + codec); 057 if(result != null && result.length > 0){ 058 for(String line : result) { 059 String parts[] = line.split("=", 2); 060 return parts[1].trim().equalsIgnoreCase("enabled"); 061 } 062 } 063 throw new RuntimeException("Invalid command or response."); 064 } 065 066 private float getVoltage(String id) throws IOException, InterruptedException, NumberFormatException { 067 String result[] = ExecUtil.execute("/opt/vc/bin/vcgencmd measure_volts " + id); 068 if(result != null && result.length > 0){ 069 for(String line : result) { 070 String parts[] = line.split("[=V]", 3); 071 return Float.parseFloat(parts[1]); 072 } 073 } 074 throw new UnsupportedOperationException("Invalid command or response."); 075 } 076 077 @Override 078 public String getModelName() throws IOException, InterruptedException, UnsupportedOperationException { 079 return getCpuInfo("model name"); 080 } 081 082 @Override 083 public String getOsFirmwareBuild() throws IOException, InterruptedException, UnsupportedOperationException { 084 String result[] = ExecUtil.execute("/opt/vc/bin/vcgencmd version"); 085 if(result != null){ 086 for(String line : result) { 087 if(line.startsWith("version ")){ 088 return line.substring(8); 089 } 090 } 091 } 092 throw new UnsupportedOperationException("Invalid command or response."); 093 } 094 095 @Override 096 public String getOsFirmwareDate() throws IOException, InterruptedException, ParseException, UnsupportedOperationException { 097 String result[] = ExecUtil.execute("/opt/vc/bin/vcgencmd version"); 098 if(result != null && result.length > 0){ 099 for(String line : result) { 100 return line; // return 1st line 101 } 102 } 103 throw new UnsupportedOperationException("Invalid command or response."); 104 } 105 106 // Raspberry Pi Revision :: Model 107 public static final short RPI_MODEL_A = 0; 108 public static final short RPI_MODEL_B = 1; 109 public static final short RPI_MODEL_A_PLUS = 2; 110 public static final short RPI_MODEL_B_PLUS = 3; 111 public static final short RPI_MODEL_2B = 4; 112 public static final short RPI_MODEL_ALPHA = 5; 113 public static final short RPI_MODEL_CM = 6; 114 public static final short RPI_MODEL_UNKNOWN = 7; 115 public static final short RPI_MODEL_3B = 8; 116 public static final short RPI_MODEL_ZERO = 9; 117 public static final short RPI_MODEL_CM3 = 10; 118 public static final short RPI_MODEL_ZERO_W = 12; 119 public static final short RPI_MODEL_3B_PLUS = 13; 120 public static final short RPI_MODEL_3A_PLUS = 14; 121 public static final short RPI_MODEL_CM3_PLUS = 16; 122 public static final short RPI_MODEL_4B = 17; 123 public static final short RPI_MODEL_400 = 19; 124 public static final short RPI_MODEL_CM4 = 20; 125 126 // Raspberry Pi Revision :: Memory 127 public static final short RPI_RAM_256 = 0; 128 public static final short RPI_RAM_512 = 1; 129 public static final short RPI_RAM_1024 = 2; 130 131 // Raspberry Pi Revision :: Manufacture 132 public static final short RPI_MFG_SONY = 0; 133 public static final short RPI_MFG_EGOMAN = 1; 134 public static final short RPI_MFG_EMBEST = 2; 135 public static final short RPI_MFG_UNKNOWN = 3; 136 public static final short RPI_MFG_EMBEST2 = 4; 137 138 // Raspberry Pi Revision :: Processor 139 public static final short RPI_PROC_BCM2835 = 0; 140 public static final short RPI_PROC_BCM2836 = 1; 141 public static final short RPI_PROC_BCM2837 = 2; 142 143 @Override 144 public SystemInfo.BoardType getBoardType() throws IOException, InterruptedException, UnsupportedOperationException { 145 146 //------------------------------------------------------------------------- 147 // SEE: https://github.com/AndrewFromMelbourne/raspberry_pi_revision 148 //------------------------------------------------------------------------- 149 // 150 // The file /proc/cpuinfo contains a line such as:- 151 // 152 // Revision : 0003 153 // 154 // that holds the revision number of the Raspberry Pi. 155 // Known revisions (prior to the Raspberry Pi 2) are: 156 // 157 // +----------+---------+---------+--------+-------------+ 158 // | Revision | Model | PCB Rev | Memory | Manufacture | 159 // +----------+---------+---------+--------+-------------+ 160 // | 0000 | | | | | 161 // | 0001 | | | | | 162 // | 0002 | B | 1 | 256 MB | | 163 // | 0003 | B | 1 | 256 MB | | 164 // | 0004 | B | 2 | 256 MB | Sony | 165 // | 0005 | B | 2 | 256 MB | Qisda | 166 // | 0006 | B | 2 | 256 MB | Egoman | 167 // | 0007 | A | 2 | 256 MB | Egoman | 168 // | 0008 | A | 2 | 256 MB | Sony | 169 // | 0009 | A | 2 | 256 MB | Qisda | 170 // | 000a | | | | | 171 // | 000b | | | | | 172 // | 000c | | | | | 173 // | 000d | B | 2 | 512 MB | Egoman | 174 // | 000e | B | 2 | 512 MB | Sony | 175 // | 000f | B | 2 | 512 MB | Qisda | 176 // | 0010 | B+ | 1 | 512 MB | Sony | 177 // | 0011 | compute | 1 | 512 MB | Sony | 178 // | 0012 | A+ | 1 | 256 MB | Sony | 179 // | 0013 | B+ | 1 | 512 MB | Embest | 180 // | 0014 | compute | 1 | 512 MB | Sony | 181 // | 0015 | A+ | 1 | 256 MB | Sony | 182 // +----------+---------+---------+--------+-------------+ 183 // 184 // If the Raspberry Pi has been over-volted (voiding the warranty) the 185 // revision number will have 100 at the front. e.g. 1000002. 186 // 187 //------------------------------------------------------------------------- 188 // 189 // With the release of the Raspberry Pi 2, there is a new encoding of the 190 // Revision field in /proc/cpuinfo. The bit fields are as follows 191 // 192 // +----+----+----+----+----+----+----+----+ 193 // |FEDC|BA98|7654|3210|FEDC|BA98|7654|3210| 194 // +----+----+----+----+----+----+----+----+ 195 // | | | | | | | |AAAA| 196 // | | | | | |BBBB|BBBB| | 197 // | | | | |CCCC| | | | 198 // | | | |DDDD| | | | | 199 // | | | EEE| | | | | | 200 // | | |F | | | | | | 201 // | | G| | | | | | | 202 // | | H | | | | | | | 203 // +----+----+----+----+----+----+----+----+ 204 // |1098|7654|3210|9876|5432|1098|7654|3210| 205 // +----+----+----+----+----+----+----+----+ 206 // 207 // +---+-------+--------------+--------------------------------------------+ 208 // | # | bits | contains | values | 209 // +---+-------+--------------+--------------------------------------------+ 210 // | A | 00-03 | PCB Revision | (the pcb revision number) | 211 // | B | 04-11 | Model name | A, B, A+, B+, B Pi2, Alpha, Compute Module | 212 // | | | | unknown, B Pi3, Zero, CM3, ZeroW, Pi3+ | 213 // | C | 12-15 | Processor | BCM2835, BCM2836, BCM2837 | 214 // | D | 16-19 | Manufacturer | Sony, Egoman, Embest, unknown, Embest | 215 // | E | 20-22 | Memory size | 256 MB, 512 MB, 1024 MB | 216 // | F | 23-23 | encoded flag | (if set, revision is a bit field) | 217 // | G | 24-24 | waranty bit | (if set, warranty void - Pre Pi2) | 218 // | H | 25-25 | waranty bit | (if set, warranty void - Post Pi2) | 219 // +---+-------+--------------+--------------------------------------------+ 220 // 221 // Also, due to some early issues the warranty bit has been move from bit 222 // 24 to bit 25 of the revision number (i.e. 0x2000000). 223 224 // get revision number from /proc/cpuinfo 225 String revision = getRevision(); 226 227 // determine the board info by deciphering the revision number 228 long irevision = Long.parseLong(revision, 16); 229 long scheme = (irevision >> 23) & 0x1; 230 @SuppressWarnings("unused") 231 long ram = (irevision >> 20) & 0x7; 232 @SuppressWarnings("unused") 233 long manufacturer = (irevision >> 16) & 0xF; 234 @SuppressWarnings("unused") 235 long processor = (irevision >> 12) & 0xF; 236 long model = (irevision >> 4) & 0xFF; 237 long pcbrev = irevision & 0xF; 238 239// System.out.println(" SCHEME : " + scheme); 240// System.out.println(" MEMSIZE : " + ram); 241// System.out.println(" MANUFACTURER : " + manufacturer); 242// System.out.println(" PROCESSOR : " + processor); 243// System.out.println(" MODEL : " + model); 244// System.out.println(" PCB REVISION : " + pcbrev); 245 246 // determine board type based on revision scheme 247 if (scheme > 0) { 248 // a new revision scheme was provided with the release of Raspberry Pi 2 249 // if the scheme bit is enabled, then use the new revision numbering scheme 250 switch((int)model) { 251 case RPI_MODEL_A: return SystemInfo.BoardType.RaspberryPi_A; 252 case RPI_MODEL_A_PLUS: return SystemInfo.BoardType.RaspberryPi_A_Plus; 253 case RPI_MODEL_B_PLUS: return SystemInfo.BoardType.RaspberryPi_B_Plus; 254 case RPI_MODEL_2B: return SystemInfo.BoardType.RaspberryPi_2B; 255 case RPI_MODEL_ALPHA: return SystemInfo.BoardType.RaspberryPi_Alpha; 256 case RPI_MODEL_CM: return SystemInfo.BoardType.RaspberryPi_ComputeModule; 257 case RPI_MODEL_UNKNOWN: return SystemInfo.BoardType.RaspberryPi_Unknown; 258 case RPI_MODEL_3B: return SystemInfo.BoardType.RaspberryPi_3B; 259 case RPI_MODEL_ZERO: return SystemInfo.BoardType.RaspberryPi_Zero; 260 case RPI_MODEL_CM3: return SystemInfo.BoardType.RaspberryPi_ComputeModule3; 261 case RPI_MODEL_ZERO_W: return SystemInfo.BoardType.RaspberryPi_ZeroW; 262 case RPI_MODEL_3B_PLUS: return SystemInfo.BoardType.RaspberryPi_3B_Plus; 263 case RPI_MODEL_3A_PLUS: return SystemInfo.BoardType.RaspberryPi_3A_Plus; 264 case RPI_MODEL_CM3_PLUS: return SystemInfo.BoardType.RaspberryPi_ComputeModule3_Plus; 265 case RPI_MODEL_4B: return SystemInfo.BoardType.RaspberryPi_4B; 266 case RPI_MODEL_400: return SystemInfo.BoardType.RaspberryPi_400; 267 case RPI_MODEL_CM4: return SystemInfo.BoardType.RaspberryPi_ComputeModule4; 268 case RPI_MODEL_B: { 269 // for model B, also take into consideration the revision 270 if(pcbrev <= 1) 271 return SystemInfo.BoardType.RaspberryPi_B_Rev1; 272 else 273 return SystemInfo.BoardType.RaspberryPi_B_Rev2; 274 } 275 } 276 } 277 278 // prior to the Raspberry Pi 2, the original revision scheme 279 // was simply a fixed identifier number 280 else if (scheme == 0) { 281 282 // The following info obtained from: 283 // http://elinux.org/RPi_HardwareHistory 284 // -and- 285 // https://github.com/Pi4J/wiringPi/blob/master/wiringPi/wiringPi.c#L808 286 287 // ------------------------------------------------------------------- 288 // Revision Release Date Model PCB Revision Memory Notes 289 // ------------------------------------------------------------------- 290 // Beta Q1 2012 B (Beta) ?.? 256 MB Beta Board 291 // 0002 Q1 2012 B 1.0 256 MB 292 // 0003 Q3 2012 B 1.0 256 MB (ECN0001) Fuses mod and D14 removed 293 // 0004 Q3 2012 B 2.0 256 MB (Mfg by Sony) 294 // 0005 Q4 2012 B 2.0 256 MB (Mfg by Qisda) 295 // 0006 Q4 2012 B 2.0 256 MB (Mfg by Egoman) 296 // 0007 Q1 2013 A 2.0 256 MB (Mfg by Egoman) 297 // 0008 Q1 2013 A 2.0 256 MB (Mfg by Sony) 298 // 0009 Q1 2013 A 2.0 256 MB (Mfg by Qisda) 299 // 000d Q4 2012 B 2.0 512 MB (Mfg by Egoman) 300 // 000e Q4 2012 B 2.0 512 MB (Mfg by Sony) 301 // 000f Q4 2012 B 2.0 512 MB (Mfg by Qisda) 302 // 0010 Q3 2014 B+ 1.0 512 MB (Mfg by Sony) 303 // 0011 Q2 2014 CM 1.0 512 MB (Mfg by Sony) 304 // 0012 Q4 2014 A+ 1.0 256 MB (Mfg by Sony) 305 // 0013 Q1 2015 B+ 1.2 512 MB ? 306 // 0014 ?? ???? CM 1.0 512 MB (Mfg by Sony) 307 // 0015 ?? ???? A+ 1.1 256 MB (Mfg by Sony)| 308 switch (revision.trim().toLowerCase()) { 309 case "Beta": // Model B Beta 310 case "0002": // Model B Revision 1 311 case "0003": // Model B Revision 1 (Egoman) + Fuses mod and D14 removed 312 return SystemInfo.BoardType.RaspberryPi_B_Rev1; 313 314 case "0004": // Model B Revision 2 256MB (Sony) 315 case "0005": // Model B Revision 2 256MB (Qisda) 316 case "0006": // Model B Revision 2 256MB (Egoman) 317 return SystemInfo.BoardType.RaspberryPi_B_Rev2; 318 319 case "0007": // Model A 256MB (Egoman) 320 case "0008": // Model A 256MB (Sony) 321 case "0009": // Model A 256MB (Qisda) 322 return SystemInfo.BoardType.RaspberryPi_A; 323 324 case "000d": // Model B Revision 2 512MB (Egoman) 325 case "000e": // Model B Revision 2 512MB (Sony) 326 case "000f": // Model B Revision 2 512MB (Egoman) 327 return SystemInfo.BoardType.RaspberryPi_B_Rev2; 328 329 case "0010": // Model B Plus 512MB (Sony) 330 return SystemInfo.BoardType.RaspberryPi_B_Plus; 331 332 case "0011": // Compute Module 512MB (Sony) 333 return SystemInfo.BoardType.RaspberryPi_ComputeModule; 334 335 case "0012": // Model A Plus 512MB (Sony) 336 return SystemInfo.BoardType.RaspberryPi_A_Plus; 337 338 case "0013": // Model B Plus 512MB (Egoman) 339 return SystemInfo.BoardType.RaspberryPi_B_Plus; 340 341 /* UNDOCUMENTED */ 342 case "0014": // Compute Module Rev 1.2, 512MB, (Sony) 343 return SystemInfo.BoardType.RaspberryPi_ComputeModule; 344 345 /* UNDOCUMENTED */ 346 case "0015": // Model A Plus 256MB (Sony) 347 return SystemInfo.BoardType.RaspberryPi_A_Plus; 348 349 // unknown 350 default: 351 return SystemInfo.BoardType.RaspberryPi_Unknown; 352 } 353 } 354 355 // unknown board 356 return SystemInfo.BoardType.UNKNOWN; 357 } 358 359 @Override 360 public float getCpuTemperature() throws IOException, InterruptedException, NumberFormatException, UnsupportedOperationException { 361 // CPU temperature is in the form 362 // pi@mypi$ /opt/vc/bin/vcgencmd measure_temp 363 // temp=42.3'C 364 // Support for this was added around firmware version 3357xx per info 365 // at http://www.raspberrypi.org/phpBB3/viewtopic.php?p=169909#p169909 366 String result[] = ExecUtil.execute("/opt/vc/bin/vcgencmd measure_temp"); 367 if(result != null && result.length > 0){ 368 for(String line : result) { 369 String parts[] = line.split("[=']", 3); 370 return Float.parseFloat(parts[1]); 371 } 372 } 373 throw new UnsupportedOperationException(); 374 } 375 376 @Override 377 public float getCpuVoltage() throws IOException, InterruptedException, NumberFormatException, UnsupportedOperationException { 378 return getVoltage("core"); 379 } 380 381 @Override 382 public float getMemoryVoltageSDRam_C() throws IOException, InterruptedException, NumberFormatException, UnsupportedOperationException { 383 return getVoltage("sdram_c"); 384 } 385 386 @Override 387 public float getMemoryVoltageSDRam_I() throws IOException, InterruptedException, NumberFormatException, UnsupportedOperationException { 388 return getVoltage("sdram_i"); 389 } 390 391 @Override 392 public float getMemoryVoltageSDRam_P() throws IOException, InterruptedException, NumberFormatException, UnsupportedOperationException { 393 return getVoltage("sdram_p"); 394 } 395 396 @Override 397 public boolean getCodecH264Enabled() throws IOException, InterruptedException, UnsupportedOperationException { 398 return getCodecEnabled("H264"); 399 } 400 401 @Override 402 public boolean getCodecMPG2Enabled() throws IOException, InterruptedException, UnsupportedOperationException { 403 return getCodecEnabled("MPG2"); 404 } 405 406 @Override 407 public boolean getCodecWVC1Enabled() throws IOException, InterruptedException, UnsupportedOperationException { 408 return getCodecEnabled("WVC1"); 409 } 410 411 @Override 412 public long getClockFrequencyArm() throws IOException, InterruptedException, UnsupportedOperationException { 413 return getClockFrequency("arm"); 414 } 415 416 @Override 417 public long getClockFrequencyCore() throws IOException, InterruptedException, UnsupportedOperationException { 418 return getClockFrequency("core"); 419 } 420 421 @Override 422 public long getClockFrequencyH264() throws IOException, InterruptedException, UnsupportedOperationException { 423 return getClockFrequency("h264"); 424 } 425 426 @Override 427 public long getClockFrequencyISP() throws IOException, InterruptedException, UnsupportedOperationException { 428 return getClockFrequency("isp"); 429 } 430 431 @Override 432 public long getClockFrequencyV3D() throws IOException, InterruptedException, UnsupportedOperationException { 433 return getClockFrequency("v3d"); 434 } 435 436 @Override 437 public long getClockFrequencyUART() throws IOException, InterruptedException, UnsupportedOperationException { 438 return getClockFrequency("uart"); 439 } 440 441 @Override 442 public long getClockFrequencyPWM() throws IOException, InterruptedException, UnsupportedOperationException { 443 return getClockFrequency("pwm"); 444 } 445 446 @Override 447 public long getClockFrequencyEMMC() throws IOException, InterruptedException, UnsupportedOperationException { 448 return getClockFrequency("emmc"); 449 } 450 451 @Override 452 public long getClockFrequencyPixel() throws IOException, InterruptedException, UnsupportedOperationException { 453 return getClockFrequency("pixel"); 454 } 455 456 @Override 457 public long getClockFrequencyVEC() throws IOException, InterruptedException, UnsupportedOperationException { 458 return getClockFrequency("vec"); 459 } 460 461 @Override 462 public long getClockFrequencyHDMI() throws IOException, InterruptedException, UnsupportedOperationException { 463 return getClockFrequency("hdmi"); 464 } 465 466 @Override 467 public long getClockFrequencyDPI() throws IOException, InterruptedException, UnsupportedOperationException { 468 return getClockFrequency("dpi"); 469 } 470}