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