/**
* @file battery-bme.c
* Battery module -- this implements battery and charger logic for MCE
*
* Copyright © 2008-2011 Nokia Corporation and/or its subsidiary(-ies).
* Copyright (C) 2013-2019 Jolla Ltd.
*
* @author David Weinehall
* @author Simo Piiroinen
*
* mce is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License
* version 2.1 as published by the Free Software Foundation.
*
* mce is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with mce. If not, see .
*/
#include "../mce.h"
#include "../mce-log.h"
#include "../mce-dbus.h"
#include "../bme-dbus-names.h"
#include
/** Module name */
#define MODULE_NAME "battery"
/** Functionality provided by this module */
static const gchar *const provides[] = { MODULE_NAME, NULL };
/** Module information */
G_MODULE_EXPORT module_info_struct module_info = {
/** Name of the module */
.name = MODULE_NAME,
/** Module provides */
.provides = provides,
/** Module priority */
.priority = 100
};
/** Cached value of the charger connected state */
static gint cached_charger_connected = -1;
/**
* D-Bus callback for the battery full signal
*
* @param msg The D-Bus message
* @return TRUE on success, FALSE on failure
*/
static gboolean battery_full_dbus_cb(DBusMessage *const msg)
{
gboolean status = FALSE;
(void)msg;
mce_log(LL_DEBUG,
"Received battery full signal");
datapipe_exec_full(&led_pattern_deactivate_pipe, MCE_LED_PATTERN_BATTERY_CHARGING);
datapipe_exec_full(&led_pattern_activate_pipe, MCE_LED_PATTERN_BATTERY_FULL);
datapipe_exec_full(&battery_status_pipe,
GINT_TO_POINTER(BATTERY_STATUS_FULL));
status = TRUE;
//EXIT:
return status;
}
/**
* D-Bus callback for the battery ok signal
*
* @param msg The D-Bus message
* @return TRUE on success, FALSE on failure
*/
static gboolean battery_ok_dbus_cb(DBusMessage *const msg)
{
gboolean status = FALSE;
(void)msg;
mce_log(LL_DEBUG,
"Received battery ok signal");
// datapipe_exec_full(&led_pattern_deactivate_pipe, MCE_LED_PATTERN_BATTERY_LOW);
datapipe_exec_full(&battery_status_pipe,
GINT_TO_POINTER(BATTERY_STATUS_OK));
status = TRUE;
//EXIT:
return status;
}
/**
* D-Bus callback for the battery low signal
*
* @param msg The D-Bus message
* @return TRUE on success, FALSE on failure
*/
static gboolean battery_low_dbus_cb(DBusMessage *const msg)
{
gboolean status = FALSE;
(void)msg;
mce_log(LL_DEBUG,
"Received battery low signal");
// datapipe_exec_full(&led_pattern_activate_pipe, MCE_LED_PATTERN_BATTERY_LOW);
datapipe_exec_full(&battery_status_pipe,
GINT_TO_POINTER(BATTERY_STATUS_LOW));
status = TRUE;
//EXIT:
return status;
}
/**
* D-Bus callback for the battery empty signal
*
* @param msg The D-Bus message
* @return TRUE on success, FALSE on failure
*/
static gboolean battery_empty_dbus_cb(DBusMessage *const msg)
{
gboolean status = FALSE;
(void)msg;
mce_log(LL_DEBUG,
"Received battery empty signal");
datapipe_exec_full(&battery_status_pipe,
GINT_TO_POINTER(BATTERY_STATUS_EMPTY));
status = TRUE;
//EXIT:
return status;
}
/**
* D-Bus callback for the battery state changed signal
*
* @param msg The D-Bus message
* @return TRUE on success, FALSE on failure
*/
static gboolean battery_state_changed_dbus_cb(DBusMessage *const msg)
{
dbus_uint32_t percentage;
DBusMessageIter iter;
dbus_uint32_t now;
dbus_uint32_t max;
gint argcount = 0;
gint argtype;
gboolean status = FALSE;
mce_log(LL_DEBUG,
"Received battery state changed signal");
if (dbus_message_iter_init(msg, &iter) == FALSE) {
// XXX: should we return an error instead?
mce_log(LL_ERR,
"Failed to initialise D-Bus message iterator; "
"message has no arguments");
goto EXIT;
}
while ((argtype = dbus_message_iter_get_arg_type(&iter)) != DBUS_TYPE_INVALID) {
if (argtype == DBUS_TYPE_UINT32) {
if (argcount == 0) {
dbus_message_iter_get_basic(&iter, &now);
} else if (argcount == 1) {
dbus_message_iter_get_basic(&iter, &max);
} else if (argcount == 2) {
dbus_message_iter_get_basic(&iter, &percentage);
}
} else if (argcount < 3) {
mce_log(LL_ERR,
"Argument %d passed to %s.%s has "
"incorrect type",
argcount,
BME_SIGNAL_IF,
BME_BATTERY_STATE_UPDATE);
goto EXIT;
}
argcount++;
dbus_message_iter_next (&iter);
}
if (argcount < 2) {
mce_log(LL_ERR,
"Too few arguments received from "
"%s.%s; "
"got %d, expected %d-%d",
BME_SIGNAL_IF, BME_BATTERY_STATE_UPDATE,
argcount, 2, 3);
goto EXIT;
}
if (argcount > 3) {
mce_log(LL_INFO,
"Too many arguments received from "
"%s.%s; "
"got %d, expected %d-%d -- ignoring extra arguments",
BME_SIGNAL_IF, BME_BATTERY_STATE_UPDATE,
argcount, 2, 3);
}
if (argcount == 2) {
percentage = (now * 10 / max) * 10;
}
mce_log(LL_DEBUG,
"Percentage: %d",
percentage);
datapipe_exec_full(&battery_level_pipe,
GINT_TO_POINTER(percentage));
status = TRUE;
EXIT:
return status;
}
/**
* D-Bus callback for the charger_charging_on signal
*
* @param msg The D-Bus message
* @return TRUE on success, FALSE on failure
*/
static gboolean charger_charging_on_dbus_cb(DBusMessage *const msg)
{
charger_state_t old_charger_state = datapipe_get_gint(charger_state_pipe);
gboolean status = FALSE;
(void)msg;
mce_log(LL_DEBUG,
"Received charger_charging_on signal");
/* Only update the charger state if needed */
if (old_charger_state != CHARGER_STATE_ON) {
datapipe_exec_full(&charger_state_pipe,
GINT_TO_POINTER(CHARGER_STATE_ON));
}
/* In case these are active; there's no harm to call them anyway */
datapipe_exec_full(&led_pattern_deactivate_pipe, MCE_LED_PATTERN_BATTERY_FULL);
// datapipe_exec_full(&led_pattern_deactivate_pipe, MCE_LED_PATTERN_BATTERY_LOW);
datapipe_exec_full(&led_pattern_activate_pipe, MCE_LED_PATTERN_BATTERY_CHARGING);
status = TRUE;
//EXIT:
return status;
}
/**
* D-Bus callback for the charger_charging_off signal
*
* @param msg The D-Bus message
* @return TRUE on success, FALSE on failure
*/
static gboolean charger_charging_off_dbus_cb(DBusMessage *const msg)
{
charger_state_t old_charger_state = datapipe_get_gint(charger_state_pipe);
gboolean status = FALSE;
(void)msg;
mce_log(LL_DEBUG,
"Received charger_charging_off signal");
/* Only update the charger state if needed */
if (old_charger_state != CHARGER_STATE_OFF) {
datapipe_exec_full(&charger_state_pipe,
GINT_TO_POINTER(CHARGER_STATE_OFF));
}
/* In case these are active; there's no harm to call them anyway */
datapipe_exec_full(&led_pattern_deactivate_pipe, MCE_LED_PATTERN_BATTERY_CHARGING);
status = TRUE;
//EXIT:
return status;
}
/**
* D-Bus callback for the charger_charging_failed signal
*
* @param msg The D-Bus message
* @return TRUE on success, FALSE on failure
*/
static gboolean charger_charging_failed_dbus_cb(DBusMessage *const msg)
{
charger_state_t old_charger_state = datapipe_get_gint(charger_state_pipe);
gboolean status = FALSE;
(void)msg;
mce_log(LL_DEBUG,
"Received charger_charging_failed signal");
/* Only update the charger state if needed */
if (old_charger_state != CHARGER_STATE_OFF) {
datapipe_exec_full(&charger_state_pipe,
GINT_TO_POINTER(CHARGER_STATE_OFF));
}
/* In case these are active; there's no harm to call them anyway */
datapipe_exec_full(&led_pattern_deactivate_pipe, MCE_LED_PATTERN_BATTERY_FULL);
datapipe_exec_full(&led_pattern_deactivate_pipe, MCE_LED_PATTERN_BATTERY_CHARGING);
/* Generate activity */
mce_datapipe_generate_activity();
status = TRUE;
//EXIT:
return status;
}
/**
* D-Bus callback for the charger_connected signal
*
* @param msg The D-Bus message
* @return TRUE on success, FALSE on failure
*/
static gboolean charger_connected_dbus_cb(DBusMessage *const msg)
{
gboolean status = FALSE;
(void)msg;
mce_log(LL_DEBUG,
"Received charger_connected signal");
if (cached_charger_connected != 1) {
/* Generate activity */
mce_datapipe_generate_activity();
cached_charger_connected = 1;
}
status = TRUE;
//EXIT:
return status;
}
/**
* D-Bus callback for the charger_disconnected signal
*
* @param msg The D-Bus message
* @return TRUE on success, FALSE on failure
*/
static gboolean charger_disconnected_dbus_cb(DBusMessage *const msg)
{
charger_state_t old_charger_state = datapipe_get_gint(charger_state_pipe);
gboolean status = FALSE;
(void)msg;
mce_log(LL_DEBUG,
"Received charger_disconnected signal");
/* Only update the charger state if needed */
if (old_charger_state != CHARGER_STATE_OFF) {
datapipe_exec_full(&charger_state_pipe,
GINT_TO_POINTER(CHARGER_STATE_OFF));
}
/* In case these are active; there's no harm to call them anyway */
datapipe_exec_full(&led_pattern_deactivate_pipe, MCE_LED_PATTERN_BATTERY_FULL);
datapipe_exec_full(&led_pattern_deactivate_pipe, MCE_LED_PATTERN_BATTERY_CHARGING);
if (cached_charger_connected != 0) {
/* Generate activity */
mce_datapipe_generate_activity();
cached_charger_connected = 0;
}
status = TRUE;
//EXIT:
return status;
}
/**
* Request update of charger status
*
* @return TRUE on success, FALSE on failure
*/
static gboolean request_charger_status(void)
{
return dbus_send(BME_SERVICE, BME_REQUEST_PATH, BME_REQUEST_IF,
BME_STATUS_INFO_REQ, NULL, DBUS_TYPE_INVALID);
}
/** Array of dbus message handlers */
static mce_dbus_handler_t battery_bme_dbus_handlers[] =
{
/* signals */
{
.interface = BME_SIGNAL_IF,
.name = BME_BATTERY_FULL,
.type = DBUS_MESSAGE_TYPE_SIGNAL,
.callback = battery_full_dbus_cb,
},
{
.interface = BME_SIGNAL_IF,
.name = BME_BATTERY_OK,
.type = DBUS_MESSAGE_TYPE_SIGNAL,
.callback = battery_ok_dbus_cb,
},
{
.interface = BME_SIGNAL_IF,
.name = BME_BATTERY_LOW,
.type = DBUS_MESSAGE_TYPE_SIGNAL,
.callback = battery_low_dbus_cb,
},
{
.interface = BME_SIGNAL_IF,
.name = BME_BATTERY_EMPTY,
.type = DBUS_MESSAGE_TYPE_SIGNAL,
.callback = battery_empty_dbus_cb,
},
{
.interface = BME_SIGNAL_IF,
.name = BME_BATTERY_STATE_UPDATE,
.type = DBUS_MESSAGE_TYPE_SIGNAL,
.callback = battery_state_changed_dbus_cb,
},
{
.interface = BME_SIGNAL_IF,
.name = BME_CHARGER_CHARGING_ON,
.type = DBUS_MESSAGE_TYPE_SIGNAL,
.callback = charger_charging_on_dbus_cb,
},
{
.interface = BME_SIGNAL_IF,
.name = BME_CHARGER_CHARGING_OFF,
.type = DBUS_MESSAGE_TYPE_SIGNAL,
.callback = charger_charging_off_dbus_cb,
},
{
.interface = BME_SIGNAL_IF,
.name = BME_CHARGER_CHARGING_FAILED,
.type = DBUS_MESSAGE_TYPE_SIGNAL,
.callback = charger_charging_failed_dbus_cb,
},
{
.interface = BME_SIGNAL_IF,
.name = BME_CHARGER_CONNECTED,
.type = DBUS_MESSAGE_TYPE_SIGNAL,
.callback = charger_connected_dbus_cb,
},
{
.interface = BME_SIGNAL_IF,
.name = BME_CHARGER_DISCONNECTED,
.type = DBUS_MESSAGE_TYPE_SIGNAL,
.callback = charger_disconnected_dbus_cb,
},
/* sentinel */
{
.interface = 0
}
};
/** Add dbus handlers
*/
static void battery_bme_init_dbus(void)
{
mce_dbus_handler_register_array(battery_bme_dbus_handlers);
}
/** Remove dbus handlers
*/
static void battery_bme_quit_dbus(void)
{
mce_dbus_handler_unregister_array(battery_bme_dbus_handlers);
}
/**
* Init function for the battery and charger module
*
* @todo XXX status needs to be set on error!
*
* @param module Unused
* @return NULL on success, a string with an error message on failure
*/
G_MODULE_EXPORT const gchar *g_module_check_init(GModule *module);
const gchar *g_module_check_init(GModule *module)
{
(void)module;
/* Add dbus handlers */
battery_bme_init_dbus();
/* Update charger status */
request_charger_status();
return NULL;
}
/**
* Exit function for the battery and charger module
*
* @todo D-Bus unregistration
*
* @param module Unused
*/
G_MODULE_EXPORT void g_module_unload(GModule *module);
void g_module_unload(GModule *module)
{
(void)module;
/* Remove dbus handlers */
battery_bme_quit_dbus();
return;
}