From 954b04669c93cdb4a8e124201b374d8d455477c9 Mon Sep 17 00:00:00 2001 From: Jesse Talavera-Greenberg Date: Sat, 12 Aug 2023 19:41:05 -0400 Subject: [PATCH] Add an environment call for querying the device's battery (#15387) * First crack at RETRO_ENVIRONMENT_GET_POWER_STATUS * First crack at RETRO_ENVIRONMENT_GET_POWER_STATUS * Remove a stray comma * Rename some symbols for clarity * Change some references to the old environment call's name * Fix some mixed-up cases in checking the power state - I misunderstood the meaning of these enums * Add a comment * Rename seconds_remaining to seconds * Clarify some comments about the power state * Adjust power state behavior - Don't return 0 seconds; instead, return NO_ESTIMATE - Don't force percent to 100 in the CHARGED state * Adhere to C89 * Mention the environment call in CHANGES.md --- CHANGES.md | 1 + libretro-common/include/libretro.h | 98 +++++++++++++++++++++++++++++- runloop.c | 49 +++++++++++++++ 3 files changed, 147 insertions(+), 1 deletion(-) diff --git a/CHANGES.md b/CHANGES.md index 3d9521c3a8..09e272fbb1 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -89,6 +89,7 @@ being able to do the expected tvOS behavior of "backing out" of the app. - LIBRETRO: Add API to check JIT availability on iOS - LIBRETRO: Allow RETRO_ENVIRONMENT_SET_MEMORY_MAPS also after core startup. Change the comment in libretro.h about the removed limit and handle the environment call during core runtime in RetroArch. - LIBRETRO/MICROPHONE: Add new API for microphone support. +- LIBRETRO: Add new API for querying the device's power state. - LINUX: Input driver fix 8+ joypads. It was reported that controllers beyond 8 worked only partially (analogs yes, but not buttons), and the found fix was also confirmed. - MENU: Start directory browsing from current value - MENU: Fix menu toggle combo hold with same 'enable_hotkey' diff --git a/libretro-common/include/libretro.h b/libretro-common/include/libretro.h index 8d6a1664a4..54c05ca62c 100644 --- a/libretro-common/include/libretro.h +++ b/libretro-common/include/libretro.h @@ -1833,6 +1833,22 @@ enum retro_mod * input devices does not need to take any action on its own. */ +#define RETRO_ENVIRONMENT_GET_DEVICE_POWER (77 | RETRO_ENVIRONMENT_EXPERIMENTAL) + /* struct retro_device_power * -- + * Returns the device's current power state as reported by the frontend. + * This is useful for emulating the battery level in handheld consoles, + * or for reducing power consumption when on battery power. + * + * The return value indicates whether the frontend can provide this information, + * even if the parameter is NULL. + * + * If the frontend does not support this functionality, + * then the provided argument will remain unchanged. + * + * Note that this environment call describes the power state for the entire device, + * not for individual peripherals like controllers. + */ + /* VFS functionality */ /* File paths: @@ -3133,7 +3149,7 @@ typedef void (RETRO_CALLCONV *retro_netpacket_disconnected_t)(uint16_t client_id /** * A callback interface for giving a core the ability to send and receive custom - * network packets during a multiplayer session between two or more instances + * network packets during a multiplayer session between two or more instances * of a libretro frontend. * * @see RETRO_ENVIRONMENT_SET_NETPACKET_INTERFACE @@ -4153,6 +4169,86 @@ struct retro_microphone_interface retro_read_mic_t read_mic; }; +/** + * Describes how a device is being powered. + * @see RETRO_ENVIRONMENT_GET_DEVICE_POWER + */ +enum retro_power_state +{ + /** + * Indicates that the frontend cannot report its power state at this time, + * most likely due to a lack of support. + * + * \c RETRO_ENVIRONMENT_GET_DEVICE_POWER will not return this value; + * instead, the environment callback will return \c false. + */ + RETRO_POWERSTATE_UNKNOWN = 0, + + /** + * Indicates that the device is running on its battery. + * Usually applies to portable devices such as handhelds, laptops, and smartphones. + */ + RETRO_POWERSTATE_DISCHARGING, + + /** + * Indicates that the device's battery is currently charging. + */ + RETRO_POWERSTATE_CHARGING, + + /** + * Indicates that the device is connected to a power source + * and that its battery has finished charging. + */ + RETRO_POWERSTATE_CHARGED, + + /** + * Indicates that the device is connected to a power source + * and that it does not have a battery. + * This usually suggests a desktop computer or a non-portable game console. + */ + RETRO_POWERSTATE_PLUGGED_IN +}; + +/** + * Indicates that an estimate is not available for the battery level or time remaining, + * even if the actual power state is known. + */ +#define RETRO_POWERSTATE_NO_ESTIMATE (-1) + +/** + * Describes the power state of the device running the frontend. + * @see RETRO_ENVIRONMENT_GET_DEVICE_POWER + */ +struct retro_device_power +{ + /** + * The current state of the frontend's power usage. + */ + enum retro_power_state state; + + /** + * A rough estimate of the amount of time remaining (in seconds) + * before the device powers off. + * This value depends on a variety of factors, + * so it is not guaranteed to be accurate. + * + * Will be set to \c RETRO_POWERSTATE_NO_ESTIMATE if \c state does not equal \c RETRO_POWERSTATE_DISCHARGING. + * May still be set to \c RETRO_POWERSTATE_NO_ESTIMATE if the frontend is unable to provide an estimate. + */ + int seconds; + + /** + * The approximate percentage of battery charge, + * ranging from 0 to 100 (inclusive). + * The device may power off before this reaches 0. + * + * The user might have configured their device + * to stop charging before the battery is full, + * so do not assume that this will be 100 in the \c RETRO_POWERSTATE_CHARGED state. + */ + int8_t percent; +}; + /* Callbacks */ /* Environment callback. Gives implementations a way of performing diff --git a/runloop.c b/runloop.c index 4ef9c32c71..35fe07a272 100644 --- a/runloop.c +++ b/runloop.c @@ -3492,6 +3492,55 @@ bool runloop_environment_cb(unsigned cmd, void *data) return false; #endif + case RETRO_ENVIRONMENT_GET_DEVICE_POWER: + { + struct retro_device_power *status = (struct retro_device_power *)data; + frontend_ctx_driver_t *frontend = frontend_get_ptr(); + int seconds = 0; + int percent = 0; + + /* If the frontend driver is unavailable... */ + if (!frontend) + return false; + + /* If the core just wants to query support for this environment call... */ + if (!status) + return frontend->get_powerstate != NULL; + + /* If the frontend driver doesn't support reporting the powerstate... */ + if (frontend->get_powerstate == NULL) + return false; + + switch (frontend->get_powerstate(&seconds, &percent)) + { + case FRONTEND_POWERSTATE_ON_POWER_SOURCE: /* on battery power */ + status->state = RETRO_POWERSTATE_DISCHARGING; + status->percent = (int8_t)percent; + status->seconds = seconds == 0 ? RETRO_POWERSTATE_NO_ESTIMATE : seconds; + break; + case FRONTEND_POWERSTATE_CHARGING /* battery available, charging */: + status->state = RETRO_POWERSTATE_CHARGING; + status->percent = (int8_t)percent; + status->seconds = seconds == 0 ? RETRO_POWERSTATE_NO_ESTIMATE : seconds; + break; + case FRONTEND_POWERSTATE_CHARGED: /* on AC, battery is full */ + status->state = RETRO_POWERSTATE_CHARGED; + status->percent = (int8_t)percent; + status->seconds = RETRO_POWERSTATE_NO_ESTIMATE; + break; + case FRONTEND_POWERSTATE_NO_SOURCE: /* on AC, no battery available */ + status->state = RETRO_POWERSTATE_PLUGGED_IN; + status->percent = RETRO_POWERSTATE_NO_ESTIMATE; + status->seconds = RETRO_POWERSTATE_NO_ESTIMATE; + break; + default: + /* The frontend driver supports power status queries, + * but it still gave us bad information for whatever reason. */ + return false; + break; + } + } + break; default: RARCH_LOG("[Environ]: UNSUPPORTED (#%u).\n", cmd); return false;