Skip to content

Commit

Permalink
Add an environment call for querying the device's battery (#15387)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
JesseTG authored Aug 12, 2023
1 parent ee75111 commit 954b046
Show file tree
Hide file tree
Showing 3 changed files with 147 additions and 1 deletion.
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down
98 changes: 97 additions & 1 deletion libretro-common/include/libretro.h
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
49 changes: 49 additions & 0 deletions runloop.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down

0 comments on commit 954b046

Please sign in to comment.