View Javadoc
1   /*
2    * Copyright 2016-2022 The OSHI Project Contributors
3    * SPDX-License-Identifier: MIT
4    */
5   package oshi.hardware.platform.unix.solaris;
6   
7   import java.time.LocalDate;
8   import java.util.Arrays;
9   import java.util.List;
10  
11  import com.sun.jna.platform.unix.solaris.LibKstat.Kstat;
12  
13  import oshi.annotation.concurrent.ThreadSafe;
14  import oshi.hardware.PowerSource;
15  import oshi.hardware.common.AbstractPowerSource;
16  import oshi.util.Constants;
17  import oshi.util.platform.unix.solaris.KstatUtil;
18  import oshi.util.platform.unix.solaris.KstatUtil.KstatChain;
19  
20  /**
21   * A Power Source
22   */
23  @ThreadSafe
24  public final class SolarisPowerSource extends AbstractPowerSource {
25  
26      // One-time lookup to see which kstat module to use
27      private static final String[] KSTAT_BATT_MOD = { null, "battery", "acpi_drv" };
28  
29      private static final int KSTAT_BATT_IDX;
30  
31      static {
32          try (KstatChain kc = KstatUtil.openChain()) {
33              if (kc.lookup(KSTAT_BATT_MOD[1], 0, null) != null) {
34                  KSTAT_BATT_IDX = 1;
35              } else if (kc.lookup(KSTAT_BATT_MOD[2], 0, null) != null) {
36                  KSTAT_BATT_IDX = 2;
37              } else {
38                  KSTAT_BATT_IDX = 0;
39              }
40          }
41      }
42  
43      public SolarisPowerSource(String psName, String psDeviceName, double psRemainingCapacityPercent,
44              double psTimeRemainingEstimated, double psTimeRemainingInstant, double psPowerUsageRate, double psVoltage,
45              double psAmperage, boolean psPowerOnLine, boolean psCharging, boolean psDischarging,
46              CapacityUnits psCapacityUnits, int psCurrentCapacity, int psMaxCapacity, int psDesignCapacity,
47              int psCycleCount, String psChemistry, LocalDate psManufactureDate, String psManufacturer,
48              String psSerialNumber, double psTemperature) {
49          super(psName, psDeviceName, psRemainingCapacityPercent, psTimeRemainingEstimated, psTimeRemainingInstant,
50                  psPowerUsageRate, psVoltage, psAmperage, psPowerOnLine, psCharging, psDischarging, psCapacityUnits,
51                  psCurrentCapacity, psMaxCapacity, psDesignCapacity, psCycleCount, psChemistry, psManufactureDate,
52                  psManufacturer, psSerialNumber, psTemperature);
53      }
54  
55      /**
56       * Gets Battery Information
57       *
58       * @return A list of PowerSource objects representing batteries, etc.
59       */
60      public static List<PowerSource> getPowerSources() {
61          return Arrays.asList(getPowerSource("BAT0"));
62      }
63  
64      private static SolarisPowerSource getPowerSource(String name) {
65          String psName = name;
66          String psDeviceName = Constants.UNKNOWN;
67          double psRemainingCapacityPercent = 1d;
68          double psTimeRemainingEstimated = -1d; // -1 = unknown, -2 = unlimited
69          double psTimeRemainingInstant = 0d;
70          double psPowerUsageRate = 0d;
71          double psVoltage = -1d;
72          double psAmperage = 0d;
73          boolean psPowerOnLine = false;
74          boolean psCharging = false;
75          boolean psDischarging = false;
76          CapacityUnits psCapacityUnits = CapacityUnits.RELATIVE;
77          int psCurrentCapacity = 0;
78          int psMaxCapacity = 1;
79          int psDesignCapacity = 1;
80          int psCycleCount = -1;
81          String psChemistry = Constants.UNKNOWN;
82          LocalDate psManufactureDate = null;
83          String psManufacturer = Constants.UNKNOWN;
84          String psSerialNumber = Constants.UNKNOWN;
85          double psTemperature = 0d;
86  
87          // If no kstat info, return empty
88          if (KSTAT_BATT_IDX > 0) {
89              // Get kstat for the battery information
90              try (KstatChain kc = KstatUtil.openChain()) {
91                  Kstat ksp = kc.lookup(KSTAT_BATT_MOD[KSTAT_BATT_IDX], 0, "battery BIF0");
92                  if (ksp != null && kc.read(ksp)) {
93                      // Predicted battery capacity when fully charged.
94                      long energyFull = KstatUtil.dataLookupLong(ksp, "bif_last_cap");
95                      if (energyFull == 0xffffffff || energyFull <= 0) {
96                          energyFull = KstatUtil.dataLookupLong(ksp, "bif_design_cap");
97                      }
98                      if (energyFull != 0xffffffff && energyFull > 0) {
99                          psMaxCapacity = (int) energyFull;
100                     }
101                     long unit = KstatUtil.dataLookupLong(ksp, "bif_unit");
102                     if (unit == 0) {
103                         psCapacityUnits = CapacityUnits.MWH;
104                     } else if (unit == 1) {
105                         psCapacityUnits = CapacityUnits.MAH;
106                     }
107                     psDeviceName = KstatUtil.dataLookupString(ksp, "bif_model");
108                     psSerialNumber = KstatUtil.dataLookupString(ksp, "bif_serial");
109                     psChemistry = KstatUtil.dataLookupString(ksp, "bif_type");
110                     psManufacturer = KstatUtil.dataLookupString(ksp, "bif_oem_info");
111                 }
112 
113                 // Get kstat for the battery state
114                 ksp = kc.lookup(KSTAT_BATT_MOD[KSTAT_BATT_IDX], 0, "battery BST0");
115                 if (ksp != null && kc.read(ksp)) {
116                     // estimated remaining battery capacity
117                     long energyNow = KstatUtil.dataLookupLong(ksp, "bst_rem_cap");
118                     if (energyNow >= 0) {
119                         psCurrentCapacity = (int) energyNow;
120                     }
121                     // power or current supplied at battery terminal
122                     long powerNow = KstatUtil.dataLookupLong(ksp, "bst_rate");
123                     if (powerNow == 0xFFFFFFFF) {
124                         powerNow = 0L;
125                     }
126                     // Battery State:
127                     // bit 0 = discharging
128                     // bit 1 = charging
129                     // bit 2 = critical energy state
130                     boolean isCharging = (KstatUtil.dataLookupLong(ksp, "bst_state") & 0x10) > 0;
131 
132                     if (!isCharging) {
133                         psTimeRemainingEstimated = powerNow > 0 ? 3600d * energyNow / powerNow : -1d;
134                     }
135 
136                     long voltageNow = KstatUtil.dataLookupLong(ksp, "bst_voltage");
137                     if (voltageNow > 0) {
138                         psVoltage = voltageNow / 1000d;
139                         psAmperage = psPowerUsageRate * 1000d / voltageNow;
140                     }
141                 }
142             }
143         }
144 
145         return new SolarisPowerSource(psName, psDeviceName, psRemainingCapacityPercent, psTimeRemainingEstimated,
146                 psTimeRemainingInstant, psPowerUsageRate, psVoltage, psAmperage, psPowerOnLine, psCharging,
147                 psDischarging, psCapacityUnits, psCurrentCapacity, psMaxCapacity, psDesignCapacity, psCycleCount,
148                 psChemistry, psManufactureDate, psManufacturer, psSerialNumber, psTemperature);
149     }
150 }