Skip to content

Commit

Permalink
darwin: introduce battery info API
Browse files Browse the repository at this point in the history
Refs: #4172
Signed-off-by: Juan José Arboleda <[email protected]>
  • Loading branch information
juanarbol committed Jan 17, 2024
1 parent 3b6a1a1 commit 2106a75
Show file tree
Hide file tree
Showing 7 changed files with 259 additions and 0 deletions.
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@ if(WIN32)
shell32)
list(APPEND uv_sources
src/win/async.c
src/win/battery.c
src/win/core.c
src/win/detect-wakeup.c
src/win/dl.c
Expand Down Expand Up @@ -230,6 +231,7 @@ else()
endif()
list(APPEND uv_sources
src/unix/async.c
src/unix/battery.c
src/unix/core.c
src/unix/dl.c
src/unix/fs.c
Expand Down
22 changes: 22 additions & 0 deletions docs/src/misc.rst
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,20 @@ Data types
Random data request type.

.. c:type:: uv_battery_info_t
Data type for battery information storage.

::

typedef struct uv_battery_info_s {
int is_charging;
uint64_t level;
uint64_t discharge_time_in_secs;
uint64_t charge_time_in_secs;
void *reserved[7];
} uv_battery_info_t;

API
---

Expand Down Expand Up @@ -376,6 +390,14 @@ API
.. versionadded:: 1.44.0
.. c:function:: int uv_battery_info(uv_battery_info_t* battery_info)
Gets information about the current power source and battery status of the
system. The gathered information is stored in the provided `battery_info_t`
structure.
:returns: 0 on success, or an error code < 0 on failure.
.. c:function:: int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count)
Gets information about the CPUs on the system. The `cpu_infos` array will
Expand Down
11 changes: 11 additions & 0 deletions include/uv.h
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,8 @@ typedef struct uv_passwd_s uv_passwd_t;
typedef struct uv_group_s uv_group_t;
typedef struct uv_utsname_s uv_utsname_t;
typedef struct uv_statfs_s uv_statfs_t;
typedef struct uv_battery_info_s uv_battery_info_t;


typedef struct uv_metrics_s uv_metrics_t;

Expand Down Expand Up @@ -1160,6 +1162,14 @@ struct uv_cpu_info_s {
struct uv_cpu_times_s cpu_times;
};

struct uv_battery_info_s {
int is_charging;
uint64_t level;
uint64_t discharge_time_in_secs;
uint64_t charge_time_in_secs;
void *reserved[7];
};

struct uv_interface_address_s {
char* name;
char phys_addr[6];
Expand Down Expand Up @@ -1295,6 +1305,7 @@ enum {
UV_EXTERN int uv_thread_getpriority(uv_thread_t tid, int* priority);
UV_EXTERN int uv_thread_setpriority(uv_thread_t tid, int priority);

UV_EXTERN int uv_battery_info(uv_battery_info_t* battery_info);
UV_EXTERN unsigned int uv_available_parallelism(void);
UV_EXTERN int uv_cpu_info(uv_cpu_info_t** cpu_infos, int* count);
UV_EXTERN void uv_free_cpu_info(uv_cpu_info_t* cpu_infos, int count);
Expand Down
180 changes: 180 additions & 0 deletions src/unix/battery.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
/* Copyright libuv project contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/

#include "uv.h"

#include <dlfcn.h>

#if defined(__APPLE__) || TARGET_OS_IPHONE
#include "darwin-stub.h"
#endif // defined(__APPLE__) || TARGET_OS_IPHONE

int uv_battery_info(uv_battery_info_t* info) {
int err;
#if defined(__APPLE__) || TARGET_OS_IPHONE
CFTypeRef (*pIOPSCopyPowerSourcesInfo)(void);
CFArrayRef (*pIOPSCopyPowerSourcesList)(CFTypeRef);
CFIndex (*pCFArrayGetCount)(CFArrayRef);
CFArrayRef (*pIOPSGetPowerSourceDescription)(CFTypeRef, CFTypeRef);
void (*pCFRelease)(CFTypeRef);
void (*pCFNumberGetValue)(CFNumberRef, int, void *);
void* (*pCFArrayGetValueAtIndex)(CFArrayRef, CFIndex);
void* (*pCFDictionaryGetValue)(CFDictionaryRef, const void*);
int (*pCFBooleanGetValue)(CFBooleanRef);
CFStringRef (*pCFStringCreateWithCString)(CFAllocatorRef,
const char*,
CFStringEncoding);

CFBooleanRef isChargingValue;
CFDictionaryRef powerSource;
CFNumberRef currentCapacity;
CFNumberRef timeRemainingValue;
CFArrayRef sources = NULL;
CFTypeRef blob = NULL;

int holder = 0;
int is_charging = 0;
void* core_foundation_handle;
void* iokit_framekwork_handle;

err = UV_ENOENT;
iokit_framekwork_handle = dlopen("/System/Library/Frameworks/"
"IOKit.framework/IOKit",
RTLD_LAZY | RTLD_LOCAL);

core_foundation_handle = dlopen("/System/Library/Frameworks/"
"CoreFoundation.framework/CoreFoundation",
RTLD_LAZY | RTLD_LOCAL);

if (iokit_framekwork_handle == NULL || core_foundation_handle == NULL)
goto out;

*(void **)(&pCFRelease) = dlsym(core_foundation_handle, "CFRelease");
*(void **)(&pCFStringCreateWithCString) =
dlsym(core_foundation_handle, "CFStringCreateWithCString");
*(void **)(&pCFArrayGetCount) =
dlsym(core_foundation_handle, "CFArrayGetCount");
*(void **)(&pCFArrayGetValueAtIndex) =
dlsym(core_foundation_handle, "CFArrayGetValueAtIndex");
*(void **)(&pCFNumberGetValue) =
dlsym(core_foundation_handle, "CFNumberGetValue");
*(void **)(&pCFBooleanGetValue) =
dlsym(core_foundation_handle, "CFBooleanGetValue");
*(void **)(&pCFDictionaryGetValue) =
dlsym(core_foundation_handle, "CFDictionaryGetValue");
*(void **)(&pIOPSCopyPowerSourcesInfo) =
dlsym(iokit_framekwork_handle, "IOPSCopyPowerSourcesInfo");
*(void **)(&pIOPSCopyPowerSourcesList) =
dlsym(iokit_framekwork_handle, "IOPSCopyPowerSourcesList");
*(void **)(&pIOPSGetPowerSourceDescription) =
dlsym(iokit_framekwork_handle, "IOPSGetPowerSourceDescription");

if (pCFRelease == NULL ||
pCFStringCreateWithCString == NULL ||
pCFArrayGetCount == NULL ||
pCFArrayGetValueAtIndex == NULL ||
pCFNumberGetValue == NULL ||
pCFDictionaryGetValue == NULL ||
pIOPSCopyPowerSourcesInfo == NULL ||
pIOPSCopyPowerSourcesList == NULL ||
pIOPSGetPowerSourceDescription == NULL) {
goto out;
}

#define S(s) pCFStringCreateWithCString(NULL, (s), kCFStringEncodingUTF8)

blob = pIOPSCopyPowerSourcesInfo();
if (blob == NULL)
goto out;

sources = pIOPSCopyPowerSourcesList(blob);
if (sources == NULL)
goto out;

if (pCFArrayGetCount(sources) == 0)
goto out;

powerSource =
pIOPSGetPowerSourceDescription(blob, pCFArrayGetValueAtIndex(sources, 0));
if (powerSource == NULL)
goto out;

err = 0;

// kIOPSCurrentCapacityKey
currentCapacity = pCFDictionaryGetValue(powerSource, S("Current Capacity"));
if (currentCapacity != NULL) {
pCFNumberGetValue(currentCapacity, pkCFNumberIntType, &holder);
info->level = holder;
}


// Retrieve is_charging status
// kIOPSIsChargingKey
isChargingValue = pCFDictionaryGetValue(powerSource, S("Is Charging"));
if (isChargingValue != NULL) {
is_charging = pCFBooleanGetValue(isChargingValue);
info->is_charging = is_charging;
}

// kIOPSTimeToFullChargeKey and kIOPSTimeToEmptyKey
timeRemainingValue =
pCFDictionaryGetValue(powerSource,
is_charging ? S("Time to Full Charge") : S("Time to Empty"));
if (timeRemainingValue != NULL) {
pCFNumberGetValue(timeRemainingValue, pkCFNumberIntType, &holder);
}

// A value of -1 indicates "Still Calculating the Time"
if (holder == -1)
goto out;

holder = holder * 60; // Default unit is minutes, convert to seconds
if (is_charging == 1) {
info->charge_time_in_secs = holder;
info->discharge_time_in_secs = 0;
} else {
info->discharge_time_in_secs = holder;
info->charge_time_in_secs = 0;
}
out:
if (iokit_framekwork_handle != NULL) {
dlclose(iokit_framekwork_handle);
}

if (core_foundation_handle != NULL) {
dlclose(core_foundation_handle);
}

if (blob != NULL) {
pCFRelease(blob);
}

if (sources != NULL) {
pCFRelease(sources);
}

#else
// To be implemented
err = UV_ENOSYS;
#endif // defined(__APPLE__) || TARGET_OS_IPHONE
return err;
}
5 changes: 5 additions & 0 deletions src/unix/darwin-stub.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,11 @@ typedef uint64_t FSEventStreamEventId;
typedef unsigned CFStringEncoding;
typedef void* CFAllocatorRef;
typedef void* CFArrayRef;
typedef void* CFBooleanRef;
typedef void* CFBundleRef;
typedef void* CFDictionaryRef;
typedef void* CFNumberRef;
typedef void* CFNumberType;
typedef void* CFRunLoopRef;
typedef void* CFRunLoopSourceRef;
typedef void* CFStringRef;
Expand Down Expand Up @@ -72,6 +75,8 @@ struct FSEventStreamContext {
static const CFStringEncoding kCFStringEncodingUTF8 = 0x8000100;
static const OSStatus noErr = 0;

static const int pkCFNumberIntType = 9;

static const FSEventStreamEventId kFSEventStreamEventIdSinceNow = -1;

static const int kFSEventStreamCreateFlagNoDefer = 2;
Expand Down
26 changes: 26 additions & 0 deletions src/win/battery.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/* Copyright libuv project contributors. All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include "uv.h"

int uv_battery_info(uv_battery_info_t* info) {
// To be implemented
return UV_ENOSYS;
}
13 changes: 13 additions & 0 deletions test/test-platform-output.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ TEST_IMPL(platform_output) {
uv_passwd_t pwd;
uv_group_t grp;
uv_utsname_t uname;
uv_battery_info_t battery;
unsigned par;
char* const* member;
int count;
Expand Down Expand Up @@ -197,5 +198,17 @@ TEST_IMPL(platform_output) {
printf(" version: %s\n", uname.version);
printf(" machine: %s\n", uname.machine);

err = uv_battery_info(&battery);
printf("uv_battery_info:\n");
printf(" level: %lld\n", battery.level);
printf(" is_charging: %d\n", battery.is_charging);
printf(" discharge_time_in_secs: %lld\n", battery.discharge_time_in_secs);
printf(" charge_time_in_secs: %lld\n", battery.charge_time_in_secs);
#if defined(__APPLE__)
ASSERT_OK(err);
#else
ASSERT_EQ(err, UV_ENOSYS);
#endif

return 0;
}

0 comments on commit 2106a75

Please sign in to comment.