1//
2//  main.c
3//  IOPSCreatePowerSource-simple
4//
5//
6//
7
8#include <CoreFoundation/CoreFoundation.h>
9#include <IOKit/ps/IOPowerSources.h>
10#include <IOKit/ps/IOPowerSourcesPrivate.h>
11#include <IOKit/ps/IOPSKeys.h>
12#include <IOKit/IOCFSerialize.h>
13
14static CFDictionaryRef      copyNextPSDictionary(void);
15static CFStringRef          copyNextPSType(void);
16
17static void iterateCreateSetRelease(int iterations);
18static bool verifyThatAPublishedPowerSourceIsNamed(CFStringRef checkname);
19static void createAndCheckForExistence(CFStringRef useName);
20static void fillAndReleaseAllPowerSourceSlots(int count);
21
22static const int kTryDictionaries = 5;
23static const int kMaxPSCount = 7;
24
25int main(int argc, const char * argv[])
26{
27    for (int i = 0; i< 3; i++)
28    {
29        iterateCreateSetRelease(kTryDictionaries);
30        createAndCheckForExistence(CFSTR("Snaggletooth"));
31        fillAndReleaseAllPowerSourceSlots(kMaxPSCount * 2);
32    }
33}
34
35
36//******************************************************************************
37//******************************************************************************
38//******************************************************************************
39
40static void createAndCheckForExistence(CFStringRef useName)
41{
42    CFDictionaryRef         useDictionary = NULL;
43    CFMutableDictionaryRef  setDictionary = NULL;
44    IOReturn                ret;
45    IOPSPowerSourceID         psid = 0;
46
47    char buf[255];
48    CFStringGetCString(useName, buf, sizeof(buf), kCFStringEncodingUTF8);
49
50
51    useDictionary = copyNextPSDictionary();
52    if (useDictionary) {
53        setDictionary = CFDictionaryCreateMutableCopy(0, 0, useDictionary);
54        if (setDictionary) {
55            CFDictionarySetValue(setDictionary, CFSTR(kIOPSNameKey), useName);
56        }
57        CFRelease(useDictionary);
58    }
59
60    if (!setDictionary) {
61        printf("FAIL: createAndCheckForExistence couldn't create PS dictionary\n");
62        return;
63    }
64
65    ret = IOPSCreatePowerSource(&psid);
66    if (kIOReturnSuccess != ret) {
67        printf("FAIL: createAndCheckForExistence couldn't create PS power source 0x%08x\n", ret);
68        return;
69    }
70
71    ret = IOPSSetPowerSourceDetails(psid, setDictionary);
72    if (kIOReturnSuccess != ret) {
73        printf("[FAIL] Failure return 0x%08x from IOPSSetPowerSourceDetails\n", ret);
74        exit(1);
75    }
76    CFRelease(setDictionary);
77
78    if (verifyThatAPublishedPowerSourceIsNamed(useName))
79    {
80        printf("[PASS] Successfully created, then found, a power source named %s\n", buf);
81    } else {
82        printf("[FAIL] createAndCheckForExistence couldn't locate a power source named %s\n", buf);
83        system("pmset -g ps");
84    }
85
86    IOPSReleasePowerSource(psid);
87
88    // We want to wait a second to let the release power source percolate through powerd
89    // before we check if the Release worked.
90    sleep(1);
91
92    if (!verifyThatAPublishedPowerSourceIsNamed(useName))
93    {
94        printf("[PASS] Successfully RELEASED (it's not published any more), a power source named %s\n", buf);
95    } else {
96        printf("[FAIL] createAndCheckForExistence just released a power source, but it's still published %s\n", buf);
97        system("pmset -g ps");
98    }
99
100    fflush(stdout);
101    return;
102}
103
104static bool verifyThatAPublishedPowerSourceIsNamed(CFStringRef checkname)
105{
106    CFTypeRef blob = NULL;
107    CFArrayRef arr = NULL;
108    CFDictionaryRef details = NULL;
109    bool doMatch = false;
110
111    blob = IOPSCopyPowerSourcesInfo();
112    if (blob) {
113        arr = IOPSCopyPowerSourcesList(blob);
114    }
115
116    if (!arr) {
117        return false;
118    }
119
120    for (int i=0; i<CFArrayGetCount(arr); i++) {
121        details = CFArrayGetValueAtIndex(arr, i);
122        if (!details) {
123            continue;
124        }
125
126        CFStringRef hasName = NULL;
127        hasName = CFDictionaryGetValue(details, CFSTR(kIOPSNameKey));
128        if (hasName && CFEqual(checkname, hasName)) {
129            doMatch = true;
130            break;
131        }
132    }
133
134    if (arr) {
135        CFRelease(arr);
136    }
137    if (blob) {
138        CFRelease(blob);
139    }
140    return doMatch;
141}
142
143
144static void fillAndReleaseAllPowerSourceSlots(int count)
145{
146    IOReturn ret;
147
148    IOPSPowerSourceID *ids = calloc(count, sizeof(IOPSPowerSourceID));
149
150    for (int i=0; i<count; i++)
151    {
152
153        CFStringRef     pstype = copyNextPSType();
154        if (!pstype) {
155            printf("[FAIL] internal error generating testing ps type");
156            exit(1);
157        }
158
159        /*
160         * Create
161         */
162        ret = IOPSCreatePowerSource(&ids[i]);
163
164        printf("Creating %d power sources to exceed limits (%d returns 0x%08x)\n", count, i, ret);
165        if (ret != kIOReturnSuccess
166            && ret != kIOReturnNoSpace)
167        {
168            printf("[FAIL] IOPSCreatePowerSource return value was 0x%08x, should have been Success or NoSpace.\n", ret);
169        }
170        fflush(stdout);
171    }
172
173
174    for (int i=0; i<count; i++)
175    {
176        /*
177         * Release
178         */
179        ret = IOPSReleasePowerSource(ids[i]);
180        if (kIOReturnSuccess != ret) {
181            printf("[FAIL] Failure return 0x%08x from IOPSReleasePowerSource\n", ret);
182        }
183        printf("Release %d power sources to exceed limits (%d returns 0x%08x)\n", count, i, ret);
184    fflush(stdout);
185    }
186
187}
188
189static void iterateCreateSetRelease(int iterations)
190{
191    IOReturn ret;
192
193    IOPSPowerSourceID psid = NULL;
194
195    for (int i=0; i<iterations; i++)
196    {
197        printf("Big iteration %d of %d\n", i, iterations);
198
199        CFStringRef     pstype = copyNextPSType();
200        if (!pstype) {
201            printf("[FAIL] internal error generating testing ps type");
202            exit(1);
203        }
204
205        /*
206         * Create
207         */
208        ret = IOPSCreatePowerSource(&psid);
209        if (kIOReturnSuccess != ret) {
210            printf("[FAIL] Failure return 0x%08x from IOPSCreatePowerSource\n", ret);
211            exit(1);
212        }
213
214        /*
215         * Set
216         */
217        CFDictionaryRef psdict = NULL;
218        psdict = copyNextPSDictionary();
219
220        if (!psdict) {
221            printf("[FAIL] internal error generating testing dictionary");
222            exit(1);
223        }
224        ret = IOPSSetPowerSourceDetails(psid, psdict);
225        if (kIOReturnSuccess != ret) {
226            printf("[FAIL] Failure return 0x%08x from IOPSSetPowerSourceDetails\n", ret);
227            exit(1);
228        }
229        CFRelease(psdict);
230
231        /*
232         * Release
233         */
234        ret = IOPSReleasePowerSource(psid);
235        if (kIOReturnSuccess != ret) {
236            printf("[FAIL] Failure return 0x%08x from IOPSReleasePowerSource\n", ret);
237            exit(1);
238        }
239
240        fflush(stdout);
241
242    }
243
244}
245
246
247//******************************************************************************
248//******************************************************************************
249//******************************************************************************
250
251static CFStringRef  copyNextPSType(void)
252{
253    static int t = 0;
254    CFStringRef _types[] = {
255                            CFSTR(kIOPSInternalBatteryType),
256                            CFSTR(kIOPSUPSType)
257//                            CFSTR("HenryThe8thBogus")
258                            };
259
260    return _types[t++ % (sizeof(_types)/sizeof(_types[0]))];
261}
262
263//******************************************************************************
264enum {
265    kCurrentCapacity = 0,
266    kMaxCapacity,
267    kName,
268    kTimeToEmpty,
269    kTimeToFull,
270    kTimeRemaining,
271    kIsCharged,
272    kIsCharging,
273    kIsPresent,
274    kDesignCap,
275    kVoltage,
276    kIsFinishingCharge,
277    kTransportType
278};
279
280//******************************************************************************
281static CFDictionaryRef copyNextPSDictionary(void)
282{
283    const CFStringRef   keys[] = {
284        CFSTR(kIOPSCurrentCapacityKey),
285        CFSTR(kIOPSMaxCapacityKey),
286        CFSTR(kIOPSNameKey),
287        CFSTR(kIOPSTimeToEmptyKey),
288        CFSTR(kIOPSTimeToFullChargeKey),
289        CFSTR(kIOPSTimeRemainingNotificationKey),
290        CFSTR(kIOPSIsChargedKey),
291        CFSTR(kIOPSIsChargingKey),
292        CFSTR(kIOPSIsPresentKey),
293        CFSTR(kIOPSDesignCapacityKey),
294        CFSTR(kIOPSVoltageKey),
295        CFSTR(kIOPSIsFinishingChargeKey),
296        CFSTR(kIOPSTransportTypeKey)
297    };
298
299    CFTypeRef *values = NULL;
300    int tmpInt = 0;
301
302    int count = sizeof(keys)/sizeof(CFTypeRef);
303    values = calloc(1, sizeof(keys));
304
305    tmpInt = 6000;
306    values[kCurrentCapacity] = CFNumberCreate(0, kCFNumberIntType, &tmpInt);
307    values[kMaxCapacity] = CFNumberCreate(0, kCFNumberIntType, &tmpInt);
308    values[kName] = CFSTR("com.iokit.IOPSCreatePowerSource");
309    tmpInt = 25;
310    values[kTimeToEmpty] = CFNumberCreate(0, kCFNumberIntType, &tmpInt);
311    tmpInt = 0;
312    values[kTimeToFull] = CFNumberCreate(0, kCFNumberIntType, &tmpInt);
313    values[kTimeRemaining] = CFNumberCreate(0, kCFNumberIntType, &tmpInt);
314    values[kIsCharged] = CFRetain(kCFBooleanTrue);
315    values[kIsCharging] = CFRetain(kCFBooleanTrue);
316    values[kIsPresent] = CFRetain(kCFBooleanTrue);
317    tmpInt = 7000;
318    values[kDesignCap] = CFNumberCreate(0, kCFNumberIntType, &tmpInt);
319    tmpInt = 1100;
320    values[kVoltage] = CFNumberCreate(0, kCFNumberIntType, &tmpInt);
321    values[kIsFinishingCharge] = CFRetain(kCFBooleanTrue);
322    values[kTransportType] = CFSTR(kIOPSUSBTransportType);
323
324    return CFDictionaryCreate(0, (const void **)keys, (const void **)values, count,
325                              &kCFTypeDictionaryKeyCallBacks,
326                              &kCFTypeDictionaryValueCallBacks);
327
328}
329