1
2
3
4
5 package oshi.hardware.platform.mac;
6
7 import java.time.LocalDate;
8 import java.util.ArrayList;
9 import java.util.List;
10
11 import com.sun.jna.Pointer;
12 import com.sun.jna.platform.mac.CoreFoundation;
13 import com.sun.jna.platform.mac.CoreFoundation.CFArrayRef;
14 import com.sun.jna.platform.mac.CoreFoundation.CFBooleanRef;
15 import com.sun.jna.platform.mac.CoreFoundation.CFDictionaryRef;
16 import com.sun.jna.platform.mac.CoreFoundation.CFNumberRef;
17 import com.sun.jna.platform.mac.CoreFoundation.CFStringRef;
18 import com.sun.jna.platform.mac.CoreFoundation.CFTypeRef;
19 import com.sun.jna.platform.mac.IOKit;
20 import com.sun.jna.platform.mac.IOKit.IORegistryEntry;
21 import com.sun.jna.platform.mac.IOKitUtil;
22
23 import oshi.annotation.concurrent.ThreadSafe;
24 import oshi.hardware.PowerSource;
25 import oshi.hardware.common.AbstractPowerSource;
26 import oshi.util.Constants;
27 import oshi.util.platform.mac.CFUtil;
28
29
30
31
32 @ThreadSafe
33 public final class MacPowerSource extends AbstractPowerSource {
34
35 private static final CoreFoundation CF = CoreFoundation.INSTANCE;
36 private static final IOKit IO = IOKit.INSTANCE;
37
38 public MacPowerSource(String psName, String psDeviceName, double psRemainingCapacityPercent,
39 double psTimeRemainingEstimated, double psTimeRemainingInstant, double psPowerUsageRate, double psVoltage,
40 double psAmperage, boolean psPowerOnLine, boolean psCharging, boolean psDischarging,
41 CapacityUnits psCapacityUnits, int psCurrentCapacity, int psMaxCapacity, int psDesignCapacity,
42 int psCycleCount, String psChemistry, LocalDate psManufactureDate, String psManufacturer,
43 String psSerialNumber, double psTemperature) {
44 super(psName, psDeviceName, psRemainingCapacityPercent, psTimeRemainingEstimated, psTimeRemainingInstant,
45 psPowerUsageRate, psVoltage, psAmperage, psPowerOnLine, psCharging, psDischarging, psCapacityUnits,
46 psCurrentCapacity, psMaxCapacity, psDesignCapacity, psCycleCount, psChemistry, psManufactureDate,
47 psManufacturer, psSerialNumber, psTemperature);
48 }
49
50
51
52
53
54
55 public static List<PowerSource> getPowerSources() {
56 String psDeviceName = Constants.UNKNOWN;
57 double psTimeRemainingInstant = 0d;
58 double psPowerUsageRate = 0d;
59 double psVoltage = -1d;
60 double psAmperage = 0d;
61 boolean psPowerOnLine = false;
62 boolean psCharging = false;
63 boolean psDischarging = false;
64 CapacityUnits psCapacityUnits = CapacityUnits.RELATIVE;
65 int psCurrentCapacity = 0;
66 int psMaxCapacity = 1;
67 int psDesignCapacity = 1;
68 int psCycleCount = -1;
69 String psChemistry = Constants.UNKNOWN;
70 LocalDate psManufactureDate = null;
71 String psManufacturer = Constants.UNKNOWN;
72 String psSerialNumber = Constants.UNKNOWN;
73 double psTemperature = 0d;
74
75
76
77
78
79
80
81
82
83 IORegistryEntry smartBattery = IOKitUtil.getMatchingService("AppleSmartBattery");
84 if (smartBattery != null) {
85 String s = smartBattery.getStringProperty("DeviceName");
86 if (s != null) {
87 psDeviceName = s;
88 }
89 s = smartBattery.getStringProperty("Manufacturer");
90 if (s != null) {
91 psManufacturer = s;
92 }
93 s = smartBattery.getStringProperty("BatterySerialNumber");
94 if (s != null) {
95 psSerialNumber = s;
96 }
97
98 Integer temp = smartBattery.getIntegerProperty("ManufactureDate");
99 if (temp != null) {
100
101
102
103 int day = temp & 0x1f;
104 int month = (temp >> 5) & 0xf;
105 int year80 = (temp >> 9) & 0x7f;
106 psManufactureDate = LocalDate.of(1980 + year80, month, day);
107 }
108
109 temp = smartBattery.getIntegerProperty("DesignCapacity");
110 if (temp != null) {
111 psDesignCapacity = temp;
112 }
113 temp = smartBattery.getIntegerProperty("MaxCapacity");
114 if (temp != null) {
115 psMaxCapacity = temp;
116 }
117 temp = smartBattery.getIntegerProperty("CurrentCapacity");
118 if (temp != null) {
119 psCurrentCapacity = temp;
120 }
121 psCapacityUnits = CapacityUnits.MAH;
122
123 temp = smartBattery.getIntegerProperty("TimeRemaining");
124 if (temp != null) {
125 psTimeRemainingInstant = temp * 60d;
126 }
127 temp = smartBattery.getIntegerProperty("CycleCount");
128 if (temp != null) {
129 psCycleCount = temp;
130 }
131 temp = smartBattery.getIntegerProperty("Temperature");
132 if (temp != null) {
133 psTemperature = temp / 100d;
134 }
135 temp = smartBattery.getIntegerProperty("Voltage");
136 if (temp != null) {
137 psVoltage = temp / 1000d;
138 }
139 temp = smartBattery.getIntegerProperty("Amperage");
140 if (temp != null) {
141 psAmperage = temp;
142 }
143 psPowerUsageRate = psVoltage * psAmperage;
144
145 Boolean bool = smartBattery.getBooleanProperty("ExternalConnected");
146 if (bool != null) {
147 psPowerOnLine = bool;
148 }
149 bool = smartBattery.getBooleanProperty("IsCharging");
150 if (bool != null) {
151 psCharging = bool;
152 }
153 psDischarging = !psCharging;
154
155 smartBattery.release();
156 }
157
158
159 CFTypeRef powerSourcesInfo = IO.IOPSCopyPowerSourcesInfo();
160 CFArrayRef powerSourcesList = IO.IOPSCopyPowerSourcesList(powerSourcesInfo);
161 int powerSourcesCount = powerSourcesList.getCount();
162
163
164
165 double psTimeRemainingEstimated = IO.IOPSGetTimeRemainingEstimate();
166
167 CFStringRef nameKey = CFStringRef.createCFString("Name");
168 CFStringRef isPresentKey = CFStringRef.createCFString("Is Present");
169 CFStringRef currentCapacityKey = CFStringRef.createCFString("Current Capacity");
170 CFStringRef maxCapacityKey = CFStringRef.createCFString("Max Capacity");
171
172 List<PowerSource> psList = new ArrayList<>(powerSourcesCount);
173 for (int ps = 0; ps < powerSourcesCount; ps++) {
174
175 Pointer pwrSrcPtr = powerSourcesList.getValueAtIndex(ps);
176 CFTypeRef powerSource = new CFTypeRef();
177 powerSource.setPointer(pwrSrcPtr);
178 CFDictionaryRef dictionary = IO.IOPSGetPowerSourceDescription(powerSourcesInfo, powerSource);
179
180
181
182 Pointer result = dictionary.getValue(isPresentKey);
183 if (result != null) {
184 CFBooleanRef isPresentRef = new CFBooleanRef(result);
185 if (0 != CF.CFBooleanGetValue(isPresentRef)) {
186
187 result = dictionary.getValue(nameKey);
188 String psName = CFUtil.cfPointerToString(result);
189
190 double currentCapacity = 0d;
191 if (dictionary.getValueIfPresent(currentCapacityKey, null)) {
192 result = dictionary.getValue(currentCapacityKey);
193 CFNumberRef cap = new CFNumberRef(result);
194 currentCapacity = cap.intValue();
195 }
196 double maxCapacity = 1d;
197 if (dictionary.getValueIfPresent(maxCapacityKey, null)) {
198 result = dictionary.getValue(maxCapacityKey);
199 CFNumberRef cap = new CFNumberRef(result);
200 maxCapacity = cap.intValue();
201 }
202 double psRemainingCapacityPercent = Math.min(1d, currentCapacity / maxCapacity);
203
204 psList.add(new MacPowerSource(psName, psDeviceName, psRemainingCapacityPercent,
205 psTimeRemainingEstimated, psTimeRemainingInstant, psPowerUsageRate, psVoltage, psAmperage,
206 psPowerOnLine, psCharging, psDischarging, psCapacityUnits, psCurrentCapacity, psMaxCapacity,
207 psDesignCapacity, psCycleCount, psChemistry, psManufactureDate, psManufacturer,
208 psSerialNumber, psTemperature));
209 }
210 }
211 }
212 isPresentKey.release();
213 nameKey.release();
214 currentCapacityKey.release();
215 maxCapacityKey.release();
216
217 powerSourcesList.release();
218 powerSourcesInfo.release();
219
220 return psList;
221 }
222 }