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 - 2019 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 121 // Raspberry Pi Revision :: Memory 122 public static final short RPI_RAM_256 = 0; 123 public static final short RPI_RAM_512 = 1; 124 public static final short RPI_RAM_1024 = 2; 125 126 // Raspberry Pi Revision :: Manufacture 127 public static final short RPI_MFG_SONY = 0; 128 public static final short RPI_MFG_EGOMAN = 1; 129 public static final short RPI_MFG_EMBEST = 2; 130 public static final short RPI_MFG_UNKNOWN = 3; 131 public static final short RPI_MFG_EMBEST2 = 4; 132 133 // Raspberry Pi Revision :: Processor 134 public static final short RPI_PROC_BCM2835 = 0; 135 public static final short RPI_PROC_BCM2836 = 1; 136 public static final short RPI_PROC_BCM2837 = 2; 137 138 @Override 139 public SystemInfo.BoardType getBoardType() throws IOException, InterruptedException, UnsupportedOperationException { 140 141 //------------------------------------------------------------------------- 142 // SEE: https://github.com/AndrewFromMelbourne/raspberry_pi_revision 143 //------------------------------------------------------------------------- 144 // 145 // The file /proc/cpuinfo contains a line such as:- 146 // 147 // Revision : 0003 148 // 149 // that holds the revision number of the Raspberry Pi. 150 // Known revisions (prior to the Raspberry Pi 2) are: 151 // 152 // +----------+---------+---------+--------+-------------+ 153 // | Revision | Model | PCB Rev | Memory | Manufacture | 154 // +----------+---------+---------+--------+-------------+ 155 // | 0000 | | | | | 156 // | 0001 | | | | | 157 // | 0002 | B | 1 | 256 MB | | 158 // | 0003 | B | 1 | 256 MB | | 159 // | 0004 | B | 2 | 256 MB | Sony | 160 // | 0005 | B | 2 | 256 MB | Qisda | 161 // | 0006 | B | 2 | 256 MB | Egoman | 162 // | 0007 | A | 2 | 256 MB | Egoman | 163 // | 0008 | A | 2 | 256 MB | Sony | 164 // | 0009 | A | 2 | 256 MB | Qisda | 165 // | 000a | | | | | 166 // | 000b | | | | | 167 // | 000c | | | | | 168 // | 000d | B | 2 | 512 MB | Egoman | 169 // | 000e | B | 2 | 512 MB | Sony | 170 // | 000f | B | 2 | 512 MB | Qisda | 171 // | 0010 | B+ | 1 | 512 MB | Sony | 172 // | 0011 | compute | 1 | 512 MB | Sony | 173 // | 0012 | A+ | 1 | 256 MB | Sony | 174 // | 0013 | B+ | 1 | 512 MB | Embest | 175 // | 0014 | compute | 1 | 512 MB | Sony | 176 // | 0015 | A+ | 1 | 256 MB | Sony | 177 // +----------+---------+---------+--------+-------------+ 178 // 179 // If the Raspberry Pi has been over-volted (voiding the warranty) the 180 // revision number will have 100 at the front. e.g. 1000002. 181 // 182 //------------------------------------------------------------------------- 183 // 184 // With the release of the Raspberry Pi 2, there is a new encoding of the 185 // Revision field in /proc/cpuinfo. The bit fields are as follows 186 // 187 // +----+----+----+----+----+----+----+----+ 188 // |FEDC|BA98|7654|3210|FEDC|BA98|7654|3210| 189 // +----+----+----+----+----+----+----+----+ 190 // | | | | | | | |AAAA| 191 // | | | | | |BBBB|BBBB| | 192 // | | | | |CCCC| | | | 193 // | | | |DDDD| | | | | 194 // | | | EEE| | | | | | 195 // | | |F | | | | | | 196 // | | G| | | | | | | 197 // | | H | | | | | | | 198 // +----+----+----+----+----+----+----+----+ 199 // |1098|7654|3210|9876|5432|1098|7654|3210| 200 // +----+----+----+----+----+----+----+----+ 201 // 202 // +---+-------+--------------+--------------------------------------------+ 203 // | # | bits | contains | values | 204 // +---+-------+--------------+--------------------------------------------+ 205 // | A | 00-03 | PCB Revision | (the pcb revision number) | 206 // | B | 04-11 | Model name | A, B, A+, B+, B Pi2, Alpha, Compute Module | 207 // | | | | unknown, B Pi3, Zero, CM3, ZeroW, Pi3+ | 208 // | C | 12-15 | Processor | BCM2835, BCM2836, BCM2837 | 209 // | D | 16-19 | Manufacturer | Sony, Egoman, Embest, unknown, Embest | 210 // | E | 20-22 | Memory size | 256 MB, 512 MB, 1024 MB | 211 // | F | 23-23 | encoded flag | (if set, revision is a bit field) | 212 // | G | 24-24 | waranty bit | (if set, warranty void - Pre Pi2) | 213 // | H | 25-25 | waranty bit | (if set, warranty void - Post Pi2) | 214 // +---+-------+--------------+--------------------------------------------+ 215 // 216 // Also, due to some early issues the warranty bit has been move from bit 217 // 24 to bit 25 of the revision number (i.e. 0x2000000). 218 219 // get revision number from /proc/cpuinfo 220 String revision = getRevision(); 221 222 // determine the board info by deciphering the revision number 223 long irevision = Long.parseLong(revision, 16); 224 long scheme = (irevision >> 23) & 0x1; 225 @SuppressWarnings("unused") 226 long ram = (irevision >> 20) & 0x7; 227 @SuppressWarnings("unused") 228 long manufacturer = (irevision >> 16) & 0xF; 229 @SuppressWarnings("unused") 230 long processor = (irevision >> 12) & 0xF; 231 long model = (irevision >> 4) & 0xFF; 232 long pcbrev = irevision & 0xF; 233 234// System.out.println(" SCHEME : " + scheme); 235// System.out.println(" MEMSIZE : " + ram); 236// System.out.println(" MANUFACTURER : " + manufacturer); 237// System.out.println(" PROCESSOR : " + processor); 238// System.out.println(" MODEL : " + model); 239// System.out.println(" PCB REVISION : " + pcbrev); 240 241 // determine board type based on revision scheme 242 if (scheme > 0) { 243 // a new revision scheme was provided with the release of Raspberry Pi 2 244 // if the scheme bit is enabled, then use the new revision numbering scheme 245 switch((int)model) { 246 case RPI_MODEL_A: return SystemInfo.BoardType.RaspberryPi_A; 247 case RPI_MODEL_A_PLUS: return SystemInfo.BoardType.RaspberryPi_A_Plus; 248 case RPI_MODEL_B_PLUS: return SystemInfo.BoardType.RaspberryPi_B_Plus; 249 case RPI_MODEL_2B: return SystemInfo.BoardType.RaspberryPi_2B; 250 case RPI_MODEL_ALPHA: return SystemInfo.BoardType.RaspberryPi_Alpha; 251 case RPI_MODEL_CM: return SystemInfo.BoardType.RaspberryPi_ComputeModule; 252 case RPI_MODEL_UNKNOWN: return SystemInfo.BoardType.RaspberryPi_Unknown; 253 case RPI_MODEL_3B: return SystemInfo.BoardType.RaspberryPi_3B; 254 case RPI_MODEL_ZERO: return SystemInfo.BoardType.RaspberryPi_Zero; 255 case RPI_MODEL_CM3: return SystemInfo.BoardType.RaspberryPi_ComputeModule3; 256 case RPI_MODEL_ZERO_W: return SystemInfo.BoardType.RaspberryPi_ZeroW; 257 case RPI_MODEL_3B_PLUS: return SystemInfo.BoardType.RaspberryPi_3B_Plus; 258 case RPI_MODEL_B: { 259 // for model B, also take into consideration the revision 260 if(pcbrev <= 1) 261 return SystemInfo.BoardType.RaspberryPi_B_Rev1; 262 else 263 return SystemInfo.BoardType.RaspberryPi_B_Rev2; 264 } 265 } 266 } 267 268 // prior to the Raspberry Pi 2, the original revision scheme 269 // was simply a fixed identifier number 270 else if (scheme == 0) { 271 272 // The following info obtained from: 273 // http://elinux.org/RPi_HardwareHistory 274 // -and- 275 // https://github.com/Pi4J/wiringPi/blob/master/wiringPi/wiringPi.c#L808 276 277 // ------------------------------------------------------------------- 278 // Revision Release Date Model PCB Revision Memory Notes 279 // ------------------------------------------------------------------- 280 // Beta Q1 2012 B (Beta) ?.? 256 MB Beta Board 281 // 0002 Q1 2012 B 1.0 256 MB 282 // 0003 Q3 2012 B 1.0 256 MB (ECN0001) Fuses mod and D14 removed 283 // 0004 Q3 2012 B 2.0 256 MB (Mfg by Sony) 284 // 0005 Q4 2012 B 2.0 256 MB (Mfg by Qisda) 285 // 0006 Q4 2012 B 2.0 256 MB (Mfg by Egoman) 286 // 0007 Q1 2013 A 2.0 256 MB (Mfg by Egoman) 287 // 0008 Q1 2013 A 2.0 256 MB (Mfg by Sony) 288 // 0009 Q1 2013 A 2.0 256 MB (Mfg by Qisda) 289 // 000d Q4 2012 B 2.0 512 MB (Mfg by Egoman) 290 // 000e Q4 2012 B 2.0 512 MB (Mfg by Sony) 291 // 000f Q4 2012 B 2.0 512 MB (Mfg by Qisda) 292 // 0010 Q3 2014 B+ 1.0 512 MB (Mfg by Sony) 293 // 0011 Q2 2014 CM 1.0 512 MB (Mfg by Sony) 294 // 0012 Q4 2014 A+ 1.0 256 MB (Mfg by Sony) 295 // 0013 Q1 2015 B+ 1.2 512 MB ? 296 // 0014 ?? ???? CM 1.0 512 MB (Mfg by Sony) 297 // 0015 ?? ???? A+ 1.1 256 MB (Mfg by Sony)| 298 switch (revision.trim().toLowerCase()) { 299 case "Beta": // Model B Beta 300 case "0002": // Model B Revision 1 301 case "0003": // Model B Revision 1 (Egoman) + Fuses mod and D14 removed 302 return SystemInfo.BoardType.RaspberryPi_B_Rev1; 303 304 case "0004": // Model B Revision 2 256MB (Sony) 305 case "0005": // Model B Revision 2 256MB (Qisda) 306 case "0006": // Model B Revision 2 256MB (Egoman) 307 return SystemInfo.BoardType.RaspberryPi_B_Rev2; 308 309 case "0007": // Model A 256MB (Egoman) 310 case "0008": // Model A 256MB (Sony) 311 case "0009": // Model A 256MB (Qisda) 312 return SystemInfo.BoardType.RaspberryPi_A; 313 314 case "000d": // Model B Revision 2 512MB (Egoman) 315 case "000e": // Model B Revision 2 512MB (Sony) 316 case "000f": // Model B Revision 2 512MB (Egoman) 317 return SystemInfo.BoardType.RaspberryPi_B_Rev2; 318 319 case "0010": // Model B Plus 512MB (Sony) 320 return SystemInfo.BoardType.RaspberryPi_B_Plus; 321 322 case "0011": // Compute Module 512MB (Sony) 323 return SystemInfo.BoardType.RaspberryPi_ComputeModule; 324 325 case "0012": // Model A Plus 512MB (Sony) 326 return SystemInfo.BoardType.RaspberryPi_A_Plus; 327 328 case "0013": // Model B Plus 512MB (Egoman) 329 return SystemInfo.BoardType.RaspberryPi_B_Plus; 330 331 /* UNDOCUMENTED */ 332 case "0014": // Compute Module Rev 1.2, 512MB, (Sony) 333 return SystemInfo.BoardType.RaspberryPi_ComputeModule; 334 335 /* UNDOCUMENTED */ 336 case "0015": // Model A Plus 256MB (Sony) 337 return SystemInfo.BoardType.RaspberryPi_A_Plus; 338 339 // unknown 340 default: 341 return SystemInfo.BoardType.RaspberryPi_Unknown; 342 } 343 } 344 345 // unknown board 346 return SystemInfo.BoardType.UNKNOWN; 347 } 348 349 @Override 350 public float getCpuTemperature() throws IOException, InterruptedException, NumberFormatException, UnsupportedOperationException { 351 // CPU temperature is in the form 352 // pi@mypi$ /opt/vc/bin/vcgencmd measure_temp 353 // temp=42.3'C 354 // Support for this was added around firmware version 3357xx per info 355 // at http://www.raspberrypi.org/phpBB3/viewtopic.php?p=169909#p169909 356 String result[] = ExecUtil.execute("/opt/vc/bin/vcgencmd measure_temp"); 357 if(result != null && result.length > 0){ 358 for(String line : result) { 359 String parts[] = line.split("[=']", 3); 360 return Float.parseFloat(parts[1]); 361 } 362 } 363 throw new UnsupportedOperationException(); 364 } 365 366 @Override 367 public float getCpuVoltage() throws IOException, InterruptedException, NumberFormatException, UnsupportedOperationException { 368 return getVoltage("core"); 369 } 370 371 @Override 372 public float getMemoryVoltageSDRam_C() throws IOException, InterruptedException, NumberFormatException, UnsupportedOperationException { 373 return getVoltage("sdram_c"); 374 } 375 376 @Override 377 public float getMemoryVoltageSDRam_I() throws IOException, InterruptedException, NumberFormatException, UnsupportedOperationException { 378 return getVoltage("sdram_i"); 379 } 380 381 @Override 382 public float getMemoryVoltageSDRam_P() throws IOException, InterruptedException, NumberFormatException, UnsupportedOperationException { 383 return getVoltage("sdram_p"); 384 } 385 386 @Override 387 public boolean getCodecH264Enabled() throws IOException, InterruptedException, UnsupportedOperationException { 388 return getCodecEnabled("H264"); 389 } 390 391 @Override 392 public boolean getCodecMPG2Enabled() throws IOException, InterruptedException, UnsupportedOperationException { 393 return getCodecEnabled("MPG2"); 394 } 395 396 @Override 397 public boolean getCodecWVC1Enabled() throws IOException, InterruptedException, UnsupportedOperationException { 398 return getCodecEnabled("WVC1"); 399 } 400 401 @Override 402 public long getClockFrequencyArm() throws IOException, InterruptedException, UnsupportedOperationException { 403 return getClockFrequency("arm"); 404 } 405 406 @Override 407 public long getClockFrequencyCore() throws IOException, InterruptedException, UnsupportedOperationException { 408 return getClockFrequency("core"); 409 } 410 411 @Override 412 public long getClockFrequencyH264() throws IOException, InterruptedException, UnsupportedOperationException { 413 return getClockFrequency("h264"); 414 } 415 416 @Override 417 public long getClockFrequencyISP() throws IOException, InterruptedException, UnsupportedOperationException { 418 return getClockFrequency("isp"); 419 } 420 421 @Override 422 public long getClockFrequencyV3D() throws IOException, InterruptedException, UnsupportedOperationException { 423 return getClockFrequency("v3d"); 424 } 425 426 @Override 427 public long getClockFrequencyUART() throws IOException, InterruptedException, UnsupportedOperationException { 428 return getClockFrequency("uart"); 429 } 430 431 @Override 432 public long getClockFrequencyPWM() throws IOException, InterruptedException, UnsupportedOperationException { 433 return getClockFrequency("pwm"); 434 } 435 436 @Override 437 public long getClockFrequencyEMMC() throws IOException, InterruptedException, UnsupportedOperationException { 438 return getClockFrequency("emmc"); 439 } 440 441 @Override 442 public long getClockFrequencyPixel() throws IOException, InterruptedException, UnsupportedOperationException { 443 return getClockFrequency("pixel"); 444 } 445 446 @Override 447 public long getClockFrequencyVEC() throws IOException, InterruptedException, UnsupportedOperationException { 448 return getClockFrequency("vec"); 449 } 450 451 @Override 452 public long getClockFrequencyHDMI() throws IOException, InterruptedException, UnsupportedOperationException { 453 return getClockFrequency("hdmi"); 454 } 455 456 @Override 457 public long getClockFrequencyDPI() throws IOException, InterruptedException, UnsupportedOperationException { 458 return getClockFrequency("dpi"); 459 } 460}