001package com.pi4j.system;
002
003/*
004 * #%L
005 * **********************************************************************
006 * ORGANIZATION  :  Pi4J
007 * PROJECT       :  Pi4J :: Java Library (Core)
008 * FILENAME      :  SystemInfo.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 - 2013 Pi4J
015 * %%
016 * Licensed under the Apache License, Version 2.0 (the "License");
017 * you may not use this file except in compliance with the License.
018 * You may obtain a copy of the License at
019 * 
020 *      http://www.apache.org/licenses/LICENSE-2.0
021 * 
022 * Unless required by applicable law or agreed to in writing, software
023 * distributed under the License is distributed on an "AS IS" BASIS,
024 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
025 * See the License for the specific language governing permissions and
026 * limitations under the License.
027 * #L%
028 */
029
030
031import java.io.IOException;
032import java.security.AccessController;
033import java.security.PrivilegedAction;
034import java.text.ParseException;
035import java.util.ArrayList;
036import java.util.HashMap;
037import java.util.List;
038import java.util.Map;
039
040import com.pi4j.util.ExecUtil;
041import com.pi4j.util.StringUtil;
042
043public class SystemInfo {
044
045    // private constructor 
046    private SystemInfo() {
047        // forbid object construction 
048    }
049    
050    public enum BoardType {
051        UNKNOWN,
052        ModelA_Rev0,
053        ModelB_Rev1,
054        ModelB_Rev2
055    }    
056    
057    private static Map<String, String> cpuInfo;
058
059    private static String getCpuInfo(String target) throws IOException, InterruptedException {
060        // if the CPU data has not been previously acquired, then acquire it now
061        if (cpuInfo == null) {
062            cpuInfo = new HashMap<String, String>();
063            String result[] = ExecUtil.execute("cat /proc/cpuinfo");
064            if(result != null){
065                for(String line : result) {
066                    String parts[] = line.split(":", 2);
067                    if (parts.length >= 2 && !parts[0].trim().isEmpty() && !parts[1].trim().isEmpty()) {
068                        cpuInfo.put(parts[0].trim(), parts[1].trim());
069                    }
070                }
071            }
072        }
073
074        if (cpuInfo.containsKey(target)) {
075            return cpuInfo.get(target);
076        }
077
078        throw new RuntimeException("Invalid target: " + target);
079    }
080
081    public static String getProcessor() throws IOException, InterruptedException {
082        return getCpuInfo("Processor");
083    }
084
085    public static String getBogoMIPS() throws IOException, InterruptedException {
086        return getCpuInfo("BogoMIPS");
087    }
088
089    public static String[] getCpuFeatures() throws IOException, InterruptedException {
090        return getCpuInfo("Features").split(" ");
091    }
092
093    public static String getCpuImplementer() throws IOException, InterruptedException {
094        return getCpuInfo("CPU implementer");
095    }
096
097    public static String getCpuArchitecture() throws IOException, InterruptedException {
098        return getCpuInfo("CPU architecture");
099    }
100
101    public static String getCpuVariant() throws IOException, InterruptedException {
102        return getCpuInfo("CPU variant");
103    }
104
105    public static String getCpuPart() throws IOException, InterruptedException {
106        return getCpuInfo("CPU part");
107    }
108
109    public static String getCpuRevision() throws IOException, InterruptedException {
110        return getCpuInfo("CPU revision");
111    }
112
113    public static String getHardware() throws IOException, InterruptedException {
114        return getCpuInfo("Hardware");
115    }
116
117    public static String getRevision() throws IOException, InterruptedException {
118        return getCpuInfo("Revision");
119    }
120
121    public static String getSerial() throws IOException, InterruptedException {
122        return getCpuInfo("Serial");
123    }
124
125    public static String getOsName() {
126        return System.getProperty("os.name");
127    }
128
129    public static String getOsVersion() {
130        return System.getProperty("os.version");
131    }
132
133    public static String getOsArch()  {
134        return System.getProperty("os.arch");
135    }
136    
137    public static String getOsFirmwareBuild() throws IOException, InterruptedException {
138        String result[] = ExecUtil.execute("/opt/vc/bin/vcgencmd version");
139        if(result != null){
140            for(String line : result) {
141                if(line.startsWith("version ")){                
142                    return line.substring(8);
143                }
144            }
145        }
146        throw new RuntimeException("Invalid command or response.");
147    }    
148
149    public static String getOsFirmwareDate() throws IOException, InterruptedException, ParseException {
150        String result[] = ExecUtil.execute("/opt/vc/bin/vcgencmd version");
151        if(result != null){
152            for(String line : result) {
153                return line; // return 1st line
154            }
155        }
156        throw new RuntimeException("Invalid command or response.");
157    }    
158    
159    public static String getJavaVendor()  {
160        return System.getProperty("java.vendor");
161    }
162 
163    public static String getJavaVendorUrl() {
164        return System.getProperty("java.vendor.url");
165    }
166 
167    public static String getJavaVersion() {
168        return System.getProperty("java.version");
169    }
170
171    public static String getJavaVirtualMachine() {
172        return System.getProperty("java.vm.name");
173    }
174
175    public static String getJavaRuntime() {
176        return AccessController.doPrivileged(new PrivilegedAction<String>()  {
177            public String run()  {
178                return System.getProperty("java.runtime.name");
179            }
180        });
181    }
182    
183    /*
184     * this method was partially derived from :: (project) jogamp / (developer) sgothel
185     * https://github.com/sgothel/gluegen/blob/master/src/java/jogamp/common/os/PlatformPropsImpl.java#L160
186     * https://github.com/sgothel/gluegen/blob/master/LICENSE.txt
187     */
188    public static boolean isHardFloatAbi() {
189        
190        return AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
191            private final String[] gnueabihf = new String[] { "gnueabihf", "armhf" };
192            public Boolean run() {                    
193                if ( StringUtil.contains(System.getProperty("sun.boot.library.path"), gnueabihf) ||
194                     StringUtil.contains(System.getProperty("java.library.path"), gnueabihf) ||
195                     StringUtil.contains(System.getProperty("java.home"), gnueabihf) || 
196                     getBashVersionInfo().contains("gnueabihf") ||
197                     hasReadElfTag("Tag_ABI_HardFP_use")) {
198                        return true; //
199                }
200                return false;
201            } } );
202    }
203    
204
205    private static List<Long> getMemory() throws IOException, InterruptedException {
206        // Memory information is in the form
207        // root@mypi:/home/pi# free -b
208        //              total       used       free     shared    buffers     cached
209        // Mem:     459771904  144654336  315117568          0   21319680   63713280
210        // -/+ buffers/cache:   59621376  400150528
211        // Swap:    104853504          0  104853504
212        List<Long> values = new ArrayList<>();
213        String result[] = ExecUtil.execute("free -b");
214        if(result != null){
215            for(String line : result) {
216                if(line.startsWith("Mem:")){
217                    String parts[] = line.split(" ");                    
218                    for(String part : parts){
219                        part = part.trim();
220                        if(!part.isEmpty() && !part.equalsIgnoreCase("Mem:")){
221                            values.add(new Long(part));
222                        }
223                    }
224                }
225            }
226        }
227        return values;
228    }
229    
230    public static long getMemoryTotal() throws IOException, InterruptedException {
231        List<Long> values = getMemory();
232        if(!values.isEmpty() && values.size() > 0){
233            return values.get(0); // total memory value is in first position
234        }
235        return -1;
236    }
237
238    public static long getMemoryUsed() throws IOException, InterruptedException {
239        List<Long> values = getMemory();
240        if(!values.isEmpty() && values.size() > 1){
241            return values.get(1); // used memory value is in second position
242        }
243        return -1;
244    }
245
246    public static long getMemoryFree() throws IOException, InterruptedException {
247        List<Long> values = getMemory();
248        if(!values.isEmpty() && values.size() > 2){
249            return values.get(2); // free memory value is in third position
250        }
251        return -1;
252    }
253
254    public static long getMemoryShared() throws IOException, InterruptedException {
255        List<Long> values = getMemory();
256        if(!values.isEmpty() && values.size() > 3){
257            return values.get(3); // shared memory value is in fourth position
258        }
259        return -1;
260    }
261
262    public static long getMemoryBuffers() throws IOException, InterruptedException {
263        List<Long> values = getMemory();
264        if(!values.isEmpty() && values.size() > 4){
265            return values.get(4); // buffers memory value is in fifth position
266        }
267        return -1;
268    }
269
270    public static long getMemoryCached() throws IOException, InterruptedException {
271        List<Long> values = getMemory();
272        if(!values.isEmpty() && values.size() > 5){
273            return values.get(5); // cached memory value is in sixth position
274        }
275        return -1;
276    }
277
278    public static BoardType getBoardType() throws IOException, InterruptedException
279    {
280        // The following info obtained from:
281        // http://www.raspberrypi.org/archives/1929
282        // http://raspberryalphaomega.org.uk/?p=428
283        // http://www.raspberrypi.org/phpBB3/viewtopic.php?p=281039#p281039
284        switch(getRevision())
285        {
286        case "0002":  // Model B Revision 1
287        case "0003":  // Model B Revision 1 + Fuses mod and D14 removed
288            return BoardType.ModelB_Rev1;
289        case "0004":  // Model B Revision 2 256MB (Sony)
290        case "0005":  // Model B Revision 2 256MB (Qisda)
291        case "0006":  // Model B Revision 2 256MB (Egoman)
292            return BoardType.ModelB_Rev2;
293        case "0007":  // Model A 256MB (Egoman)
294        case "0008":  // Model A 256MB (Sony)
295        case "0009":  // Model A 256MB (Qisda)
296            return BoardType.ModelA_Rev0;
297        case "000d":  // Model B Revision 2 512MB (Egoman)
298        case "000e":  // Model B Revision 2 512MB (Sony)
299        case "000f":  // Model B Revision 2 512MB (Qisda)
300            return BoardType.ModelB_Rev2;
301        default:
302            return BoardType.UNKNOWN;
303        }
304    }
305
306    public static float getCpuTemperature() throws IOException, InterruptedException, NumberFormatException {
307        // CPU temperature is in the form
308        // pi@mypi$ /opt/vc/bin/vcgencmd measure_temp
309        // temp=42.3'C
310        // Support for this was added around firmware version 3357xx per info
311        // at http://www.raspberrypi.org/phpBB3/viewtopic.php?p=169909#p169909
312        String result[] = ExecUtil.execute("/opt/vc/bin/vcgencmd measure_temp");
313        if(result != null){
314            for(String line : result) {
315                String parts[] = line.split("[=']", 3);                
316                return Float.parseFloat(parts[1]);
317            }
318        }
319        throw new RuntimeException("Invalid command or response.");
320    }
321
322    private static float getVoltage(String id) throws IOException, InterruptedException, NumberFormatException {
323        String result[] = ExecUtil.execute("/opt/vc/bin/vcgencmd measure_volts " + id);
324        if(result != null){
325            for(String line : result) {
326                String parts[] = line.split("[=V]", 3);                
327                return Float.parseFloat(parts[1]);
328            }
329        }
330        throw new RuntimeException("Invalid command or response.");
331    }
332    
333    public static float getCpuVoltage() throws IOException, InterruptedException, NumberFormatException {
334        return getVoltage("core");
335    }
336
337    public static float getMemoryVoltageSDRam_C() throws IOException, InterruptedException, NumberFormatException {
338        return getVoltage("sdram_c");
339    }
340
341    public static float getMemoryVoltageSDRam_I() throws IOException, InterruptedException, NumberFormatException {
342        return getVoltage("sdram_i");
343    }
344
345    public static float getMemoryVoltageSDRam_P() throws IOException, InterruptedException, NumberFormatException {
346        return getVoltage("sdram_p");
347    }
348    
349
350    private static boolean getCodecEnabled(String codec) throws IOException, InterruptedException {
351        String result[] = ExecUtil.execute("/opt/vc/bin/vcgencmd codec_enabled " + codec);
352        if(result != null){
353            for(String line : result) {
354                String parts[] = line.split("=", 2);                
355                return parts[1].trim().equalsIgnoreCase("enabled");
356            }
357        }
358        throw new RuntimeException("Invalid command or response.");
359    }
360    
361    public static boolean getCodecH264Enabled() throws IOException, InterruptedException {
362        return getCodecEnabled("H264");
363    }
364
365    public static boolean getCodecMPG2Enabled() throws IOException, InterruptedException {
366        return getCodecEnabled("MPG2");
367    }
368
369    public static boolean getCodecWVC1Enabled() throws IOException, InterruptedException {
370        return getCodecEnabled("WVC1");
371    }
372    
373
374    private static long getClockFrequency(String target) throws IOException, InterruptedException {
375        String result[] = ExecUtil.execute("/opt/vc/bin/vcgencmd measure_clock " + target.trim());
376        if(result != null){
377            for(String line : result) {
378                String parts[] = line.split("=", 2);                
379                return Long.parseLong(parts[1].trim());
380            }
381        }
382        throw new RuntimeException("Invalid command or response.");
383    }
384    
385    public static long getClockFrequencyArm() throws IOException, InterruptedException {
386        return getClockFrequency("arm");
387    }
388
389    public static long getClockFrequencyCore() throws IOException, InterruptedException {
390        return getClockFrequency("core");
391    }
392
393    public static long getClockFrequencyH264() throws IOException, InterruptedException {
394        return getClockFrequency("h264");
395    }
396
397    public static long getClockFrequencyISP() throws IOException, InterruptedException {
398        return getClockFrequency("isp");
399    }
400
401    public static long getClockFrequencyV3D() throws IOException, InterruptedException {
402        return getClockFrequency("v3d");
403    }
404
405    public static long getClockFrequencyUART() throws IOException, InterruptedException {
406        return getClockFrequency("uart");
407    }
408
409    public static long getClockFrequencyPWM() throws IOException, InterruptedException {
410        return getClockFrequency("pwm");
411    }
412
413    public static long getClockFrequencyEMMC() throws IOException, InterruptedException {
414        return getClockFrequency("emmc");
415    }
416    
417    public static long getClockFrequencyPixel() throws IOException, InterruptedException {
418        return getClockFrequency("pixel");
419    }
420    
421    public static long getClockFrequencyVEC() throws IOException, InterruptedException {
422        return getClockFrequency("vec");
423    }
424    
425    public static long getClockFrequencyHDMI() throws IOException, InterruptedException {
426        return getClockFrequency("hdmi");
427    }
428
429    public static long getClockFrequencyDPI() throws IOException, InterruptedException {
430        return getClockFrequency("dpi");
431    }
432    
433    
434    /*
435     * this method will to obtain the version info string from the 'bash' program
436     * (this method is used to help determine the HARD-FLOAT / SOFT-FLOAT ABI of the system)
437     */
438    private static String getBashVersionInfo() {
439        String versionInfo = "";
440        try {
441            String result[] = ExecUtil.execute("bash --version");
442            for(String line : result) {
443                if(!line.isEmpty()) { 
444                    versionInfo = line; // return only first output line of version info
445                    break;
446                }
447            }
448        }
449        catch (IOException ioe) { ioe.printStackTrace(); }
450        catch (InterruptedException ie) { ie.printStackTrace(); }
451        return versionInfo;
452    }
453
454    /*
455     * this method will determine if a specified tag exists from the elf info in the '/proc/self/exe' program
456     * (this method is used to help determine the HARD-FLOAT / SOFT-FLOAT ABI of the system)
457     */    
458    private static boolean hasReadElfTag(String tag) {
459        String tagValue = getReadElfTag(tag);
460        if(tagValue != null && !tagValue.isEmpty())
461            return true;
462        return false;
463    }
464    
465    /*
466     * this method will obtain a specified tag value from the elf info in the '/proc/self/exe' program
467     * (this method is used to help determine the HARD-FLOAT / SOFT-FLOAT ABI of the system)
468     */    
469    private static String getReadElfTag(String tag) {
470        String tagValue = null;
471        try {
472            String result[] = ExecUtil.execute("/usr/bin/readelf -A /proc/self/exe");
473            if(result != null){
474                for(String line : result) {
475                    line = line.trim();
476                    if (line.startsWith(tag) && line.contains(":")) {
477                        String lineParts[] = line.split(":", 2);
478                        if(lineParts.length > 1)
479                            tagValue = lineParts[1].trim();
480                        break;
481                    }
482                }
483            }            
484        }
485        catch (IOException ioe) { ioe.printStackTrace(); }
486        catch (InterruptedException ie) { ie.printStackTrace(); }
487        return tagValue;
488    }
489}