Commit 513dbb54 authored by spiiroin's avatar spiiroin

[battery-udev] Expose battery charging state. JB#44852

For example CSD tests need more detailed information about battery
charging state.

Track udev battery status, expose it as mce battery state on D-Bus.

Required D-Bus constants are included in mce-dev >= 1.28.0.
Signed-off-by: spiiroin's avatarSimo Piiroinen <simo.piiroinen@jollamobile.com>
parent b32e355a
......@@ -116,6 +116,7 @@ static const char *datapipe_hook_tklock_request_value (gconstpointer data);
static const char *datapipe_hook_charger_state_value (gconstpointer data);
static const char *datapipe_hook_charger_type_value (gconstpointer data);
static const char *datapipe_hook_battery_status_value (gconstpointer data);
static const char *datapipe_hook_battery_state_value (gconstpointer data);
static const char *datapipe_hook_camera_button_state_value(gconstpointer data);
static const char *datapipe_hook_audio_route_value (gconstpointer data);
static const char *datapipe_hook_usb_cable_state_value (gconstpointer data);
......@@ -249,6 +250,13 @@ const char *tklock_status_repr(int status);
const char *battery_status_repr (battery_status_t state);
const char *battery_status_to_dbus(battery_status_t state);
/* ------------------------------------------------------------------------- *
* BATTERY_STATE
* ------------------------------------------------------------------------- */
const char *battery_state_repr (battery_state_t state);
const char *battery_state_to_dbus(battery_state_t state);
/* ------------------------------------------------------------------------- *
* ALARM_STATE
* ------------------------------------------------------------------------- */
......@@ -506,6 +514,14 @@ datapipe_hook_battery_status_value(gconstpointer data)
}
#define datapipe_hook_battery_status_change 0
static const char *
datapipe_hook_battery_state_value(gconstpointer data)
{
battery_state_t value = GPOINTER_TO_INT(data);
return battery_state_repr(value);
}
#define datapipe_hook_battery_state_change 0
static const char *
datapipe_hook_camera_button_state_value(gconstpointer data)
{
......@@ -724,6 +740,9 @@ datapipe_t charger_state_pipe = DATAPIPE_INIT(charger_state, c
/** Battery status; read only */
datapipe_t battery_status_pipe = DATAPIPE_INIT(battery_status, battery_status, BATTERY_STATUS_UNDEF, 0, DATAPIPE_FILTERING_DENIED, DATAPIPE_CACHE_DEFAULT);
/** Battery state; read only */
datapipe_t battery_state_pipe = DATAPIPE_INIT(battery_state, battery_state, BATTERY_STATE_UNKNOWN, 0, DATAPIPE_FILTERING_DENIED, DATAPIPE_CACHE_DEFAULT);
/** Battery charge level; read only */
datapipe_t battery_level_pipe = DATAPIPE_INIT(battery_level, int, BATTERY_LEVEL_INITIAL, 0, DATAPIPE_FILTERING_DENIED, DATAPIPE_CACHE_DEFAULT);
......@@ -1303,6 +1322,7 @@ void mce_datapipe_quit(void)
datapipe_free(&topmost_window_pid_pipe);
datapipe_free(&camera_button_state_pipe);
datapipe_free(&battery_status_pipe);
datapipe_free(&battery_state_pipe);
datapipe_free(&charger_type_pipe);
datapipe_free(&charger_state_pipe);
datapipe_free(&interaction_expected_pipe);
......@@ -1810,6 +1830,60 @@ const char *tklock_status_repr(int status)
return repr;
}
/** Convert battery_state_t enum to human readable string
*
* @param state battery_state_t enumeration value
*
* @return human readable representation of state
*/
const char *
battery_state_repr(battery_state_t state)
{
const char *repr = "invalid";
switch( state ) {
case BATTERY_STATE_UNKNOWN: repr = "unknown"; break;
case BATTERY_STATE_CHARGING: repr = "charging"; break;
case BATTERY_STATE_DISCHARGING: repr = "discharging"; break;
case BATTERY_STATE_NOT_CHARGING: repr = "not_charging"; break;
case BATTERY_STATE_FULL: repr = "full"; break;
default: break;
}
return repr;
}
/** Convert battery_state_t enum to dbus argument string
*
* @param state battery_state_t enumeration value
*
* @return representation of state for use over dbus
*/
const char *
battery_state_to_dbus(battery_state_t state)
{
const char *res = MCE_BATTERY_STATE_UNKNOWN;
switch( state ) {
case BATTERY_STATE_CHARGING:
res = MCE_BATTERY_STATE_CHARGING;
break;
case BATTERY_STATE_DISCHARGING:
res = MCE_BATTERY_STATE_DISCHARGING;
break;
case BATTERY_STATE_NOT_CHARGING:
res = MCE_BATTERY_STATE_NOT_CHARGING;
break;
case BATTERY_STATE_FULL:
res = MCE_BATTERY_STATE_FULL;
break;
default:
break;
}
return res;
}
/** Convert battery_status_t enum to human readable string
*
* @param state battery_status_t enumeration value
......
......@@ -257,6 +257,7 @@ extern datapipe_t interaction_expected_pipe;
extern datapipe_t charger_type_pipe;
extern datapipe_t charger_state_pipe;
extern datapipe_t battery_status_pipe;
extern datapipe_t battery_state_pipe;
extern datapipe_t battery_level_pipe;
extern datapipe_t topmost_window_pid_pipe;
extern datapipe_t camera_button_state_pipe;
......
......@@ -85,6 +85,8 @@ static void common_dbus_send_charger_state (DBusMessage *const req);
static gboolean common_dbus_get_charger_state_cb (DBusMessage *const req);
static void common_dbus_send_battery_status (DBusMessage *const req);
static gboolean common_dbus_get_battery_status_cb (DBusMessage *const req);
static void common_dbus_send_battery_state (DBusMessage *const req);
static gboolean common_dbus_get_battery_state_cb (DBusMessage *const req);
static void common_dbus_send_battery_level (DBusMessage *const req);
static gboolean common_dbus_get_battery_level_cb (DBusMessage *const req);
static gboolean common_dbus_initial_cb (gpointer aptr);
......@@ -99,6 +101,7 @@ static void common_datapipe_usb_cable_state_cb (gconstpointer data);
static void common_datapipe_charger_type_cb (gconstpointer data);
static void common_datapipe_charger_state_cb (gconstpointer data);
static void common_datapipe_battery_status_cb (gconstpointer data);
static void common_datapipe_battery_state_cb (gconstpointer data);
static void common_datapipe_battery_level_cb (gconstpointer data);
static void common_datapipe_proximity_sensor_actual_cb(gconstpointer data);
static void common_datapipe_init (void);
......@@ -127,6 +130,9 @@ static charger_state_t charger_state = CHARGER_STATE_UNDEF;
/** Battery status; assume undefined */
static battery_status_t battery_status = BATTERY_STATUS_UNDEF;
/** Battery state; assume unknown */
static battery_state_t battery_state = BATTERY_STATE_UNKNOWN;
/** Battery charge level: assume 100% */
static gint battery_level = BATTERY_LEVEL_INITIAL;
......@@ -589,6 +595,69 @@ common_dbus_get_battery_status_cb(DBusMessage *const req)
return TRUE;
}
/* ------------------------------------------------------------------------- *
* battery_state
* ------------------------------------------------------------------------- */
/** Send battery_state D-Bus signal / method call reply
*
* @param req method call message to reply, or NULL to send signal
*/
static void
common_dbus_send_battery_state(DBusMessage *const req)
{
static const char *last = 0;
DBusMessage *msg = NULL;
const char *value = battery_state_to_dbus(battery_state);
if( req ) {
msg = dbus_new_method_reply(req);
}
else if( last == value ) {
goto EXIT;
}
else {
last = value;
msg = dbus_new_signal(MCE_SIGNAL_PATH,
MCE_SIGNAL_IF,
MCE_BATTERY_STATE_SIG);
}
if( !dbus_message_append_args(msg,
DBUS_TYPE_STRING, &value,
DBUS_TYPE_INVALID) )
goto EXIT;
mce_log(LL_DEBUG, "%s: %s = %s",
req ? "reply" : "broadcast",
"battery_state", value);
dbus_send_message(msg), msg = 0;
EXIT:
if( msg )
dbus_message_unref(msg);
}
/** Callback for handling battery_state D-Bus queries
*
* @param req method call message to reply
*/
static gboolean
common_dbus_get_battery_state_cb(DBusMessage *const req)
{
mce_log(LL_DEBUG, "battery_state query from: %s",
mce_dbus_get_message_sender_ident(req));
if( !dbus_message_get_no_reply(req) )
common_dbus_send_battery_state(req);
return TRUE;
}
/* ------------------------------------------------------------------------- *
* battery_level
* ------------------------------------------------------------------------- */
......@@ -694,6 +763,13 @@ static mce_dbus_handler_t common_dbus_handlers[] =
.args =
" <arg name=\"battery_status\" type=\"s\"/>\n"
},
{
.interface = MCE_SIGNAL_IF,
.name = MCE_BATTERY_STATE_SIG,
.type = DBUS_MESSAGE_TYPE_SIGNAL,
.args =
" <arg name=\"battery_state\" type=\"s\"/>\n"
},
{
.interface = MCE_SIGNAL_IF,
.name = MCE_BATTERY_LEVEL_SIG,
......@@ -734,6 +810,14 @@ static mce_dbus_handler_t common_dbus_handlers[] =
.args =
" <arg direction=\"out\" name=\"battery_status\" type=\"s\"/>\n"
},
{
.interface = MCE_REQUEST_IF,
.name = MCE_BATTERY_STATE_GET,
.type = DBUS_MESSAGE_TYPE_METHOD_CALL,
.callback = common_dbus_get_battery_state_cb,
.args =
" <arg direction=\"out\" name=\"battery_state\" type=\"s\"/>\n"
},
{
.interface = MCE_REQUEST_IF,
.name = MCE_BATTERY_LEVEL_GET,
......@@ -771,6 +855,7 @@ static gboolean common_dbus_initial_cb(gpointer aptr)
common_dbus_send_charger_type(0);
common_dbus_send_charger_state(0);
common_dbus_send_battery_status(0);
common_dbus_send_battery_state(0);
common_dbus_send_battery_level(0);
common_dbus_initial_id = 0;
......@@ -918,6 +1003,32 @@ EXIT:
return;
}
/* ------------------------------------------------------------------------- *
* battery_state
* ------------------------------------------------------------------------- */
/** Callback for handling battery_state_pipe state changes
*
* @param data battery_state (as void pointer)
*/
static void common_datapipe_battery_state_cb(gconstpointer data)
{
battery_state_t prev = battery_state;
battery_state = GPOINTER_TO_INT(data);
if( battery_state == prev )
goto EXIT;
mce_log(LL_DEBUG, "battery_state = %s -> %s",
battery_state_repr(prev),
battery_state_repr(battery_state));
common_dbus_send_battery_state(0);
EXIT:
return;
}
/* ------------------------------------------------------------------------- *
* battery_level
* ------------------------------------------------------------------------- */
......@@ -992,6 +1103,10 @@ static datapipe_handler_t common_datapipe_handlers[] =
.datapipe = &battery_status_pipe,
.output_cb = common_datapipe_battery_status_cb,
},
{
.datapipe = &battery_state_pipe,
.output_cb = common_datapipe_battery_state_cb,
},
{
.datapipe = &battery_level_pipe,
.output_cb = common_datapipe_battery_level_cb,
......
......@@ -219,6 +219,9 @@
<allow send_destination="com.nokia.mce"
send_interface="com.nokia.mce.request"
send_member="get_battery_status"/>
<allow send_destination="com.nokia.mce"
send_interface="com.nokia.mce.request"
send_member="get_battery_state"/>
<allow send_destination="com.nokia.mce"
send_interface="com.nokia.mce.request"
send_member="get_battery_level"/>
......
......@@ -313,6 +313,19 @@ const char *tklock_status_repr(int status);
/** Assumed initial battery level */
#define BATTERY_LEVEL_INITIAL 100
/** Raw udev battery status */
typedef enum
{
BATTERY_STATE_UNKNOWN,
BATTERY_STATE_CHARGING,
BATTERY_STATE_DISCHARGING,
BATTERY_STATE_NOT_CHARGING,
BATTERY_STATE_FULL,
} battery_state_t;
const char *battery_state_repr(battery_state_t state);
const char *battery_state_to_dbus(battery_state_t state);
/** Battery status */
typedef enum {
BATTERY_STATUS_UNDEF = -1, /**< Battery status not known */
......
......@@ -116,6 +116,9 @@ typedef struct
/** Battery FULL/OK/LOW/EMPTY; for use with battery_status_pipe */
battery_status_t battery_status;
/** Battery UNKNOWN|CHARGING|DISCHARGING|NOT_CHARGING|FULL"*/
battery_state_t battery_state;
/** Charger connected; for use with charger_state_pipe */
charger_state_t charger_state;
......@@ -224,26 +227,27 @@ static bool udevproperty_set (udevproperty_t *self, const ch
* UDEVDEVICE
* ------------------------------------------------------------------------- */
static charger_type_t udevdevice_lookup_charger_type(const char *name);
static void udevdevice_init_blacklist (void);
static void udevdevice_quit_blacklist (void);
static bool udevdevice_is_blacklisted (const char *name);
static udevdevice_t *udevdevice_create (const char *name);
static void udevdevice_delete (udevdevice_t *self);
static void udevdevice_delete_cb (void *self);
static const char *udevdevice_name (const udevdevice_t *self);
static udevproperty_t *udevdevice_get_prop (udevdevice_t *self, const char *key);
static udevproperty_t *udevdevice_add_prop (udevdevice_t *self, const char *key);
static bool udevdevice_set_prop (udevdevice_t *self, const char *key, const char *val);
static const char *udevdevice_get_str_prop (udevdevice_t *self, const char *key, const char *def);
static int udevdevice_get_int_prop (udevdevice_t *self, const char *key, int def);
static bool udevdevice_refresh (udevdevice_t *self, struct udev_device *dev);
static bool udevdevice_is_battery (udevdevice_t *self);
static bool udevdevice_is_charger (udevdevice_t *self);
static void udevdevice_evaluate_charger (udevdevice_t *self, mcebat_t *mcebat);
static void udevdevice_evaluate_charger_cb(gpointer key, gpointer value, gpointer aptr);
static void udevdevice_evaluate_battery (udevdevice_t *self, mcebat_t *mcebat);
static void udevdevice_evaluate_battery_cb(gpointer key, gpointer value, gpointer aptr);
static battery_state_t udevdevice_lookup_battery_state(const char *status);
static charger_type_t udevdevice_lookup_charger_type (const char *name);
static void udevdevice_init_blacklist (void);
static void udevdevice_quit_blacklist (void);
static bool udevdevice_is_blacklisted (const char *name);
static udevdevice_t *udevdevice_create (const char *name);
static void udevdevice_delete (udevdevice_t *self);
static void udevdevice_delete_cb (void *self);
static const char *udevdevice_name (const udevdevice_t *self);
static udevproperty_t *udevdevice_get_prop (udevdevice_t *self, const char *key);
static udevproperty_t *udevdevice_add_prop (udevdevice_t *self, const char *key);
static bool udevdevice_set_prop (udevdevice_t *self, const char *key, const char *val);
static const char *udevdevice_get_str_prop (udevdevice_t *self, const char *key, const char *def);
static int udevdevice_get_int_prop (udevdevice_t *self, const char *key, int def);
static bool udevdevice_refresh (udevdevice_t *self, struct udev_device *dev);
static bool udevdevice_is_battery (udevdevice_t *self);
static bool udevdevice_is_charger (udevdevice_t *self);
static void udevdevice_evaluate_charger (udevdevice_t *self, mcebat_t *mcebat);
static void udevdevice_evaluate_charger_cb (gpointer key, gpointer value, gpointer aptr);
static void udevdevice_evaluate_battery (udevdevice_t *self, mcebat_t *mcebat);
static void udevdevice_evaluate_battery_cb (gpointer key, gpointer value, gpointer aptr);
/* ------------------------------------------------------------------------- *
* UDEVTRACKER
......@@ -294,6 +298,7 @@ G_MODULE_EXPORT module_info_struct module_info =
static mcebat_t mcebat_datapipe = {
.battery_level = BATTERY_LEVEL_INITIAL,
.battery_status = BATTERY_STATUS_UNDEF,
.battery_state = BATTERY_STATE_UNKNOWN,
.charger_state = CHARGER_STATE_UNDEF,
.charger_type = CHARGER_TYPE_NONE,
};
......@@ -303,6 +308,7 @@ static mcebat_t mcebat_datapipe = {
static mcebat_t mcebat_actual = {
.battery_level = BATTERY_LEVEL_INITIAL,
.battery_status = BATTERY_STATUS_UNDEF,
.battery_state = BATTERY_STATE_UNKNOWN,
.charger_state = CHARGER_STATE_UNDEF,
.charger_type = CHARGER_TYPE_NONE,
};
......@@ -466,9 +472,12 @@ mcebat_dbus_evaluate_battery_status(void)
{
/* Handle charger-connected special cases */
if( mcebat_simulated.charger_state == CHARGER_STATE_ON ) {
mcebat_simulated.battery_state = BATTERY_STATE_CHARGING;
if( mcebat_simulated.battery_level >= 100 ) {
/* Battery full reached */
mcebat_simulated.battery_status = BATTERY_STATUS_FULL;
mcebat_simulated.battery_state = BATTERY_STATE_FULL;
goto EXIT;
}
if( mcebat_simulated.battery_status == BATTERY_STATUS_FULL &&
......@@ -482,6 +491,9 @@ mcebat_dbus_evaluate_battery_status(void)
goto EXIT;
}
}
else {
mcebat_simulated.battery_state = BATTERY_STATE_DISCHARGING;
}
/* Evaluate based on battery level */
if( mcebat_simulated.battery_level <= BATTERY_CAPACITY_UNDEF )
......@@ -804,6 +816,16 @@ mcebat_update(void)
mce_datapipe_generate_activity();
}
if( prev.battery_state != curr->battery_state ) {
mce_log(LL_CRUCIAL, "battery_state: %s -> %s",
battery_state_repr(prev.battery_state),
battery_state_repr(curr->battery_state));
/* Battery charging state */
datapipe_exec_full(&battery_state_pipe,
GINT_TO_POINTER(curr->battery_state));
}
if( prev.battery_status != curr->battery_status ) {
mce_log(LL_CRUCIAL, "battery_status: %s -> %s",
battery_status_repr(prev.battery_status),
......@@ -1045,6 +1067,32 @@ udevproperty_set(udevproperty_t *self, const char *val)
* UDEVDEVICE
* ========================================================================= */
/** Lookup mce battery state based on udev battery status property value
*
* @param status udev battery status
*
* @return battery_state_t enumeration value
*/
static battery_state_t
udevdevice_lookup_battery_state(const char *status)
{
battery_state_t state = BATTERY_STATE_UNKNOWN;
if( !g_strcmp0(status, "Charging") )
state = BATTERY_STATE_CHARGING;
else if( !g_strcmp0(status, "Discharging") )
state = BATTERY_STATE_DISCHARGING;
else if( !g_strcmp0(status, "Not charging") )
state = BATTERY_STATE_NOT_CHARGING;
else if( !g_strcmp0(status, "Full") )
state = BATTERY_STATE_FULL;
else if( g_strcmp0(status, "Unknown") )
mce_log(LL_WARN, "unrecognized power supply state '%s'", status);
return state;
}
/** Lookup charger type based on device name / value of type property
*
* @param name string to match
......@@ -1496,9 +1544,11 @@ udevdevice_evaluate_battery(udevdevice_t *self, mcebat_t *mcebat)
else
mcebat->battery_status = BATTERY_STATUS_OK;
/* udev status is "Unknown|Charging|Discharging|Not charging|Full"
*
* "Charging" and "Full" override capacity based mce battery status
/* udev status is "Unknown|Charging|Discharging|Not charging|Full" */
mcebat->battery_state = udevdevice_lookup_battery_state(status);
/* "Charging" and "Full" override capacity based mce battery status
* evaluation above.
*
* How maintenance charging is reported after hitting battery
......@@ -1511,12 +1561,12 @@ udevdevice_evaluate_battery(udevdevice_t *self, mcebat_t *mcebat)
* Also if battery device indicates that it is getting charged,
* assume that a charger is connected.
*/
if( !g_strcmp0(status, "Full") ) {
if( mcebat->battery_state == BATTERY_STATE_FULL ) {
mcebat->charger_state = CHARGER_STATE_ON;
mcebat->battery_status = BATTERY_STATUS_FULL;
self->udd_full = true;
}
else if( !g_strcmp0(status, "Charging") ) {
else if( mcebat->battery_state == BATTERY_STATE_CHARGING ) {
mcebat->charger_state = CHARGER_STATE_ON;
mcebat->battery_status = BATTERY_STATUS_OK;
if( self->udd_full && capacity >= BATTERY_CAPACITY_FULL )
......@@ -1546,6 +1596,10 @@ udevdevice_evaluate_battery(udevdevice_t *self, mcebat_t *mcebat)
self->udd_full = false;
}
/* Override udev status on heuristically determined battery full */
if( mcebat->battery_status == BATTERY_STATUS_FULL )
mcebat->battery_state = BATTERY_STATE_FULL;
mce_log(LL_DEBUG, "%s: battery @ cap=%d status=%s full=%d",
udevdevice_name(self), capacity, status, self->udd_full);
......
......@@ -20,7 +20,7 @@ BuildRequires: pkgconfig(dsme) >= 0.65.0
BuildRequires: pkgconfig(thermalmanager_dbus_if)
BuildRequires: pkgconfig(libiphb)
BuildRequires: pkgconfig(glib-2.0) >= 2.36.0
BuildRequires: pkgconfig(mce) >= 1.27.0
BuildRequires: pkgconfig(mce) >= 1.28.0
BuildRequires: pkgconfig(libngf0) >= 0.24
BuildRequires: pkgconfig(libsystemd-daemon)
BuildRequires: kernel-headers >= 2.6.32
......
......@@ -147,6 +147,7 @@ static bool xmce_set_battery_level (int leve
static void xmce_get_cable_state (void);
static void xmce_get_charger_state (void);
static void xmce_get_battery_status (void);
static void xmce_get_battery_state (void);
static void xmce_get_battery_level (void);
static void xmce_get_battery_info (void);
static void xmce_parse_notification_args (const char *args, char **title, dbus_int32_t *delay, dbus_int32_t *renew);
......@@ -2749,6 +2750,14 @@ static void xmce_get_battery_status(void)
free(str);
}
static void xmce_get_battery_state(void)
{
char *str = 0;
xmce_ipc_string_reply(MCE_BATTERY_STATE_GET, &str, DBUS_TYPE_INVALID);
printf("%-"PAD1"s %s\n","Battery state:", str ?: "unknown");
free(str);
}
static void xmce_get_battery_level(void)
{
gint num = -1;
......@@ -2762,6 +2771,7 @@ static void xmce_get_battery_info(void)
xmce_get_charger_state();
xmce_get_battery_level();
xmce_get_battery_status();
xmce_get_battery_state();
}
/* ------------------------------------------------------------------------- *
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment