From: Paulo Borges <paulo.borges@openbossa.org>
To: linux-bluetooth@vger.kernel.org
Cc: Paulo Borges <paulo.borges@openbossa.org>
Subject: [PATCH 9/9] battery: Support persistent battery level
Date: Mon, 7 Jan 2013 16:41:04 -0300 [thread overview]
Message-ID: <1357587664-16818-10-git-send-email-paulo.borges@openbossa.org> (raw)
In-Reply-To: <1357587664-16818-1-git-send-email-paulo.borges@openbossa.org>
Store battery level when read, and use the level from storage
when connecting, to reduce GATT traffic.
---
profiles/battery/battery.c | 137 +++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 135 insertions(+), 2 deletions(-)
diff --git a/profiles/battery/battery.c b/profiles/battery/battery.c
index 2ef4f6b..e4a6e53 100644
--- a/profiles/battery/battery.c
+++ b/profiles/battery/battery.c
@@ -27,6 +27,8 @@
#include <glib.h>
#include <bluetooth/uuid.h>
#include <stdbool.h>
+#include <sys/file.h>
+#include <stdlib.h>
#include "adapter.h"
#include "device.h"
@@ -37,6 +39,11 @@
#include "attrib/gatt.h"
#include "attio.h"
#include "log.h"
+#include "storage.h"
+
+#define BATTERY_FILE "batteries"
+#define BATTERY_GROUP_FORMAT "%04X"
+#define BATTERY_KEY_LEVEL "Level"
struct battery {
struct btd_device *dev; /* Device reference */
@@ -77,10 +84,133 @@ static gint cmp_device(gconstpointer a, gconstpointer b)
return -1;
}
+static gboolean store_battery_char(struct characteristic *chr)
+{
+ GKeyFile *key_file;
+ char filename[PATH_MAX + 1];
+ char adapter_addr[18];
+ char device_addr[18];
+ char group[5];
+ char *str;
+ gsize length = 0;
+
+ ba2str(adapter_get_address(device_get_adapter(chr->batt->dev)),
+ adapter_addr);
+ ba2str(device_get_address(chr->batt->dev), device_addr);
+
+ snprintf(filename, PATH_MAX, STORAGEDIR "/%s/%s/" BATTERY_FILE,
+ adapter_addr, device_addr);
+
+ snprintf(group, sizeof(group), BATTERY_GROUP_FORMAT, chr->attr.handle);
+
+ key_file = g_key_file_new();
+ g_key_file_load_from_file(key_file, filename, 0, NULL);
+
+ g_key_file_set_integer(key_file, group, BATTERY_KEY_LEVEL, chr->level);
+
+ create_file(filename, S_IRUSR | S_IWUSR);
+
+ str = g_key_file_to_data(key_file, &length, NULL);
+ g_file_set_contents(filename, str, length, NULL);
+
+ g_free(str);
+ g_key_file_free(key_file);
+
+ return TRUE;
+}
+
+static int read_battery_char(struct characteristic *chr)
+{
+ GKeyFile *key_file;
+ char filename[PATH_MAX + 1];
+ char adapter_addr[18];
+ char device_addr[18];
+ char group[5];
+ int chr_value;
+
+ ba2str(adapter_get_address(device_get_adapter(chr->batt->dev)),
+ adapter_addr);
+ ba2str(device_get_address(chr->batt->dev), device_addr);
+
+ snprintf(filename, PATH_MAX, STORAGEDIR "/%s/%s/" BATTERY_FILE,
+ adapter_addr, device_addr);
+
+ snprintf(group, sizeof(group), BATTERY_GROUP_FORMAT, chr->attr.handle);
+
+ key_file = g_key_file_new();
+ if (!g_key_file_load_from_file(key_file, filename, 0, NULL)) {
+ g_key_file_free(key_file);
+ return 0;
+ }
+
+ chr_value = g_key_file_get_integer(key_file, group, BATTERY_KEY_LEVEL,
+ NULL);
+ g_key_file_free(key_file);
+
+ return chr_value;
+}
+
+static void del_battery_char(struct characteristic *chr)
+{
+ GKeyFile *key_file;
+ char filename[PATH_MAX + 1];
+ char adapter_addr[18];
+ char device_addr[18];
+ char group[5];
+ char *str;
+ gsize length = 0;
+
+ ba2str(adapter_get_address(device_get_adapter(chr->batt->dev)),
+ adapter_addr);
+ ba2str(device_get_address(chr->batt->dev), device_addr);
+
+ snprintf(filename, PATH_MAX, STORAGEDIR "/%s/%s/" BATTERY_FILE,
+ adapter_addr, device_addr);
+
+ snprintf(group, sizeof(group), BATTERY_GROUP_FORMAT, chr->attr.handle);
+
+ key_file = g_key_file_new();
+ if (!g_key_file_load_from_file(key_file, filename, 0, NULL)) {
+ g_key_file_free(key_file);
+ return;
+ }
+
+ g_key_file_remove_key(key_file, group, BATTERY_KEY_LEVEL, NULL);
+
+ create_file(filename, S_IRUSR | S_IWUSR);
+
+ str = g_key_file_to_data(key_file, &length, NULL);
+ g_file_set_contents(filename, str, length, NULL);
+
+ g_free(str);
+ g_key_file_free(key_file);
+}
+
+static gboolean read_battery_level_value(struct characteristic *chr)
+{
+ int level;
+
+ if (!chr)
+ return FALSE;
+
+ level = read_battery_char(chr);
+ if (!level)
+ return FALSE;
+
+ chr->level = level;
+
+ btd_device_set_battery_opt(chr->devbatt, BATTERY_OPT_LEVEL, chr->level,
+ BATTERY_OPT_INVALID);
+
+ return TRUE;
+}
+
static void char_free(gpointer user_data)
{
struct characteristic *c = user_data;
+ del_battery_char(c);
+
if (c->notifyid && c->batt->attrib != NULL)
g_attrib_unregister(c->batt->attrib, c->notifyid);
@@ -135,6 +265,8 @@ static void read_batterylevel_cb(guint8 status, const guint8 *pdu, guint16 len,
ch->level = value[0];
btd_device_set_battery_opt(ch->devbatt, BATTERY_OPT_LEVEL, ch->level,
BATTERY_OPT_INVALID);
+
+ store_battery_char(ch);
}
static void process_batteryservice_char(struct characteristic *ch)
@@ -359,7 +491,8 @@ static void configure_battery_cb(GSList *characteristics, guint8 status,
start = c->value_handle + 1;
- process_batteryservice_char(ch);
+ if (!read_battery_level_value(ch))
+ process_batteryservice_char(ch);
ch->devbatt = btd_device_add_battery(ch->batt->dev);
@@ -396,7 +529,7 @@ static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
GSList *l;
for (l = batt->chars; l; l = l->next) {
struct characteristic *c = l->data;
- if (!c->can_notify)
+ if (!read_battery_level_value(c) && !c->can_notify)
process_batteryservice_char(c);
}
}
--
1.7.9.5
prev parent reply other threads:[~2013-01-07 19:41 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2013-01-07 19:40 [PATCH 0/9] Battery Profile implementation Paulo Borges
2013-01-07 19:40 ` [PATCH 1/9] battery: Add generic device battery documentation Paulo Borges
2013-01-07 19:40 ` [PATCH 2/9] battery: Implement Generic device battery Paulo Borges
2013-01-07 19:40 ` [PATCH 3/9] battery: Add GATT Battery Client Service skeleton Paulo Borges
2013-01-07 19:40 ` [PATCH 4/9] battery: Discover Characteristic Descriptors Paulo Borges
2013-01-07 19:41 ` [PATCH 5/9] battery: Get Battery ID Paulo Borges
2013-01-07 19:41 ` [PATCH 6/9] battery: Add Battery to device Paulo Borges
2013-01-07 19:41 ` [PATCH 7/9] battery: Read Battery level characteristic Paulo Borges
2013-01-07 19:41 ` [PATCH 8/9] battery: Add support for notifications Paulo Borges
2013-01-07 19:41 ` Paulo Borges [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1357587664-16818-10-git-send-email-paulo.borges@openbossa.org \
--to=paulo.borges@openbossa.org \
--cc=linux-bluetooth@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).