* Re: [PATCH v2] HID: Add support for Sony PS3 BD Remote Control
From: Antonio Ospite @ 2012-09-19 16:48 UTC (permalink / raw)
To: David Dillow
Cc: linux-bluetooth, David Herrmann, Luiz Augusto von Dentz,
Bastien Nocera, linux-input, jkosina
In-Reply-To: <1347932038.29391.17.camel@obelisk.thedillows.org>
On Mon, 17 Sep 2012 21:33:58 -0400
David Dillow <dave@thedillows.org> wrote:
> The Sony PS3 Blue-ray Disc Remote Control used to be supported by the
> BlueZ project's user space, but the code that handled it was recently
> removed as its functionality conflicted with a real HSP implementation
> and the mapping was thought to be better handled in the kernel. This is
> a port of the mapping logic from the fakehid driver by Marcel Holtmann
> to the in-kernel HID layer.
>
> We also add support for the Logitech Harmony Adapter for PS3, which
> emulates the BD Remote.
>
> Signed-off-by: David Dillow <dave@thedillows.org>
> ---
> drivers/hid/Kconfig | 11 ++-
> drivers/hid/Makefile | 1 +
> drivers/hid/hid-core.c | 2 +
> drivers/hid/hid-ids.h | 2 +
> drivers/hid/hid-ps3remote.c | 199 +++++++++++++++++++++++++++++++++++++++++++
> 5 files changed, 214 insertions(+), 1 deletions(-)
>
> Here's an updated version of the HID driver for the PS3 BD Remote. I've
> gone ahead and signed off on it as it works for my Harmony adapter, but
> it needs testing with a real BD remote before going upstream. Antonio
> also asked for some text about the pairing process -- I've left it out
> since I don't know what it should be.
>
Tested with the original PS3 BD remote and this version works fine too,
thanks.
Tested-by: Antonio Ospite <ospite@studenti.unina.it>
About the multiple keys press handling I see that my keyboard does this:
I press 'a' and keep it pressed:
Event: time 1348069423.217974, type 1 (EV_KEY), code 30 (KEY_A), value 1
Event: time 1348069423.249871, type 1 (EV_KEY), code 30 (KEY_A), value 2
Event: time 1348069423.282410, type 1 (EV_KEY), code 30 (KEY_A), value 2
aaa
...
I press 's' and release it:
Event: time 1348069423.290792, type 1 (EV_KEY), code 31 (KEY_S), value 1
Event: time 1348069423.374516, type 1 (EV_KEY), code 31 (KEY_S), value 0
s
I release 'a':
Event: time 1348069427.351315, type 1 (EV_KEY), code 30 (KEY_A), value 0
While on the remote I see:
I press '1' and keep it pressed:
Event: time 1348069656.505528, type 1 (EV_KEY), code 2 (KEY_1), value 1
1111111111...
I press '2' and release it ('1' is sent):
Event: time 1348069666.025543, type 1 (EV_KEY), code 2 (KEY_1), value 0
Event: time 1348069668.395531, type 1 (EV_KEY), code 2 (KEY_1), value 1
1111111111...
I release '1':
Event: time 1348069671.625541, type 1 (EV_KEY), code 2 (KEY_1), value 0
I don't know at what level this behavior is enforced.
I will test later with the old raw_event callback and the fix to the
descriptor you suggested in the other mail.
David D. what is the behavior of the Harmony adapter?
Few more comments inlined below.
>
> diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
> index fbf4950..7bf3b1a 100644
> --- a/drivers/hid/Kconfig
> +++ b/drivers/hid/Kconfig
> @@ -534,6 +534,14 @@ config HID_PRIMAX
> Support for Primax devices that are not fully compliant with the
> HID standard.
>
> +config HID_PS3REMOTE
> + tristate "Sony PS3 BD Remote"
If you are going for a v3, consider using "Sony PS3 BD Remote Control"
here too, not a big deal but that's the name on the user manual.
> + depends on BT_HIDP
> + ---help---
> + Support for the Sony PS3 BD Remote and Logitech Harmony Adapter
> + for PS3, which connect over Bluetooth. Support for the 6-axis
> + controllers is provided by HID_SONY.
> +
> config HID_ROCCAT
> tristate "Roccat device support"
> depends on USB_HID
> @@ -561,7 +569,8 @@ config HID_SONY
> tristate "Sony PS3 controller"
> depends on USB_HID
> ---help---
> - Support for Sony PS3 controller.
> + Support for Sony PS3 6-axis controllers. Support for the Sony PS3
> + BD Remote is provided by HID_PS3REMOTE.
>
> config HID_SPEEDLINK
> tristate "Speedlink VAD Cezanne mouse support"
> diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
> index f975485..333ed6c 100644
> --- a/drivers/hid/Makefile
> +++ b/drivers/hid/Makefile
> @@ -70,6 +70,7 @@ obj-$(CONFIG_HID_PANTHERLORD) += hid-pl.o
> obj-$(CONFIG_HID_PETALYNX) += hid-petalynx.o
> obj-$(CONFIG_HID_PICOLCD) += hid-picolcd.o
> obj-$(CONFIG_HID_PRIMAX) += hid-primax.o
> +obj-$(CONFIG_HID_PS3REMOTE) += hid-ps3remote.o
> obj-$(CONFIG_HID_ROCCAT) += hid-roccat.o hid-roccat-common.o \
> hid-roccat-arvo.o hid-roccat-isku.o hid-roccat-kone.o \
> hid-roccat-koneplus.o hid-roccat-kovaplus.o hid-roccat-pyra.o \
> diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
> index 60ea284..a9f0439 100644
> --- a/drivers/hid/hid-core.c
> +++ b/drivers/hid/hid-core.c
> @@ -1591,6 +1591,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
> { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2) },
> { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACETRAVELLER) },
> { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACENAVIGATOR) },
> + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_PS3) },
Jiri, what is supposed to be the ordering of entries here? Alphabetical
on the product field, or by product numerical value like in hid-ids.h?
> { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICOLCD) },
> { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICOLCD_BOOTLOADER) },
> { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_COMFORT_MOUSE_4500) },
> @@ -1641,6 +1642,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
> { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER) },
> { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) },
> { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE) },
> + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_BDREMOTE) },
> { HID_USB_DEVICE(USB_VENDOR_ID_SUNPLUS, USB_DEVICE_ID_SUNPLUS_WDESKTOP) },
> { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb300) },
> { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb304) },
> diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
> index 1dcb76f..0f5c2bb 100644
> --- a/drivers/hid/hid-ids.h
> +++ b/drivers/hid/hid-ids.h
> @@ -492,6 +492,7 @@
> #define USB_DEVICE_ID_LG_MULTITOUCH 0x0064
>
> #define USB_VENDOR_ID_LOGITECH 0x046d
> +#define USB_DEVICE_ID_LOGITECH_HARMONY_PS3 0x0306
> #define USB_DEVICE_ID_LOGITECH_AUDIOHUB 0x0a0e
> #define USB_DEVICE_ID_LOGITECH_RECEIVER 0xc101
> #define USB_DEVICE_ID_LOGITECH_HARMONY_FIRST 0xc110
> @@ -684,6 +685,7 @@
> #define USB_VENDOR_ID_SONY 0x054c
> #define USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE 0x024b
> #define USB_DEVICE_ID_SONY_PS3_CONTROLLER 0x0268
> +#define USB_DEVICE_ID_SONY_PS3_BDREMOTE 0x0306
> #define USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER 0x042f
>
> #define USB_VENDOR_ID_SOUNDGRAPH 0x15c2
> diff --git a/drivers/hid/hid-ps3remote.c b/drivers/hid/hid-ps3remote.c
> new file mode 100644
> index 0000000..e8caef0
> --- /dev/null
> +++ b/drivers/hid/hid-ps3remote.c
> @@ -0,0 +1,199 @@
> +/*
> + * HID driver for Sony PS3 BD Remote
> + *
> + * Copyright (c) 2012 David Dillow <dave@thedillows.org>
> + * Based on a blend of the bluez fakehid user-space code by Marcel Holtmann
> + * and other kernel HID drivers.
> + */
> +
> +/*
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of the GNU General Public License as published by the Free
> + * Software Foundation; either version 2 of the License, or (at your option)
> + * any later version.
> + */
> +
For the note about the association procedure I had in mind something
like this:
/* NOTE: in order to associate the Sony PS3 BD Remote with a Bluetooth host
* the key combination Start+Enter has to be kept pressed for about 7 seconds,
* with the host BT Controller in discovering mode.
*
* Also the pin request should be ignored by the BT Controller (NULL pin).
*/
Could someone more into BT please check the terminology here? Thanks.
>
> +#include <linux/device.h>
> +#include <linux/hid.h>
> +#include <linux/module.h>
> +
> +#include "hid-ids.h"
> +
> +/*
> + * The first byte of the raw event report seems to contain a fixed number,
> + * possibly a controller number. The next three bytes contain a bitmask,
> + * in big-endian order, of a portion of the buttons available.
> + *
> + * Button Bit Scan Mapped Key
> + * PS 0 0x43 KEY_HOMEPAGE
> + * Unknown 1-2
> + * Enter 3 0x0b KEY_ENTER
> + * Unknown 4-7
> + * L2 8 0x58 BTN_TL2
> + * R2 9 0x59 BTN_TR2
> + * L1 10 0x5a BTN_TL
> + * R1 11 0x5b BTN_TR
> + * Triangle 12 0x5c KEY_OPTION
> + * Circle 13 0x5d KEY_BACK
> + * Cross 14 0x5e BTN_0
> + * Square 15 0x5f KEY_SCREEN
> + * Select 16 0x50 KEY_SELECT
> + * L3 17 0x51 BTN_THUMBL
> + * R3 18 0x52 BTN_THUMBR
> + * Start 19 0x53 BTN_START
> + * Up 20 0x54 KEY_UP
> + * Right 21 0x55 KEY_RIGHT
> + * Down 22 0x56 KEY_DOWN
> + * Left 23 0x57 KEY_LEFT
> + *
> + * The keymap is generally ordered by the physical location of the buttons,
> + * as this makes it easier to verify a correct mapping during testing.
> + */
> +static const unsigned int ps3remote_keymap[] = {
> + [0x16] = KEY_EJECTCD,
> + [0x64] = KEY_AUDIO,
> + [0x65] = KEY_ANGLE,
> + [0x63] = KEY_SUBTITLE,
> + [0x0f] = KEY_CLEAR,
> + [0x28] = KEY_TIME,
> + [0x00] = KEY_1,
> + [0x01] = KEY_2,
> + [0x02] = KEY_3,
> + [0x03] = KEY_4,
> + [0x04] = KEY_5,
> + [0x05] = KEY_6,
> + [0x06] = KEY_7,
> + [0x07] = KEY_8,
> + [0x08] = KEY_9,
> + [0x09] = KEY_0,
> + [0x81] = KEY_RED,
> + [0x82] = KEY_GREEN,
> + [0x80] = KEY_BLUE,
> + [0x83] = KEY_YELLOW,
> + [0x70] = KEY_INFO, /* display */
> + [0x1a] = KEY_MENU, /* top menu */
> + [0x40] = KEY_CONTEXT_MENU, /* pop up/menu */
> + [0x0e] = KEY_ESC, /* return */
> + [0x5c] = KEY_OPTION, /* options/triangle */
> + [0x5d] = KEY_BACK, /* back/circle */
> + [0x5f] = KEY_SCREEN, /* view/square */
> + [0x5e] = BTN_0, /* cross */
> + [0x54] = KEY_UP,
> + [0x56] = KEY_DOWN,
> + [0x57] = KEY_LEFT,
> + [0x55] = KEY_RIGHT,
> + [0x0b] = KEY_ENTER,
> + [0x5a] = BTN_TL, /* L1 */
> + [0x58] = BTN_TL2, /* L2 */
> + [0x51] = BTN_THUMBL, /* L3 */
> + [0x5b] = BTN_TR, /* R1 */
> + [0x59] = BTN_TR2, /* R2 */
> + [0x52] = BTN_THUMBR, /* R3 */
> + [0x43] = KEY_HOMEPAGE, /* PS button */
> + [0x50] = KEY_SELECT,
> + [0x53] = BTN_START,
> + [0x33] = KEY_REWIND, /* scan back */
> + [0x32] = KEY_PLAY,
> + [0x34] = KEY_FORWARD, /* scan forward */
> + [0x30] = KEY_PREVIOUS,
> + [0x38] = KEY_STOP,
> + [0x31] = KEY_NEXT,
> + [0x60] = KEY_FRAMEBACK, /* slow/step back */
> + [0x39] = KEY_PAUSE,
> + [0x61] = KEY_FRAMEFORWARD, /* slow/step forward */
> +};
> +
> +static __u8 ps3remote_rdesc[] = {
> + 0x05, 0x01, /* USAGE PAGE (Generic Desktop) */
> + 0x09, 0x05, /* USAGE (Game Pad) */
> + 0xa1, 0x01, /* COLLECTION (Application) */
> +
> + /* First four bytes contain a bitmask for some of the buttons, and
> + * possibly a controller number. We don't need this information,
> + * as the keys will be reported in the next field as well.
> + */
> + 0x75, 0x20, /* REPORT SIZE (32) */
> + 0x95, 0x01, /* REPORT COUNT (1) */
> + 0x81, 0x01, /* INPUT (Constant) */
> +
> + /* All key presses are reported in this field */
> + 0x05, 0x09, /* USAGE PAGE (Button) */
> + 0x19, 0x00, /* USAGE MINIMUM (0) */
> + 0x29, 0xfe, /* USAGE MAXIMUM (254) */
> + 0x15, 0x00, /* LOGICAL MINIMUM (0) */
> + 0x25, 0xfe, /* LOGICAL MAXIMUM (254) */
> + 0x75, 0x08, /* REPORT SIZE (8) */
> + 0x95, 0x06, /* REPORT COUNT (6) */
> + 0x81, 0x00, /* INPUT (Array, Absolute) */
> +
> + /* Ignore press indication */
> + 0x75, 0x08, /* REPORT SIZE (8) */
> + 0x95, 0x01, /* REPORT COUNT (1) */
> + 0x81, 0x01, /* INPUT (Constant) */
> +
> + /* Report the battery level */
> + 0x05, 0x06, /* USAGE PAGE (Generic Device) */
> + 0x09, 0x20, /* USAGE (Battery Strength) */
> + 0x15, 0x00, /* LOGICAL MINIMUM (0) */
> + 0x25, 0x05, /* LOGICAL MAXIMUM (5) */
> + 0x75, 0x08, /* REPORT SIZE (8) */
> + 0x95, 0x01, /* REPORT COUNT (1) */
> + 0x81, 0x02, /* INPUT (Variable, Absolute) */
> + 0xc0, /* END_COLLECTION */
> +};
> +
> +static __u8 *ps3remote_fixup(struct hid_device *hdev, __u8 *rdesc,
> + unsigned int *rsize)
> +{
> + *rsize = sizeof(ps3remote_rdesc);
> + return ps3remote_rdesc;
> +}
> +
> +static int ps3remote_mapping(struct hid_device *hdev, struct hid_input *hi,
> + struct hid_field *field, struct hid_usage *usage,
> + unsigned long **bit, int *max)
> +{
> + unsigned int key = usage->hid & HID_USAGE;
> +
> + if ((usage->hid & HID_USAGE_PAGE) != HID_UP_BUTTON ||
> + key >= ARRAY_SIZE(ps3remote_keymap))
> + return -1;
> +
> + key = ps3remote_keymap[key];
> + if (!key)
> + return -1;
> +
> + hid_map_usage_clear(hi, usage, bit, max, EV_KEY, key);
> + return 1;
> +}
> +
> +static const struct hid_device_id ps3remote_devices[] = {
> + /* PS3 BD Remote */
> + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_BDREMOTE) },
> + /* Logitech Harmony Adapter for PS3 */
> + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_HARMONY_PS3) },
> + { }
> +};
> +MODULE_DEVICE_TABLE(hid, ps3remote_devices);
> +
> +static struct hid_driver ps3remote_driver = {
> + .name = "ps3_remote",
> + .id_table = ps3remote_devices,
> + .report_fixup = ps3remote_fixup,
> + .input_mapping = ps3remote_mapping,
> +};
> +
> +static int __init ps3remote_init(void)
> +{
> + return hid_register_driver(&ps3remote_driver);
> +}
> +
> +static void __exit ps3remote_exit(void)
> +{
> + hid_unregister_driver(&ps3remote_driver);
> +}
> +
> +module_init(ps3remote_init);
> +module_exit(ps3remote_exit);
> +MODULE_LICENSE("GPL");
> +MODULE_AUTHOR("David Dillow <dave@thedillows.org>");
>
Thanks,
Antonio
--
Antonio Ospite
http://ao2.it
A: Because it messes up the order in which people normally read text.
See http://en.wikipedia.org/wiki/Posting_style
Q: Why is top-posting such a bad thing?
^ permalink raw reply
* Re: [PATCH v2] HID: Add support for Sony PS3 BD Remote Control
From: David Dillow @ 2012-09-19 16:59 UTC (permalink / raw)
To: Antonio Ospite
Cc: linux-bluetooth, David Herrmann, Luiz Augusto von Dentz,
Bastien Nocera, linux-input, jkosina
In-Reply-To: <20120919184834.8093076c520dba2dc91c2f5d@studenti.unina.it>
On Wed, 2012-09-19 at 18:48 +0200, Antonio Ospite wrote:
> On Mon, 17 Sep 2012 21:33:58 -0400
> David Dillow <dave@thedillows.org> wrote:
> While on the remote I see:
>
> I press '1' and keep it pressed:
> Event: time 1348069656.505528, type 1 (EV_KEY), code 2 (KEY_1), value 1
> 1111111111...
>
> I press '2' and release it ('1' is sent):
> Event: time 1348069666.025543, type 1 (EV_KEY), code 2 (KEY_1), value 0
> Event: time 1348069668.395531, type 1 (EV_KEY), code 2 (KEY_1), value 1
> 1111111111...
>
> I release '1':
> Event: time 1348069671.625541, type 1 (EV_KEY), code 2 (KEY_1), value 0
>
> I don't know at what level this behavior is enforced.
>
> I will test later with the old raw_event callback and the fix to the
> descriptor you suggested in the other mail.
Please capture the raw reports
from /sys/kernel/debug/hid/0005:*:0306:*/events when pressing multiple
keys -- and tell me which ones they were. You may need to mount debugfs
to get to this path.
It looks like this simple approach isn't going to work when you press
multiple keys, so I'll need more information to see if I can do
something else -- my Harmony can only do one key press at a time, as it
is converting IR to an emulated BD remote.
> > +config HID_PS3REMOTE
> > + tristate "Sony PS3 BD Remote"
>
> If you are going for a v3, consider using "Sony PS3 BD Remote Control"
> here too, not a big deal but that's the name on the user manual.
Will do, thanks.
> For the note about the association procedure I had in mind something
> like this:
>
> /* NOTE: in order to associate the Sony PS3 BD Remote with a Bluetooth host
> * the key combination Start+Enter has to be kept pressed for about 7 seconds,
> * with the host BT Controller in discovering mode.
> *
> * Also the pin request should be ignored by the BT Controller (NULL pin).
> */
>
> Could someone more into BT please check the terminology here? Thanks.
Will add something along these lines, though I think you mean there is
no authentication step rather than a NULL pin, which implies we still
need to do auth. Or maybe that's just how the Harmony needed it...
Thanks,
Dave
^ permalink raw reply
* Re: [PATCH v2] HID: Add support for Sony PS3 BD Remote Control
From: Bastien Nocera @ 2012-09-19 17:05 UTC (permalink / raw)
To: Antonio Ospite
Cc: David Dillow, linux-bluetooth, David Herrmann,
Luiz Augusto von Dentz, linux-input, jkosina
In-Reply-To: <20120919184834.8093076c520dba2dc91c2f5d@studenti.unina.it>
Em Wed, 2012-09-19 às 18:48 +0200, Antonio Ospite escreveu:
> For the note about the association procedure I had in mind something
> like this:
>
> /* NOTE: in order to associate the Sony PS3 BD Remote with a Bluetooth
> host
> * the key combination Start+Enter has to be kept pressed for about 7
> seconds,
> * with the host BT Controller in discovering mode.
> *
> * Also the pin request should be ignored by the BT Controller (NULL
> pin).
> */
>
> Could someone more into BT please check the terminology here? Thanks.
Pairing means that the communication between the 2 Bluetooth devices
will be encrypted. In this case (and as is usually the case for mice),
the communication isn't encrypted, they will just agree to communicate
and the computer will just agree not to ask whether the connection is
allowed at every attempt (favourite/trusted settings depending on the OS
or terminology). There will be no PIN request.
Cheers
^ permalink raw reply
* A2DP optional codecs support
From: Pablo Barrantes @ 2012-09-19 17:31 UTC (permalink / raw)
To: linux-bluetooth
Hi,
I have successfully started audio streaming using A2DP profile from
an Android and iOS device to an embedded system under development. The
embedded system is using bluez, pulseaudio, ALSA and a bluetooth USB
dongle to capture the stream. By default the system is choosing SBC
encodification, but now I would like to use MPEG (AAC and MP3), this is
where it got complicated since I've been looking all around for
documentation or usage cases of A2DP with MPEG codecs with no success.
So here are a some questions I have, hope you can help me with them:
1. First, I'd like to have a better understanding of how will bluez
behave under this circumstances. Assuming that the source (Android or
iOS) is streaming MPEG data, is bluez capable of processing the packages
and then interact with another application (a pulse module maybe?) to
decode and play the data?
2. Related to the previous, my current audio.conf file has this
couple lines that are supposed to enable MPEG:
[A2DP]
SBCSources=0
MPEG12Sources=1
is that correct? Also, is there a way to "force" bluez to choose MPEG
over SBC?
3. How can I know which codec was selected on the negotiation process?
This one isn't directly related to bluez, but is still valid and maybe
somebody on this mailing list can answer it:
4. As mentioned before, I'm using an Android smartphone to stream
data to my embedded system and Android uses bluez to support bluetooth.
Is is possible to stream using MPEG encoded data with such devices?
FYI the kernel/packages version on my system are:
bluez-4.98 (had problems cross-compiling 4.101)
alsa-lib-1.0.25
pulseaudio-2.1
linux-kernel-2.6.32 (pretty old, but it's the one supported ATM)
Thanks in advance,
--Pablo
^ permalink raw reply
* [PATCH BlueZ v0 1/2] input: Remove unneeded header include
From: Claudio Takahasi @ 2012-09-19 19:33 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Claudio Takahasi
---
profiles/input/manager.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/profiles/input/manager.c b/profiles/input/manager.c
index 13096c7..30a3c05 100644
--- a/profiles/input/manager.c
+++ b/profiles/input/manager.c
@@ -39,7 +39,6 @@
#include "../src/profile.h"
#include "device.h"
-#include "hog_device.h"
#include "server.h"
#include "manager.h"
--
1.7.12
^ permalink raw reply related
* [PATCH BlueZ v0 2/2] hog: Add support for multiple instances
From: Claudio Takahasi @ 2012-09-19 19:33 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Claudio Takahasi
In-Reply-To: <1348083222-15294-1-git-send-email-claudio.takahasi@openbossa.org>
This patch adds support for multiple HID services instances exposed by
the same remote device.
---
*** Apply after "[PATCH BlueZ v2 0/6] HoG Suspend/Resume" series
profiles/input/hog_device.c | 90 +++++++++++---------------------------------
profiles/input/hog_device.h | 3 +-
profiles/input/hog_manager.c | 41 ++++++++++++--------
3 files changed, 48 insertions(+), 86 deletions(-)
diff --git a/profiles/input/hog_device.c b/profiles/input/hog_device.c
index e68134c..11ce177 100644
--- a/profiles/input/hog_device.c
+++ b/profiles/input/hog_device.c
@@ -46,13 +46,13 @@
#include "../src/adapter.h"
#include "../src/device.h"
-#include "hog_device.h"
-
#include "att.h"
#include "gattrib.h"
#include "attio.h"
#include "gatt.h"
+#include "hog_device.h"
+
#define HOG_INFO_UUID 0x2A4A
#define HOG_REPORT_MAP_UUID 0x2A4B
#define HOG_REPORT_UUID 0x2A4D
@@ -72,7 +72,7 @@
#define HID_INFO_SIZE 4
struct hog_device {
- char *path;
+ uint16_t id;
struct btd_device *device;
GAttrib *attrib;
guint attioid;
@@ -147,8 +147,8 @@ static void report_value_cb(const uint8_t *pdu, uint16_t len,
if (write(hogdev->uhid_fd, &ev, sizeof(ev)) < 0)
error("uHID write failed: %s", strerror(errno));
else
- DBG("Report from HoG device %s written to uHID fd %d",
- hogdev->path, hogdev->uhid_fd);
+ DBG("Report from HoG device 0x%04X written to uHID fd %d",
+ hogdev->id, hogdev->uhid_fd);
}
static void report_ccc_written_cb(guint8 status, const guint8 *pdu,
@@ -428,14 +428,14 @@ static void proto_mode_read_cb(guint8 status, const guint8 *pdu, guint16 plen,
if (value == HOG_PROTO_MODE_BOOT) {
uint8_t nval = HOG_PROTO_MODE_REPORT;
- DBG("HoG device %s is operating in Boot Procotol Mode",
- hogdev->path);
+ DBG("HoG device 0x%04X is operating in Boot Procotol Mode",
+ hogdev->id);
gatt_write_char(hogdev->attrib, hogdev->proto_mode_handle, &nval,
sizeof(nval), NULL, NULL);
} else if (value == HOG_PROTO_MODE_REPORT)
- DBG("HoG device %s is operating in Report Protocol Mode",
- hogdev->path);
+ DBG("HoG device 0x%04X is operating in Report Protocol Mode",
+ hogdev->id);
}
static void char_discovered_cb(GSList *chars, guint8 status, gpointer user_data)
@@ -548,8 +548,8 @@ static void forward_report(struct hog_device *hogdev,
report = l->data;
- DBG("Sending report type %d to device %s handle 0x%X", type,
- hogdev->path, report->decl->value_handle);
+ DBG("Sending report type %d to device 0x%04X handle 0x%X", type,
+ hogdev->id, report->decl->value_handle);
if (report->decl->properties & ATT_CHAR_PROPER_WRITE)
gatt_write_char(hogdev->attrib, report->decl->value_handle,
@@ -633,20 +633,8 @@ static void attio_disconnected_cb(gpointer user_data)
hogdev->attrib = NULL;
}
-struct hog_device *hog_device_find(GSList *list, const char *path)
-{
- for (; list; list = list->next) {
- struct hog_device *hogdev = list->data;
-
- if (!strcmp(hogdev->path, path))
- return hogdev;
- }
-
- return NULL;
-}
-
static struct hog_device *hog_device_new(struct btd_device *device,
- const char *path)
+ uint16_t id)
{
struct hog_device *hogdev;
@@ -654,31 +642,12 @@ static struct hog_device *hog_device_new(struct btd_device *device,
if (!hogdev)
return NULL;
- hogdev->path = g_strdup(path);
+ hogdev->id = id;
hogdev->device = btd_device_ref(device);
return hogdev;
}
-static gint primary_uuid_cmp(gconstpointer a, gconstpointer b)
-{
- const struct gatt_primary *prim = a;
- const char *uuid = b;
-
- return g_strcmp0(prim->uuid, uuid);
-}
-
-static struct gatt_primary *load_hog_primary(struct btd_device *device)
-{
- GSList *primaries, *l;
-
- primaries = btd_device_get_primaries(device);
-
- l = g_slist_find_custom(primaries, HOG_UUID, primary_uuid_cmp);
-
- return (l ? l->data : NULL);
-}
-
static void report_free(void *data)
{
struct report *report = data;
@@ -690,38 +659,27 @@ static void hog_device_free(struct hog_device *hogdev)
{
btd_device_unref(hogdev->device);
g_slist_free_full(hogdev->reports, report_free);
- g_free(hogdev->path);
g_free(hogdev->hog_primary);
g_free(hogdev);
}
struct hog_device *hog_device_register(struct btd_device *device,
- const char *path, int *perr)
+ struct gatt_primary *prim)
{
- struct gatt_primary *prim;
struct hog_device *hogdev;
GIOCondition cond = G_IO_IN | G_IO_ERR | G_IO_NVAL;
GIOChannel *io;
- int err;
- prim = load_hog_primary(device);
- if (!prim) {
- err = -EINVAL;
- goto failed;
- }
-
- hogdev = hog_device_new(device, path);
- if (!hogdev) {
- err = -ENOMEM;
- goto failed;
- }
+ hogdev = hog_device_new(device, prim->range.start);
+ if (!hogdev)
+ return NULL;
hogdev->uhid_fd = open(UHID_DEVICE_FILE, O_RDWR | O_CLOEXEC);
if (hogdev->uhid_fd < 0) {
- err = -errno;
- error("Failed to open uHID device: %s", strerror(-err));
+ error("Failed to open uHID device: %s(%d)", strerror(errno),
+ errno);
hog_device_free(hogdev);
- goto failed;
+ return NULL;
}
io = g_io_channel_unix_new(hogdev->uhid_fd);
@@ -740,12 +698,6 @@ struct hog_device *hog_device_register(struct btd_device *device,
device_set_auto_connect(device, TRUE);
return hogdev;
-
-failed:
- if (perr)
- *perr = err;
-
- return NULL;
}
int hog_device_unregister(struct hog_device *hogdev)
@@ -779,7 +731,7 @@ int hog_device_set_control_point(struct hog_device *hogdev, gboolean suspend)
if (hogdev->attrib == NULL)
return -ENOTCONN;
- DBG("%s HID Control Point: %s", hogdev->path, suspend ?
+ DBG("0x%4X HID Control Point: %s", hogdev->id, suspend ?
"Suspend" : "Exit Suspend");
if (hogdev->ctrlpt_handle == 0)
diff --git a/profiles/input/hog_device.h b/profiles/input/hog_device.h
index 03f1c90..d1bfc08 100644
--- a/profiles/input/hog_device.h
+++ b/profiles/input/hog_device.h
@@ -28,7 +28,6 @@
struct hog_device;
struct hog_device *hog_device_register(struct btd_device *device,
- const char *path, int *perr);
+ struct gatt_primary *prim);
int hog_device_unregister(struct hog_device *hogdev);
-struct hog_device *hog_device_find(GSList *list, const char *path);
int hog_device_set_control_point(struct hog_device *hogdev, gboolean suspend);
diff --git a/profiles/input/hog_manager.c b/profiles/input/hog_manager.c
index 45c6abf..9145ac5 100644
--- a/profiles/input/hog_manager.c
+++ b/profiles/input/hog_manager.c
@@ -29,6 +29,9 @@
#include <errno.h>
#include <stdbool.h>
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/uuid.h>
+
#include "log.h"
#include "../src/adapter.h"
#include "../src/device.h"
@@ -38,6 +41,9 @@
#include "hcid.h"
#include "device.h"
#include "suspend.h"
+#include "att.h"
+#include "gattrib.h"
+#include "gatt.h"
#include "hog_device.h"
static gboolean suspend_supported = FALSE;
@@ -72,36 +78,41 @@ static void resume_callback(void)
static int hog_device_probe(struct btd_device *device, GSList *uuids)
{
const char *path = device_get_path(device);
- struct hog_device *hogdev;
- int err;
+ GSList *primaries, *l;
DBG("path %s", path);
- hogdev = hog_device_find(devices, path);
- if (hogdev)
- return -EALREADY;
+ primaries = btd_device_get_primaries(device);
+ if (primaries == NULL)
+ return -EINVAL;
- hogdev = hog_device_register(device, path, &err);
- if (hogdev == NULL)
- return err;
+ for (l = primaries; l; l = g_slist_next(l)) {
+ struct gatt_primary *prim = l->data;
+ struct hog_device *hogdev;
- devices = g_slist_append(devices, hogdev);
+ hogdev = hog_device_register(device, prim);
+ if (hogdev == NULL)
+ continue;
+
+ devices = g_slist_append(devices, hogdev);
+ }
return 0;
}
+static void remove_device(gpointer hogdev, gpointer b)
+{
+ devices = g_slist_remove(devices, hogdev);
+ hog_device_unregister(hogdev);
+}
+
static void hog_device_remove(struct btd_device *device)
{
const gchar *path = device_get_path(device);
- struct hog_device *hogdev;
DBG("path %s", path);
- hogdev = hog_device_find(devices, path);
- if (hogdev) {
- devices = g_slist_remove(devices, hogdev);
- hog_device_unregister(hogdev);
- }
+ g_slist_foreach(devices, remove_device, NULL);
}
static struct btd_profile hog_profile = {
--
1.7.12
^ permalink raw reply related
* [PATCH BlueZ v1] gatttool: Fix Characteristic descriptor discovery
From: Claudio Takahasi @ 2012-09-19 19:37 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Claudio Takahasi
In-Reply-To: <CAJdJm_OSzp9i_ox380aFJvrTWwUKUeR2OYeZQDPvoBxSXvYYjw@mail.gmail.com>
This patch fixes end condition for Characteristic Descriptor Discovery.
This sub-procedure is complete when the Error Response is received and
the Error Code is set to Attribute Not Found or the Find Information
Response has an Attribute Handle that is equal to the Ending Handle of
the request.
---
attrib/interactive.c | 22 +++++++++++++---------
1 file changed, 13 insertions(+), 9 deletions(-)
diff --git a/attrib/interactive.c b/attrib/interactive.c
index 1b0edf4..1b0b9cf 100644
--- a/attrib/interactive.c
+++ b/attrib/interactive.c
@@ -48,6 +48,8 @@ static gchar *opt_dst_type = NULL;
static gchar *opt_sec_level = NULL;
static int opt_psm = 0;
static int opt_mtu = 0;
+static int start;
+static int end;
struct characteristic_data {
uint16_t orig_start;
@@ -265,11 +267,12 @@ static void char_desc_cb(guint8 status, const guint8 *pdu, guint16 plen,
{
struct att_data_list *list;
guint8 format;
+ uint16_t handle = 0xffff;
int i;
if (status != 0) {
- printf("Discover all characteristic descriptors failed: "
- "%s\n", att_ecode2str(status));
+ printf("Discover descriptors finished: %s\n",
+ att_ecode2str(status));
return;
}
@@ -280,7 +283,6 @@ static void char_desc_cb(guint8 status, const guint8 *pdu, guint16 plen,
printf("\n");
for (i = 0; i < list->num; i++) {
char uuidstr[MAX_LEN_UUID_STR];
- uint16_t handle;
uint8_t *value;
bt_uuid_t uuid;
@@ -298,7 +300,10 @@ static void char_desc_cb(guint8 status, const guint8 *pdu, guint16 plen,
att_data_list_free(list);
- rl_forced_update_display();
+ if (handle != 0xffff && handle < end)
+ gatt_find_info(attrib, handle + 1, end, char_desc_cb, NULL);
+ else
+ rl_forced_update_display();
}
static void char_read_cb(guint8 status, const guint8 *pdu, guint16 plen,
@@ -527,9 +532,6 @@ static void cmd_char(int argcp, char **argvp)
static void cmd_char_desc(int argcp, char **argvp)
{
- int start = 0x0001;
- int end = 0xffff;
-
if (conn_state != STATE_CONNECTED) {
printf("Command failed: disconnected\n");
return;
@@ -541,7 +543,8 @@ static void cmd_char_desc(int argcp, char **argvp)
printf("Invalid start handle: %s\n", argvp[1]);
return;
}
- }
+ } else
+ start = 0x0001;
if (argcp > 2) {
end = strtohandle(argvp[2]);
@@ -549,7 +552,8 @@ static void cmd_char_desc(int argcp, char **argvp)
printf("Invalid end handle: %s\n", argvp[2]);
return;
}
- }
+ } else
+ end = 0xffff;
gatt_find_info(attrib, start, end, char_desc_cb, NULL);
}
--
1.7.12
^ permalink raw reply related
* Bluez/Obexd upstream test result_20120920(bluez-4.101.319+ obexd-0.47.37)
From: Li, XiaX @ 2012-09-20 3:06 UTC (permalink / raw)
To: linux-bluetooth@vger.kernel.org; +Cc: zhouzhy@neusoft.com
[-- Attachment #1: Type: text/plain, Size: 1306 bytes --]
Hi all,
QA finished upstream testing. The test is for bluez-4.101.319 and obexd-0.47.37. Against last, BlueZ is changed from 4.101.207 to 4.101.319, Obexd is changed from 0.47.22 to 0.47.37.
In this test, totally ran 100 case: 79 Pass, 5 Fail. Other 16 are blocked or unavailable (some cases validation method is still in investigating).
The pass rate is 94% (pass / <pass + fail>). Pulseaudio has not caught up with the BlueZ interface changing in HFP profile.
New bugs:
===============================================
25724 - [HFP] Fail to launch pulseaduio daemon without SBC library
https://bugs.meego.com/show_bug.cgi?id=25724
Re-open bugs:
===============================================
No
Verified bugs:
===============================================
No
Testing Environment
==============================================
Hardware: netbook Eeepc 1005HA | Acer AspireOne NAV50
Image: netbook-ia32-pinetrail-tizen_20120424.2
Linux Kernel: v3.4-rc7
bluez-4.101.319.g7b1bda3-1.1.i586
obexd-0.47.37.g9434ebf-2.1.i586
obexd-server-0.47.37.g9434ebf-2.1.i586
connman-1.6.43.g7b0eb7b-1.1.i586
ofono-1.11.14.gbddfb9b-1.2.i586
Pulseaudio: 2c8aa18b1d95e7486fd2f2a337942795abf0cc37 (sep, 16th)
For detailed test results, please see attached file.
Thanks
Li Xia
[-- Attachment #2: Bluetooth_upstream_quality_20120920.txt --]
[-- Type: text/plain, Size: 7345 bytes --]
== Detail Result ==
[PASS]: case passed <br>
[FAIL]: case failed <br>
[Block]: case is blocked by one bug <br>
[N/A]: case not available to be tested
=== Audio-A2DP ===
[PASS] A2DP_001: audio sink connect/re-connect
[PASS] A2DP_002: stereo headset playback
[PASS] A2DP_003: stereo headset voice record
[PASS] A2DP_004: Codec support: SBC
[PASS] A2DP_005: Playback music on line
[PASS] A2DP_006: SINK role, as speaker for other device music playing
With some BT headset, we ever met issue [https://bugs.meego.com/show_bug.cgi?id=25480 Bug#25480 A2DP-source: pulseaudio fails to create bluez_sink and bluez_source]
=== Audio-AVRCP ===
[PASS] AVRCP_001: Volume Up/Down
[Block] AVRCP_002: Play/Pause (by unavailable media-player)
[Block] AVRCP_003: Next/Privious (by unavailable media-player)
[PASS] AVRCP_004: Connection Establish/Release
[N/A] AVRCP_005: Audio metadata get.
We still try to find avaliable media-player to support AVRCP-1.4
=== Audio-HFP ===
[PASS] HFP_001: RFCOMM connection on AG
Need install sbc for latest pulseaudio
[PASS] HFP_002: list (ofono) hfp modem
[PASS] HFP_003: HFP modem establishment (Ofono)
[FAIL] HFP_004: Audio SNK and SRC establishment
[FAIL] HFP_005: voicecall, audio creates BT SNK/SRC
[FAIL] HFP_006: redirect AG SNK/SRC to local SRC/SNK
BlueZ interface has some regression, bug is reported as [https://bugs.meego.com/show_bug.cgi?id=25473 Bug#25473 HFP: latest bluez cannot support pulseaudio to create bluez_sink and bluez_source]
Pulseaudio has new crash bug: [https://bugs.meego.com/show_bug.cgi?id=25593 Bug#25593 Pulseaudio crashes after connect BT sink to alsa source]
[PASS] HFP_007: Check AT-commands from HF part
[PASS] HFP_008: Connect BT Headset to HFP phone
=== Audio-HSP ===
[PASS] HSP_001: Use mono headset to play music
*** DUT is a Netbook, unable to take phone ***
[N/A] HSP_002: Take incoming call by button-press
[N/A] HSP_003: Audio transfer between AG and HS
[PASS] HSP_004: Adjust Volume Up/Down
=== OBEX-FTP ===
[PASS] FTP_001: pull/push files from/to server.
[PASS] FTP_002: browse server files
[PASS] FTP_003: Client "delete file", "rename file"
[PASS] FTP_004: Server enables FTP parameter
[PASS] FTP_005: Server sets sharing root path
[PASS] FTP_006: Server handles all requirements
[PASS] FTP_007: Server has ability to set permission for FTP
[PASS] FTP_008: FTP data-rate about 30k/s~230k/s
[PASS] FTP_009: Big size file transferred stable
=== OBEX-OPP ===
[PASS] OPP_001: pull un-patterned object from server.
[PASS] OPP_002: Server enables OPP parameter
[PASS] OPP_003: During object transferring, the progress is clear
=== OBEX-PBAP ===
[PASS] PBAP_001: Client gets phone book entries from server
[PASS] PBAP_002: Client gets ICH, OCH, MCH and CCH from server
[FAIL] PBAP_003: PSE can provide PBAP daemon by enabling corresponding parameter
Case failed due to [https://bugs.meego.com/show_bug.cgi?id=25598 Bug#25598, PBAP server fails to open /telecom/pb.vcf file]
[PASS] PBAP_004: Both sides support vCard2.1/vCard3.0
=== OBEX-SYNC ===
[PASS] SYNC_001: Server enables SYNC daemon
[PASS] SYNC_002: During sync, Server can show "syncing..."
[PASS] SYNC_003: client can set PIM fetching from INT
[PASS] SYNC_004: Server get/put entire phonebook from/to client.
[PASS] SYNC_005: Client can support vCard2.1, vCard3.0
=== OBEX-MAP MCE ===
[FAIL] MAP_001: MCE can browse message/folder list on MSE
Regression happened on client side, bug is reported as [https://bugs.meego.com/show_bug.cgi?id=25595 Bug#25595 MAP client fail to get message list from Samsung GT-i9100]
[BLOCK] MAP_002: MCE can upload local message to MSE
[BLOCK] MAP_003: MCE can delete the message on MSE side
[BLOCK] MAP_004: MCE can take use of MSE to send message
=== Network-PAN ===
[PASS] PAN_001: PANU can init nap0 device connect to NAP
[PASS] PAN_002: PANU can get ip address or assigned static ip
[PASS] PAN_003: PANU can logon internet website
[N/A] PAN_004: NAP can init bridge bnep
[N/A] PAN_005: NAP can support one or multiple PANU connection
[N/A] PAN_006: NAP can have DHCP responding to each PANU
Current connman does not support DHCP functions.
=== Network-BNEP ===
[PASS] BNEP_001: Check BNEP support on DUT
=== Networl-DUN ===
[PASS] DUN_001: GW (DUT) can parse a series of AT commands from the data terminal.
[PASS] DUN_002: DT can build up rfcomm device by bluetooth and DUN modem by Ofono.
[PASS] DUN_003: DT can use Ofono to dial up special service number ("*99#").
[PASS] DUN_004: When network connected, DT can log on website in internet.
=== SIM-SAP ===
The SAP test method is still in investigation.
[N/A] SAP_001: Server can enable a module to register Client
[N/A] SAP_002: Server can power on/off SIM Card or reset it
[N/A] SAP_003: Server can disconnect Client
[N/A] SAP_004: Server can disconnect SIM
[N/A] SAP_005: Client can connect to Server SIM
[N/A] SAP_006: Client can power on Server SIM
[N/A] SAP_007: Client can disconnect Server
=== Generic-GAP ===
[PASS] GAP_001: PSCAN/ISCAN mode setting.
[PASS] GAP_002: Active pairing to another bluetooth device.
[PASS] GAP_003: Passive pairing, accepte pair master requirement
[PASS] GAP_004: SSP supports
[PASS] GAP_005: If lost link-key, it needs re-pair
[PASS] GAP_006: reboot DUT with link-key restored, no need to re-pair
[PASS] GAP_007: Pair can be released
=== Generic-SDP ===
[PASS] SDP_001: browse available service list in local
[PASS] SDP_002: browse available service list from remote
[PASS] SDP_003: browse service by RecHandle for detail info
[PASS] SDP_004: Server can answer SDP searching request
[PASS] SDP_005: Server can add/del/update service records
=== Others-HID ===
[PASS] HID_001: Host can search nearby HID device.
[PASS] HID_002: [BAT] Host can connect to HID device.
[PASS] HID_003: Host can handle multiple human input/output devices.
=== HCI ===
[PASS] HCI_001: Build hci connection between Dev_A and Dev_B.
[PASS] HCI_002: Receive ACL data with HCI.
[PASS] HCI_003: Send ACL data with HCI.
[PASS] HCI_004: Change name of remote Dev by HCI.
[PASS] HCI_005: Change class of remote Dev by HCI.
[PASS] HCI_006: Read local HCI controller information.
[PASS] HCI_007: Read remote HCI controller information.
=== L2CAP ===
[PASS] L2CAP_001: Build l2cap connection between Dev_A and Dev_B.
[PASS] L2CAP_002: Dev_A and Dev_B take l2cap protocol to do pingpong.
=== RFCOMM ===
[PASS] RFCOMM_001: Build rfcomm connection between Dev_A and Dev_B.
[PASS] RFCOMM_002: Dev_A and Dev_B take rfcomm protocol to do pingpong.
=== Settings ===
[PASS] SET_001: [BAT] No error output during bluetoothd startup process.
=== Bluetooth Utils ===
Some basic checking for hciconfig, hcitool, sdptool commands.
[PASS] BTCMD_001: hciconfig -a
[PASS] BTCMD_002: hciconfig <adapter> piscan
[PASS] BTCMD_003: hciconfig <adapter> up/down
[PASS] BTCMD_004: hcitool scan
[PASS] BTCMD_005: sdptool browse local
[PASS] BTCMD_006: sdptool browse <ermote MAC>
[PASS] BTCMD_007: sdptool add/del
^ permalink raw reply
* [PATCH v3 00/10] Implement Generic battery and LE Battery client
From: chen.ganir @ 2012-09-20 8:27 UTC (permalink / raw)
To: linux-bluetooth; +Cc: chen.ganir
From: Chen Ganir <chen.ganir@ti.com>
This patch set replaces previous patch sets which implemented the LE battery
GATT Client. This patch set implements a generic device battery D-Bus interface
that can be used to get remote device battery status using D-Bus. In addition,
This patch set also implements the GATT Battery client, which uses the generic
device battery to expose LE device battery status.
see doc/battery-api.txt and doc/device-api.txt for more information.
This is version 2 of the patch set, including multiple style and other comments
reported on the ML. This version is rebased on the latest code.
Chen Ganir (10):
battery: Add generic device battery documentation
battery: Implement Generic device battery
battery: Add GATT Battery Client Service skeleton
battery: Add client connection logic
battery: Discover Characteristic Descriptors
battery: Get Battery ID
battery: Add Battery to device
battery: Read Battery level characteristic
battery: Add support for notifications
battery: Support persistent battery level
Makefile.am | 9 +-
doc/battery-api.txt | 31 +++
doc/device-api.txt | 5 +
lib/uuid.h | 3 +
profiles/battery/battery.c | 594 ++++++++++++++++++++++++++++++++++++++++++++
profiles/battery/battery.h | 24 ++
profiles/battery/main.c | 52 ++++
profiles/battery/manager.c | 62 +++++
profiles/battery/manager.h | 24 ++
src/device.c | 182 ++++++++++++++
src/device.h | 15 ++
test/test-device | 13 +
12 files changed, 1012 insertions(+), 2 deletions(-)
create mode 100644 doc/battery-api.txt
create mode 100644 profiles/battery/battery.c
create mode 100644 profiles/battery/battery.h
create mode 100644 profiles/battery/main.c
create mode 100644 profiles/battery/manager.c
create mode 100644 profiles/battery/manager.h
--
1.7.9.5
^ permalink raw reply
* [PATCH v3 01/10] battery: Add generic device battery documentation
From: chen.ganir @ 2012-09-20 8:27 UTC (permalink / raw)
To: linux-bluetooth; +Cc: chen.ganir
In-Reply-To: <1348129663-1701-1-git-send-email-chen.ganir@ti.com>
From: Chen Ganir <chen.ganir@ti.com>
Add documentation for the generic battery D-Bus interface.
---
doc/battery-api.txt | 31 +++++++++++++++++++++++++++++++
doc/device-api.txt | 5 +++++
2 files changed, 36 insertions(+)
create mode 100644 doc/battery-api.txt
diff --git a/doc/battery-api.txt b/doc/battery-api.txt
new file mode 100644
index 0000000..7e1b94f
--- /dev/null
+++ b/doc/battery-api.txt
@@ -0,0 +1,31 @@
+BlueZ D-Bus Battery API description
+****************************************
+
+ Texas Instruments, Inc. <chen.ganir@ti.com>
+
+Device Battery hierarchy
+=====================================
+
+Service org.bluez
+Interface org.bluez.Battery
+Object path [variable prefix]/{hci0,..}/dev_XX_XX_XX_XX_XX_XX/BATTYYYY
+YYYY is numeric value between 0 and 9999.
+
+Methods dict GetProperties()
+
+ Returns all properties for the interface. See the
+ Properties section for the available properties.
+
+ void Refresh()
+
+ Refresh the batterty level. If the battery level changed, the
+ PropertyChanged signal will be sent with the new value.
+
+Signals PropertyChanged(string name, variant value)
+
+ This signal indicates a changed value of the given
+ property.
+
+Properties uint16 Level [readonly]
+
+ Battery level (0-100).
diff --git a/doc/device-api.txt b/doc/device-api.txt
index 1f0dc96..c98d539 100644
--- a/doc/device-api.txt
+++ b/doc/device-api.txt
@@ -179,3 +179,8 @@ Properties string Address [readonly]
Note that this property can exhibit false-positives
in the case of Bluetooth 2.1 (or newer) devices that
have disabled Extended Inquiry Response support.
+
+ array{object} Batteries [readonly]
+
+ List of device battery object paths that represents the available
+ batteries on the remote device.
--
1.7.9.5
^ permalink raw reply related
* [PATCH v3 02/10] battery: Implement Generic device battery
From: chen.ganir @ 2012-09-20 8:27 UTC (permalink / raw)
To: linux-bluetooth; +Cc: chen.ganir
In-Reply-To: <1348129663-1701-1-git-send-email-chen.ganir@ti.com>
From: Chen Ganir <chen.ganir@ti.com>
Add implementation for the generic battery in bluetooth device.
This patch adds new D-Bus interface for adding/removing/changing
peer device battery status, allowing management of remote device
batteries.
---
src/device.c | 182 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/device.h | 15 +++++
test/test-device | 13 ++++
3 files changed, 210 insertions(+)
diff --git a/src/device.c b/src/device.c
index 77215f1..2e3c738 100644
--- a/src/device.c
+++ b/src/device.c
@@ -167,6 +167,7 @@ struct btd_device {
gboolean authorizing;
gint ref;
+ GSList *batteries;
GIOChannel *att_io;
guint cleanup_id;
@@ -179,6 +180,26 @@ static uint16_t uuid_list[] = {
0
};
+struct btd_battery {
+ DBusConnection *conn;
+ uint16_t level;
+ char *path;
+ struct btd_device *device;
+ refresh_battery_cb refresh;
+};
+
+static void battery_free(gpointer user_data)
+{
+ struct btd_battery *b = user_data;
+
+ g_dbus_unregister_interface(b->conn, b->path, BATTERY_INTERFACE);
+ dbus_connection_unref(b->conn);
+ btd_device_unref(b->device);
+ g_free(b->path);
+ g_free(b);
+
+}
+
static void browse_request_free(struct browse_req *req)
{
if (req->listener_id)
@@ -258,6 +279,7 @@ static void device_free(gpointer user_data)
g_slist_free_full(device->primaries, g_free);
g_slist_free_full(device->attios, g_free);
g_slist_free_full(device->attios_offline, g_free);
+ g_slist_free_full(device->batteries, battery_free);
attio_cleanup(device);
@@ -431,6 +453,15 @@ static DBusMessage *get_properties(DBusConnection *conn,
ptr = adapter_get_path(adapter);
dict_append_entry(&dict, "Adapter", DBUS_TYPE_OBJECT_PATH, &ptr);
+ /* Batteries */
+ str = g_new0(char *, g_slist_length(device->batteries) + 1);
+ for (i = 0, l = device->batteries; l; l = l->next, i++) {
+ struct btd_battery *b = l->data;
+ str[i] = b->path;
+ }
+ dict_append_array(&dict, "Batteries", DBUS_TYPE_OBJECT_PATH, &str, i);
+ g_free(str);
+
dbus_message_iter_close_container(&iter, &dict);
return reply;
@@ -3224,3 +3255,154 @@ void device_set_pnpid(struct btd_device *device, uint8_t vendor_id_src,
device_set_version(device, product_ver);
}
+static void batteries_changed(struct btd_device *device)
+{
+ DBusConnection *conn = get_dbus_connection();
+ char **batteries;
+ GSList *l;
+ int i;
+
+ batteries = g_new0(char *, g_slist_length(device->batteries) + 1);
+ for (i = 0, l = device->batteries; l; l = l->next, i++) {
+ struct btd_battery *batt = l->data;
+ batteries[i] = batt->path;
+ }
+
+ emit_array_property_changed(conn, device->path, DEVICE_INTERFACE,
+ "Batteries", DBUS_TYPE_OBJECT_PATH,
+ &batteries, i);
+
+ g_free(batteries);
+}
+
+static DBusMessage *refresh_batt_level(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct btd_battery *b = data;
+
+ if (!b->refresh)
+ return btd_error_not_supported(msg);
+
+ b->refresh(b);
+
+ return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *get_batt_properties(DBusConnection *conn,
+ DBusMessage *msg, void *data)
+{
+ struct btd_battery *b = data;
+ DBusMessageIter iter;
+ DBusMessageIter dict;
+ DBusMessage *reply;
+
+ reply = dbus_message_new_method_return(msg);
+ if (reply == NULL)
+ return NULL;
+
+ dbus_message_iter_init_append(reply, &iter);
+
+ dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+ DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+ DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
+ DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
+
+ dict_append_entry(&dict, "Level", DBUS_TYPE_UINT16, &b->level);
+
+ dbus_message_iter_close_container(&iter, &dict);
+
+ return reply;
+}
+
+static GDBusMethodTable battery_methods[] = {
+ { GDBUS_METHOD("GetProperties",
+ NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
+ get_batt_properties) },
+ { GDBUS_METHOD("Refresh",
+ NULL, NULL,
+ refresh_batt_level) },
+ { }
+};
+
+static GDBusSignalTable battery_signals[] = {
+ { GDBUS_SIGNAL("PropertyChanged",
+ GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
+ { }
+};
+
+struct btd_battery *btd_device_add_battery(struct btd_device *device)
+{
+ struct btd_battery *batt;
+ DBusConnection *conn = get_dbus_connection();
+
+ batt = g_new0(struct btd_battery, 1);
+ batt->path = g_strdup_printf("%s/BATT%04X", device->path,
+ g_slist_length(device->batteries));
+ batt->conn = dbus_connection_ref(conn);
+
+ if (!g_dbus_register_interface(batt->conn, batt->path,
+ BATTERY_INTERFACE, battery_methods, battery_signals,
+ NULL, batt, NULL)) {
+ error("D-Bus register interface %s failed", BATTERY_INTERFACE);
+ dbus_connection_unref(batt->conn);
+ g_free(batt->path);
+ g_free(batt);
+ return NULL;
+ }
+
+ batt->device = btd_device_ref(device);
+ device->batteries = g_slist_append(device->batteries, batt);
+ batteries_changed(device);
+
+ return batt;
+}
+
+void btd_device_remove_battery(struct btd_battery *batt)
+{
+ struct btd_device *dev = batt->device;
+
+ dev->batteries = g_slist_remove(dev->batteries, batt);
+
+ battery_free(batt);
+
+ batteries_changed(dev);
+}
+
+gboolean btd_device_set_battery_opt(struct btd_battery *batt,
+ battery_option_t opt1, ...)
+{
+ va_list args;
+ battery_option_t opt = opt1;
+ int level;
+
+ if (!batt)
+ return FALSE;
+
+ va_start(args, opt1);
+
+ while (opt != BATTERY_OPT_INVALID) {
+ switch (opt) {
+ case BATTERY_OPT_LEVEL:
+ level = va_arg(args, int);
+ if (level != batt->level) {
+ batt->level = level;
+ emit_property_changed(batt->conn, batt->path,
+ BATTERY_INTERFACE, "Level",
+ DBUS_TYPE_UINT16, &level);
+ }
+ break;
+ case BATTERY_OPT_REFRESH_FUNC:
+ batt->refresh = va_arg(args, refresh_battery_cb);
+ break;
+ default:
+ error("Unknown option %d", opt);
+ return FALSE;
+ }
+
+ opt = va_arg(args, int);
+ }
+
+ va_end(args);
+
+ return TRUE;
+}
diff --git a/src/device.h b/src/device.h
index 9426ef8..f1662ca 100644
--- a/src/device.h
+++ b/src/device.h
@@ -23,8 +23,10 @@
*/
#define DEVICE_INTERFACE "org.bluez.Device"
+#define BATTERY_INTERFACE "org.bluez.Battery"
struct btd_device;
+struct btd_battery;
typedef enum {
AUTH_TYPE_PINCODE,
@@ -34,6 +36,14 @@ typedef enum {
AUTH_TYPE_NOTIFY_PINCODE,
} auth_type_t;
+typedef void (*refresh_battery_cb) (struct btd_battery *batt);
+
+typedef enum {
+ BATTERY_OPT_INVALID = 0,
+ BATTERY_OPT_LEVEL,
+ BATTERY_OPT_REFRESH_FUNC,
+} battery_option_t;
+
struct btd_device *device_create(DBusConnection *conn,
struct btd_adapter *adapter,
const char *address, uint8_t bdaddr_type);
@@ -127,3 +137,8 @@ int device_unblock(DBusConnection *conn, struct btd_device *device,
void device_set_pnpid(struct btd_device *device, uint8_t vendor_id_src,
uint16_t vendor_id, uint16_t product_id,
uint16_t product_ver);
+
+struct btd_battery *btd_device_add_battery(struct btd_device *device);
+void btd_device_remove_battery(struct btd_battery *batt);
+gboolean btd_device_set_battery_opt(struct btd_battery *batt,
+ battery_option_t opt1, ...);
diff --git a/test/test-device b/test/test-device
index 63a96d3..7edb7b8 100755
--- a/test/test-device
+++ b/test/test-device
@@ -37,6 +37,7 @@ if (len(args) < 1):
print("")
print(" list")
print(" services <address>")
+ print(" batteries <address>")
print(" create <address>")
print(" remove <address|path>")
print(" disconnect <address>")
@@ -205,5 +206,17 @@ if (args[0] == "services"):
print(path)
sys.exit(0)
+if (args[0] == "batteries"):
+ if (len(args) < 2):
+ print("Need address parameter")
+ else:
+ path = adapter.FindDevice(args[1])
+ device = dbus.Interface(bus.get_object("org.bluez", path),
+ "org.bluez.Device")
+ properties = device.GetProperties()
+ for path in properties["Batteries"]:
+ print(path)
+ sys.exit(0)
+
print("Unknown command")
sys.exit(1)
--
1.7.9.5
^ permalink raw reply related
* [PATCH v3 03/10] battery: Add GATT Battery Client Service skeleton
From: chen.ganir @ 2012-09-20 8:27 UTC (permalink / raw)
To: linux-bluetooth; +Cc: chen.ganir
In-Reply-To: <1348129663-1701-1-git-send-email-chen.ganir@ti.com>
From: Chen Ganir <chen.ganir@ti.com>
Add support for the Battery Service Gatt Client side. Implement
the basic skeleton.
---
Makefile.am | 9 ++++-
lib/uuid.h | 2 +
profiles/battery/battery.c | 89 ++++++++++++++++++++++++++++++++++++++++++++
profiles/battery/battery.h | 24 ++++++++++++
profiles/battery/main.c | 52 ++++++++++++++++++++++++++
profiles/battery/manager.c | 62 ++++++++++++++++++++++++++++++
profiles/battery/manager.h | 24 ++++++++++++
7 files changed, 260 insertions(+), 2 deletions(-)
create mode 100644 profiles/battery/battery.c
create mode 100644 profiles/battery/battery.h
create mode 100644 profiles/battery/main.c
create mode 100644 profiles/battery/manager.c
create mode 100644 profiles/battery/manager.h
diff --git a/Makefile.am b/Makefile.am
index 372111a..21b5ebf 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -211,7 +211,7 @@ endif
if GATTMODULES
builtin_modules += thermometer alert time gatt_example proximity deviceinfo \
- gatt
+ gatt battery
builtin_sources += profiles/thermometer/main.c \
profiles/thermometer/manager.h \
profiles/thermometer/manager.c \
@@ -240,7 +240,12 @@ builtin_sources += profiles/thermometer/main.c \
profiles/deviceinfo/deviceinfo.c \
profiles/gatt/main.c profiles/gatt/manager.h \
profiles/gatt/manager.c profiles/gatt/gas.h \
- profiles/gatt/gas.c
+ profiles/gatt/gas.c \
+ profiles/battery/main.c \
+ profiles/battery/manager.c \
+ profiles/battery/manager.h \
+ profiles/battery/battery.c \
+ profiles/battery/battery.h
endif
builtin_modules += formfactor
diff --git a/lib/uuid.h b/lib/uuid.h
index aa6efdf..58ad0b3 100644
--- a/lib/uuid.h
+++ b/lib/uuid.h
@@ -56,6 +56,8 @@ extern "C" {
#define PNPID_UUID "00002a50-0000-1000-8000-00805f9b34fb"
#define DEVICE_INFORMATION_UUID "0000180a-0000-1000-8000-00805f9b34fb"
+#define BATTERY_SERVICE_UUID "0000180f-0000-1000-8000-00805f9b34fb"
+
#define GATT_UUID "00001801-0000-1000-8000-00805f9b34fb"
#define IMMEDIATE_ALERT_UUID "00001802-0000-1000-8000-00805f9b34fb"
#define LINK_LOSS_UUID "00001803-0000-1000-8000-00805f9b34fb"
diff --git a/profiles/battery/battery.c b/profiles/battery/battery.c
new file mode 100644
index 0000000..7702e39
--- /dev/null
+++ b/profiles/battery/battery.c
@@ -0,0 +1,89 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2012 Texas Instruments, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib.h>
+#include <bluetooth/uuid.h>
+#include <stdbool.h>
+
+#include "adapter.h"
+#include "device.h"
+#include "att.h"
+#include "gattrib.h"
+#include "gatt.h"
+#include "battery.h"
+
+struct battery {
+ struct btd_device *dev; /* Device reference */
+};
+
+static GSList *servers;
+
+static gint cmp_device(gconstpointer a, gconstpointer b)
+{
+ const struct battery *batt = a;
+ const struct btd_device *dev = b;
+
+ if (dev == batt->dev)
+ return 0;
+
+ return -1;
+}
+
+static void battery_free(gpointer user_data)
+{
+ struct battery *batt = user_data;
+
+ btd_device_unref(batt->dev);
+ g_free(batt);
+}
+
+
+int battery_register(struct btd_device *device)
+{
+ struct battery *batt;
+
+ batt = g_new0(struct battery, 1);
+ batt->dev = btd_device_ref(device);
+
+ servers = g_slist_prepend(servers, batt);
+
+ return 0;
+}
+
+void battery_unregister(struct btd_device *device)
+{
+ struct battery *batt;
+ GSList *l;
+
+ l = g_slist_find_custom(servers, device, cmp_device);
+ if (l == NULL)
+ return;
+
+ batt = l->data;
+ servers = g_slist_remove(servers, batt);
+
+ battery_free(batt);
+}
diff --git a/profiles/battery/battery.h b/profiles/battery/battery.h
new file mode 100644
index 0000000..9933343
--- /dev/null
+++ b/profiles/battery/battery.h
@@ -0,0 +1,24 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2012 Texas Instruments, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+int battery_register(struct btd_device *device);
+void battery_unregister(struct btd_device *device);
diff --git a/profiles/battery/main.c b/profiles/battery/main.c
new file mode 100644
index 0000000..d4a23c9
--- /dev/null
+++ b/profiles/battery/main.c
@@ -0,0 +1,52 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2012 Texas Instruments, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdint.h>
+#include <glib.h>
+#include <errno.h>
+
+#include "hcid.h"
+#include "plugin.h"
+#include "manager.h"
+#include "log.h"
+
+static int battery_init(void)
+{
+ if (!main_opts.gatt_enabled) {
+ error("GATT is disabled");
+ return -ENOTSUP;
+ }
+
+ return battery_manager_init();
+}
+
+static void battery_exit(void)
+{
+ battery_manager_exit();
+}
+
+BLUETOOTH_PLUGIN_DEFINE(battery, VERSION, BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
+ battery_init, battery_exit)
diff --git a/profiles/battery/manager.c b/profiles/battery/manager.c
new file mode 100644
index 0000000..9abb31a
--- /dev/null
+++ b/profiles/battery/manager.c
@@ -0,0 +1,62 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2012 Texas Instruments, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <glib.h>
+#include <errno.h>
+#include <bluetooth/uuid.h>
+#include <stdbool.h>
+
+#include "adapter.h"
+#include "device.h"
+#include "profile.h"
+#include "att.h"
+#include "gattrib.h"
+#include "gatt.h"
+#include "battery.h"
+#include "manager.h"
+
+static int battery_driver_probe(struct btd_device *device, GSList *uuids)
+{
+ return battery_register(device);
+}
+
+static void battery_driver_remove(struct btd_device *device)
+{
+ battery_unregister(device);
+}
+
+static struct btd_profile battery_profile = {
+ .name = "battery",
+ .remote_uuids = BTD_UUIDS(BATTERY_SERVICE_UUID),
+ .device_probe = battery_driver_probe,
+ .device_remove = battery_driver_remove
+};
+
+int battery_manager_init(void)
+{
+ return btd_profile_register(&battery_profile);
+}
+
+void battery_manager_exit(void)
+{
+ btd_profile_unregister(&battery_profile);
+}
diff --git a/profiles/battery/manager.h b/profiles/battery/manager.h
new file mode 100644
index 0000000..b2c849f
--- /dev/null
+++ b/profiles/battery/manager.h
@@ -0,0 +1,24 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ *
+ * Copyright (C) 2012 Texas Instruments, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+int battery_manager_init(void);
+void battery_manager_exit(void);
--
1.7.9.5
^ permalink raw reply related
* [PATCH v3 04/10] battery: Add client connection logic
From: chen.ganir @ 2012-09-20 8:27 UTC (permalink / raw)
To: linux-bluetooth; +Cc: chen.ganir
In-Reply-To: <1348129663-1701-1-git-send-email-chen.ganir@ti.com>
From: Chen Ganir <chen.ganir@ti.com>
Add connection logic to the Battery Plugin. When the driver is
loaded, it will request a connection to the remote device and
release the connection request when destroyed.
---
profiles/battery/battery.c | 90 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 90 insertions(+)
diff --git a/profiles/battery/battery.c b/profiles/battery/battery.c
index 7702e39..5e52275 100644
--- a/profiles/battery/battery.c
+++ b/profiles/battery/battery.c
@@ -30,17 +30,28 @@
#include "adapter.h"
#include "device.h"
+#include "gattrib.h"
+#include "attio.h"
#include "att.h"
#include "gattrib.h"
#include "gatt.h"
#include "battery.h"
+#include "log.h"
struct battery {
struct btd_device *dev; /* Device reference */
+ GAttrib *attrib; /* GATT connection */
+ guint attioid; /* Att watcher id */
+ struct att_range *svc_range; /* Battery range */
+ GSList *chars; /* Characteristics */
};
static GSList *servers;
+struct characteristic {
+ struct gatt_char attr; /* Characteristic */
+ struct battery *batt; /* Parent Battery Service */
+};
static gint cmp_device(gconstpointer a, gconstpointer b)
{
const struct battery *batt = a;
@@ -56,20 +67,99 @@ static void battery_free(gpointer user_data)
{
struct battery *batt = user_data;
+ if (batt->chars != NULL)
+ g_slist_free_full(batt->chars, g_free);
+
+ if (batt->attioid > 0)
+ btd_device_remove_attio_callback(batt->dev, batt->attioid);
+
+ if (batt->attrib != NULL)
+ g_attrib_unref(batt->attrib);
+
btd_device_unref(batt->dev);
g_free(batt);
}
+static void configure_battery_cb(GSList *characteristics, guint8 status,
+ gpointer user_data)
+{
+ struct battery *batt = user_data;
+ GSList *l;
+
+ if (status != 0) {
+ error("Discover Battery characteristics: %s",
+ att_ecode2str(status));
+ return;
+ }
+
+ for (l = characteristics; l; l = l->next) {
+ struct gatt_char *c = l->data;
+ struct characteristic *ch;
+
+ ch = g_new0(struct characteristic, 1);
+ ch->attr.handle = c->handle;
+ ch->attr.properties = c->properties;
+ ch->attr.value_handle = c->value_handle;
+ memcpy(ch->attr.uuid, c->uuid, MAX_LEN_UUID_STR + 1);
+ ch->batt = batt;
+
+ batt->chars = g_slist_append(batt->chars, ch);
+ }
+}
+
+static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
+{
+ struct battery *batt = user_data;
+
+ batt->attrib = g_attrib_ref(attrib);
+
+ if (batt->chars == NULL) {
+ gatt_discover_char(batt->attrib, batt->svc_range->start,
+ batt->svc_range->end, NULL,
+ configure_battery_cb, batt);
+ }
+}
+
+static void attio_disconnected_cb(gpointer user_data)
+{
+ struct battery *batt = user_data;
+
+ g_attrib_unref(batt->attrib);
+ batt->attrib = NULL;
+}
+
+static gint primary_uuid_cmp(gconstpointer a, gconstpointer b)
+{
+ const struct gatt_primary *prim = a;
+ const char *uuid = b;
+
+ return g_strcmp0(prim->uuid, uuid);
+}
int battery_register(struct btd_device *device)
{
struct battery *batt;
+ struct gatt_primary *prim;
+ GSList *primaries, *l;
+
+ primaries = btd_device_get_primaries(device);
+
+ l = g_slist_find_custom(primaries, BATTERY_SERVICE_UUID,
+ primary_uuid_cmp);
+ prim = l->data;
batt = g_new0(struct battery, 1);
batt->dev = btd_device_ref(device);
+ batt->svc_range = g_new0(struct att_range, 1);
+ batt->svc_range->start = prim->range.start;
+ batt->svc_range->end = prim->range.end;
+
servers = g_slist_prepend(servers, batt);
+ batt->attioid = btd_device_add_attio_callback(device,
+ attio_connected_cb, attio_disconnected_cb,
+ batt);
return 0;
}
--
1.7.9.5
^ permalink raw reply related
* [PATCH v3 05/10] battery: Discover Characteristic Descriptors
From: chen.ganir @ 2012-09-20 8:27 UTC (permalink / raw)
To: linux-bluetooth; +Cc: chen.ganir
In-Reply-To: <1348129663-1701-1-git-send-email-chen.ganir@ti.com>
From: Chen Ganir <chen.ganir@ti.com>
Discover all characteristic descriptors, and build a descriptor
list. Presentation Format Descriptor and Client Characteristic
Configuration descriptors are searched.
---
profiles/battery/battery.c | 73 +++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 72 insertions(+), 1 deletion(-)
diff --git a/profiles/battery/battery.c b/profiles/battery/battery.c
index 5e52275..dada15b 100644
--- a/profiles/battery/battery.c
+++ b/profiles/battery/battery.c
@@ -51,7 +51,15 @@ static GSList *servers;
struct characteristic {
struct gatt_char attr; /* Characteristic */
struct battery *batt; /* Parent Battery Service */
+ GSList *desc; /* Descriptors */
};
+
+struct descriptor {
+ struct characteristic *ch; /* Parent Characteristic */
+ uint16_t handle; /* Descriptor Handle */
+ bt_uuid_t uuid; /* UUID */
+};
+
static gint cmp_device(gconstpointer a, gconstpointer b)
{
const struct battery *batt = a;
@@ -63,12 +71,21 @@ static gint cmp_device(gconstpointer a, gconstpointer b)
return -1;
}
+static void char_free(gpointer user_data)
+{
+ struct characteristic *c = user_data;
+
+ g_slist_free_full(c->desc, g_free);
+
+ g_free(c);
+}
+
static void battery_free(gpointer user_data)
{
struct battery *batt = user_data;
if (batt->chars != NULL)
- g_slist_free_full(batt->chars, g_free);
+ g_slist_free_full(batt->chars, char_free);
if (batt->attioid > 0)
btd_device_remove_attio_callback(batt->dev, batt->attioid);
@@ -77,9 +94,48 @@ static void battery_free(gpointer user_data)
g_attrib_unref(batt->attrib);
btd_device_unref(batt->dev);
+ g_free(batt->svc_range);
g_free(batt);
}
+static void discover_desc_cb(guint8 status, const guint8 *pdu, guint16 len,
+ gpointer user_data)
+{
+ struct characteristic *ch = user_data;
+ struct att_data_list *list;
+ uint8_t format;
+ int i;
+
+ if (status != 0) {
+ error("Discover all characteristic descriptors failed [%s]: %s",
+ ch->attr.uuid, att_ecode2str(status));
+ return;
+ }
+
+ list = dec_find_info_resp(pdu, len, &format);
+ if (list == NULL)
+ return;
+
+ for (i = 0; i < list->num; i++) {
+ struct descriptor *desc;
+ uint8_t *value;
+
+ value = list->data[i];
+ desc = g_new0(struct descriptor, 1);
+ desc->handle = att_get_u16(value);
+ desc->ch = ch;
+
+ if (format == 0x01)
+ desc->uuid = att_get_uuid16(&value[2]);
+ else
+ desc->uuid = att_get_uuid128(&value[2]);
+
+ ch->desc = g_slist_append(ch->desc, desc);
+ }
+
+ att_data_list_free(list);
+}
+
static void configure_battery_cb(GSList *characteristics, guint8 status,
gpointer user_data)
{
@@ -95,6 +151,7 @@ static void configure_battery_cb(GSList *characteristics, guint8 status,
for (l = characteristics; l; l = l->next) {
struct gatt_char *c = l->data;
struct characteristic *ch;
+ uint16_t start, end;
ch = g_new0(struct characteristic, 1);
ch->attr.handle = c->handle;
@@ -104,6 +161,20 @@ static void configure_battery_cb(GSList *characteristics, guint8 status,
ch->batt = batt;
batt->chars = g_slist_append(batt->chars, ch);
+
+ start = c->value_handle + 1;
+
+ if (l->next != NULL) {
+ struct gatt_char *c = l->next->data;
+ if (start == c->handle)
+ continue;
+ end = c->handle - 1;
+ } else if (c->value_handle != batt->svc_range->end)
+ end = batt->svc_range->end;
+ else
+ continue;
+
+ gatt_find_info(batt->attrib, start, end, discover_desc_cb, ch);
}
}
--
1.7.9.5
^ permalink raw reply related
* [PATCH v3 06/10] battery: Get Battery ID
From: chen.ganir @ 2012-09-20 8:27 UTC (permalink / raw)
To: linux-bluetooth; +Cc: chen.ganir
In-Reply-To: <1348129663-1701-1-git-send-email-chen.ganir@ti.com>
From: Chen Ganir <chen.ganir@ti.com>
Read the battery level format characteristic descriptor to get the
unique namespace and description values.
---
lib/uuid.h | 1 +
profiles/battery/battery.c | 98 ++++++++++++++++++++++++++++++++++----------
2 files changed, 77 insertions(+), 22 deletions(-)
diff --git a/lib/uuid.h b/lib/uuid.h
index 58ad0b3..5c1b3ff 100644
--- a/lib/uuid.h
+++ b/lib/uuid.h
@@ -57,6 +57,7 @@ extern "C" {
#define DEVICE_INFORMATION_UUID "0000180a-0000-1000-8000-00805f9b34fb"
#define BATTERY_SERVICE_UUID "0000180f-0000-1000-8000-00805f9b34fb"
+#define BATTERY_LEVEL_UUID "00002a19-0000-1000-8000-00805f9b34fb"
#define GATT_UUID "00001801-0000-1000-8000-00805f9b34fb"
#define IMMEDIATE_ALERT_UUID "00001802-0000-1000-8000-00805f9b34fb"
diff --git a/profiles/battery/battery.c b/profiles/battery/battery.c
index dada15b..a3a1bb0 100644
--- a/profiles/battery/battery.c
+++ b/profiles/battery/battery.c
@@ -52,6 +52,8 @@ struct characteristic {
struct gatt_char attr; /* Characteristic */
struct battery *batt; /* Parent Battery Service */
GSList *desc; /* Descriptors */
+ uint8_t ns; /* Battery Namespace */
+ uint16_t description; /* Battery description */
};
struct descriptor {
@@ -98,6 +100,53 @@ static void battery_free(gpointer user_data)
g_free(batt);
}
+static void batterylevel_presentation_format_desc_cb(guint8 status,
+ const guint8 *pdu, guint16 len,
+ gpointer user_data)
+{
+ struct descriptor *desc = user_data;
+ uint8_t value[ATT_MAX_MTU];
+ int vlen;
+
+ if (status != 0) {
+ error("Presentation Format desc read failed: %s",
+ att_ecode2str(status));
+ return;
+ }
+
+ vlen = dec_read_resp(pdu, len, value, sizeof(value));
+ if (vlen < 0) {
+ error("Presentation Format desc read failed: Protocol error");
+ return;
+ }
+
+ if (vlen < 7) {
+ error("Presentation Format desc read failed: Invalid range");
+ return;
+ }
+
+ desc->ch->ns = value[4];
+ desc->ch->description = att_get_u16(&value[5]);
+}
+
+static void process_batterylevel_desc(struct descriptor *desc)
+{
+ struct characteristic *ch = desc->ch;
+ char uuidstr[MAX_LEN_UUID_STR];
+ bt_uuid_t btuuid;
+
+ bt_uuid16_create(&btuuid, GATT_CHARAC_FMT_UUID);
+
+ if (bt_uuid_cmp(&desc->uuid, &btuuid) == 0) {
+ gatt_read_char(ch->batt->attrib, desc->handle, 0,
+ batterylevel_presentation_format_desc_cb, desc);
+ return;
+ }
+
+ bt_uuid_to_string(&desc->uuid, uuidstr, MAX_LEN_UUID_STR);
+ DBG("Ignored descriptor %s characteristic %s", uuidstr, ch->attr.uuid);
+}
+
static void discover_desc_cb(guint8 status, const guint8 *pdu, guint16 len,
gpointer user_data)
{
@@ -131,6 +180,7 @@ static void discover_desc_cb(guint8 status, const guint8 *pdu, guint16 len,
desc->uuid = att_get_uuid128(&value[2]);
ch->desc = g_slist_append(ch->desc, desc);
+ process_batterylevel_desc(desc);
}
att_data_list_free(list);
@@ -150,31 +200,35 @@ static void configure_battery_cb(GSList *characteristics, guint8 status,
for (l = characteristics; l; l = l->next) {
struct gatt_char *c = l->data;
- struct characteristic *ch;
- uint16_t start, end;
-
- ch = g_new0(struct characteristic, 1);
- ch->attr.handle = c->handle;
- ch->attr.properties = c->properties;
- ch->attr.value_handle = c->value_handle;
- memcpy(ch->attr.uuid, c->uuid, MAX_LEN_UUID_STR + 1);
- ch->batt = batt;
- batt->chars = g_slist_append(batt->chars, ch);
-
- start = c->value_handle + 1;
-
- if (l->next != NULL) {
- struct gatt_char *c = l->next->data;
- if (start == c->handle)
+ if (g_strcmp0(c->uuid, BATTERY_LEVEL_UUID) == 0) {
+ struct characteristic *ch;
+ uint16_t start, end;
+
+ ch = g_new0(struct characteristic, 1);
+ ch->attr.handle = c->handle;
+ ch->attr.properties = c->properties;
+ ch->attr.value_handle = c->value_handle;
+ memcpy(ch->attr.uuid, c->uuid, MAX_LEN_UUID_STR + 1);
+ ch->batt = batt;
+
+ batt->chars = g_slist_append(batt->chars, ch);
+
+ start = c->value_handle + 1;
+
+ if (l->next != NULL) {
+ struct gatt_char *c = l->next->data;
+ if (start == c->handle)
+ continue;
+ end = c->handle - 1;
+ } else if (c->value_handle != batt->svc_range->end)
+ end = batt->svc_range->end;
+ else
continue;
- end = c->handle - 1;
- } else if (c->value_handle != batt->svc_range->end)
- end = batt->svc_range->end;
- else
- continue;
- gatt_find_info(batt->attrib, start, end, discover_desc_cb, ch);
+ gatt_find_info(batt->attrib, start, end,
+ discover_desc_cb, ch);
+ }
}
}
--
1.7.9.5
^ permalink raw reply related
* [PATCH v3 07/10] battery: Add Battery to device
From: chen.ganir @ 2012-09-20 8:27 UTC (permalink / raw)
To: linux-bluetooth; +Cc: chen.ganir
In-Reply-To: <1348129663-1701-1-git-send-email-chen.ganir@ti.com>
From: Chen Ganir <chen.ganir@ti.com>
Add/Remove battery from device
---
profiles/battery/battery.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/profiles/battery/battery.c b/profiles/battery/battery.c
index a3a1bb0..6a6635b 100644
--- a/profiles/battery/battery.c
+++ b/profiles/battery/battery.c
@@ -49,6 +49,7 @@ struct battery {
static GSList *servers;
struct characteristic {
+ struct btd_battery *devbatt; /* device_battery pointer */
struct gatt_char attr; /* Characteristic */
struct battery *batt; /* Parent Battery Service */
GSList *desc; /* Descriptors */
@@ -79,6 +80,8 @@ static void char_free(gpointer user_data)
g_slist_free_full(c->desc, g_free);
+ btd_device_remove_battery(c->devbatt);
+
g_free(c);
}
@@ -216,6 +219,8 @@ static void configure_battery_cb(GSList *characteristics, guint8 status,
start = c->value_handle + 1;
+ ch->devbatt = btd_device_add_battery(ch->batt->dev);
+
if (l->next != NULL) {
struct gatt_char *c = l->next->data;
if (start == c->handle)
--
1.7.9.5
^ permalink raw reply related
* [PATCH v3 08/10] battery: Read Battery level characteristic
From: chen.ganir @ 2012-09-20 8:27 UTC (permalink / raw)
To: linux-bluetooth; +Cc: chen.ganir
In-Reply-To: <1348129663-1701-1-git-send-email-chen.ganir@ti.com>
From: Chen Ganir <chen.ganir@ti.com>
Implement support for reading the battery level characteristic on
connection establishment.
---
profiles/battery/battery.c | 86 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 86 insertions(+)
diff --git a/profiles/battery/battery.c b/profiles/battery/battery.c
index 6a6635b..d681e2d 100644
--- a/profiles/battery/battery.c
+++ b/profiles/battery/battery.c
@@ -55,6 +55,7 @@ struct characteristic {
GSList *desc; /* Descriptors */
uint8_t ns; /* Battery Namespace */
uint16_t description; /* Battery description */
+ uint8_t level; /* Battery level */
};
struct descriptor {
@@ -103,6 +104,78 @@ static void battery_free(gpointer user_data)
g_free(batt);
}
+static void read_batterylevel_cb(guint8 status, const guint8 *pdu, guint16 len,
+ gpointer user_data)
+{
+ struct characteristic *ch = user_data;
+ uint8_t value[ATT_MAX_MTU];
+ int vlen;
+
+ if (status != 0) {
+ error("Failed to read Battery Level:%s", att_ecode2str(status));
+ return;
+ }
+
+ vlen = dec_read_resp(pdu, len, value, sizeof(value));
+ if (vlen < 0) {
+ error("Failed to read Battery Level: Protocol error");
+ return;
+ }
+
+ if (vlen != 1) {
+ error("Failed to read Battery Level: Wrong pdu len");
+ return;
+ }
+
+ ch->level = value[0];
+ btd_device_set_battery_opt(ch->devbatt, BATTERY_OPT_LEVEL, ch->level,
+ BATTERY_OPT_INVALID);
+}
+
+static void process_batteryservice_char(struct characteristic *ch)
+{
+ if (g_strcmp0(ch->attr.uuid, BATTERY_LEVEL_UUID) == 0) {
+ gatt_read_char(ch->batt->attrib, ch->attr.value_handle, 0,
+ read_batterylevel_cb, ch);
+ }
+}
+
+static gint device_battery_cmp(gconstpointer a, gconstpointer b)
+{
+ const struct characteristic *ch = a;
+ const struct btd_battery *batt = b;
+
+ if (batt == ch->devbatt)
+ return 0;
+
+ return -1;
+}
+
+static struct characteristic *find_battery_char(struct btd_battery *db)
+{
+ GSList *l, *b;
+
+ for (l = servers; l != NULL; l = g_slist_next(l)) {
+ struct battery *batt = l->data;
+
+ b = g_slist_find_custom(batt->chars, db, device_battery_cmp);
+ if (b)
+ return b->data;
+ }
+
+ return NULL;
+}
+
+static void batterylevel_refresh_cb(struct btd_battery *batt)
+{
+ struct characteristic *ch;
+
+ ch = find_battery_char(batt);
+
+ if (ch)
+ process_batteryservice_char(ch);
+}
+
static void batterylevel_presentation_format_desc_cb(guint8 status,
const guint8 *pdu, guint16 len,
gpointer user_data)
@@ -219,8 +292,15 @@ static void configure_battery_cb(GSList *characteristics, guint8 status,
start = c->value_handle + 1;
+ process_batteryservice_char(ch);
+
ch->devbatt = btd_device_add_battery(ch->batt->dev);
+ btd_device_set_battery_opt(ch->devbatt,
+ BATTERY_OPT_REFRESH_FUNC,
+ batterylevel_refresh_cb,
+ BATTERY_OPT_INVALID);
+
if (l->next != NULL) {
struct gatt_char *c = l->next->data;
if (start == c->handle)
@@ -247,6 +327,12 @@ static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
gatt_discover_char(batt->attrib, batt->svc_range->start,
batt->svc_range->end, NULL,
configure_battery_cb, batt);
+ } else {
+ GSList *l;
+ for (l = batt->chars; l; l = l->next) {
+ struct characteristic *c = l->data;
+ process_batteryservice_char(c);
+ }
}
}
--
1.7.9.5
^ permalink raw reply related
* [PATCH v3 09/10] battery: Add support for notifications
From: chen.ganir @ 2012-09-20 8:27 UTC (permalink / raw)
To: linux-bluetooth; +Cc: chen.ganir
In-Reply-To: <1348129663-1701-1-git-send-email-chen.ganir@ti.com>
From: Chen Ganir <chen.ganir@ti.com>
Add support for emitting PropertyChanged when a battery level
characteristic notification is sent from the peer device.
---
profiles/battery/battery.c | 98 +++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 96 insertions(+), 2 deletions(-)
diff --git a/profiles/battery/battery.c b/profiles/battery/battery.c
index d681e2d..fce7724 100644
--- a/profiles/battery/battery.c
+++ b/profiles/battery/battery.c
@@ -43,6 +43,7 @@ struct battery {
GAttrib *attrib; /* GATT connection */
guint attioid; /* Att watcher id */
struct att_range *svc_range; /* Battery range */
+ guint attnotid; /* Att notifications id */
GSList *chars; /* Characteristics */
};
@@ -56,6 +57,7 @@ struct characteristic {
uint8_t ns; /* Battery Namespace */
uint16_t description; /* Battery description */
uint8_t level; /* Battery level */
+ gboolean canNotify; /* Char can notify flag */
};
struct descriptor {
@@ -86,6 +88,14 @@ static void char_free(gpointer user_data)
g_free(c);
}
+static gint cmp_char_val_handle(gconstpointer a, gconstpointer b)
+{
+ const struct characteristic *ch = a;
+ const uint16_t *handle = b;
+
+ return ch->attr.value_handle - *handle;
+}
+
static void battery_free(gpointer user_data)
{
struct battery *batt = user_data;
@@ -96,8 +106,14 @@ static void battery_free(gpointer user_data)
if (batt->attioid > 0)
btd_device_remove_attio_callback(batt->dev, batt->attioid);
- if (batt->attrib != NULL)
+ if (batt->attrib != NULL) {
+ if (batt->attnotid) {
+ g_attrib_unregister(batt->attrib, batt->attnotid);
+ batt->attnotid = 0;
+ }
+
g_attrib_unref(batt->attrib);
+ }
btd_device_unref(batt->dev);
g_free(batt->svc_range);
@@ -140,6 +156,18 @@ static void process_batteryservice_char(struct characteristic *ch)
}
}
+static void batterylevel_enable_notify_cb(guint8 status, const guint8 *pdu,
+ guint16 len, gpointer user_data)
+{
+ struct characteristic *ch = (struct characteristic *)user_data;
+
+ if (status != 0) {
+ error("Could not enable batt level notification.");
+ ch->canNotify = FALSE;
+ process_batteryservice_char(ch);
+ }
+}
+
static gint device_battery_cmp(gconstpointer a, gconstpointer b)
{
const struct characteristic *ch = a;
@@ -176,6 +204,19 @@ static void batterylevel_refresh_cb(struct btd_battery *batt)
process_batteryservice_char(ch);
}
+static void enable_battery_notification(struct characteristic *ch,
+ uint16_t handle)
+{
+ uint8_t atval[2];
+ uint16_t val;
+
+ val = GATT_CLIENT_CHARAC_CFG_NOTIF_BIT;
+
+ att_put_u16(val, atval);
+ gatt_write_char(ch->batt->attrib, handle, atval, 2,
+ batterylevel_enable_notify_cb, ch);
+}
+
static void batterylevel_presentation_format_desc_cb(guint8 status,
const guint8 *pdu, guint16 len,
gpointer user_data)
@@ -211,6 +252,14 @@ static void process_batterylevel_desc(struct descriptor *desc)
char uuidstr[MAX_LEN_UUID_STR];
bt_uuid_t btuuid;
+ bt_uuid16_create(&btuuid, GATT_CLIENT_CHARAC_CFG_UUID);
+
+ if (bt_uuid_cmp(&desc->uuid, &btuuid) == 0 && g_strcmp0(ch->attr.uuid,
+ BATTERY_LEVEL_UUID) == 0) {
+ enable_battery_notification(ch, desc->handle);
+ return;
+ }
+
bt_uuid16_create(&btuuid, GATT_CHARAC_FMT_UUID);
if (bt_uuid_cmp(&desc->uuid, &btuuid) == 0) {
@@ -317,12 +366,54 @@ static void configure_battery_cb(GSList *characteristics, guint8 status,
}
}
+static void proc_batterylevel(struct characteristic *c, const uint8_t *pdu,
+ uint16_t len, gboolean final)
+{
+ if (!pdu) {
+ error("Battery level notification: Invalid pdu length");
+ return;
+ }
+
+ c->level = pdu[1];
+
+ btd_device_set_battery_opt(c->devbatt, BATTERY_OPT_LEVEL, c->level,
+ BATTERY_OPT_INVALID);
+}
+
+static void notif_handler(const uint8_t *pdu, uint16_t len, gpointer user_data)
+{
+ struct battery *batt = user_data;
+ struct characteristic *ch;
+ uint16_t handle;
+ GSList *l;
+
+ if (len < 3) {
+ error("notif_handler: Bad pdu received");
+ return;
+ }
+
+ handle = att_get_u16(&pdu[1]);
+ l = g_slist_find_custom(batt->chars, &handle, cmp_char_val_handle);
+ if (l == NULL) {
+ error("notif_handler: Unexpected handle 0x%04x", handle);
+ return;
+ }
+
+ ch = l->data;
+ if (g_strcmp0(ch->attr.uuid, BATTERY_LEVEL_UUID) == 0) {
+ proc_batterylevel(ch, pdu, len, FALSE);
+ }
+}
+
static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
{
struct battery *batt = user_data;
batt->attrib = g_attrib_ref(attrib);
+ batt->attnotid = g_attrib_register(batt->attrib, ATT_OP_HANDLE_NOTIFY,
+ notif_handler, batt, NULL);
+
if (batt->chars == NULL) {
gatt_discover_char(batt->attrib, batt->svc_range->start,
batt->svc_range->end, NULL,
@@ -331,7 +422,8 @@ 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;
- process_batteryservice_char(c);
+ if (!c->canNotify)
+ process_batteryservice_char(c);
}
}
}
@@ -340,6 +432,8 @@ static void attio_disconnected_cb(gpointer user_data)
{
struct battery *batt = user_data;
+ g_attrib_unregister(batt->attrib, batt->attnotid);
+ batt->attnotid = 0;
g_attrib_unref(batt->attrib);
batt->attrib = NULL;
}
--
1.7.9.5
^ permalink raw reply related
* [PATCH v3 10/10] battery: Support persistent battery level
From: chen.ganir @ 2012-09-20 8:27 UTC (permalink / raw)
To: linux-bluetooth; +Cc: chen.ganir
In-Reply-To: <1348129663-1701-1-git-send-email-chen.ganir@ti.com>
From: Chen Ganir <chen.ganir@ti.com>
Store battery level when read, and use the level from storage
when connecting, to reduce GATT traffic.
---
profiles/battery/battery.c | 107 +++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 106 insertions(+), 1 deletion(-)
diff --git a/profiles/battery/battery.c b/profiles/battery/battery.c
index fce7724..f97ee9c 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,10 @@
#include "gatt.h"
#include "battery.h"
#include "log.h"
+#include "storage.h"
+
+#define BATTERY_KEY_FORMAT "%17s#%04X"
+#define BATTERY_LEVEL_FORMAT "%03d"
struct battery {
struct btd_device *dev; /* Device reference */
@@ -77,10 +83,103 @@ static gint cmp_device(gconstpointer a, gconstpointer b)
return -1;
}
+static inline int create_filename(char *buf, size_t size,
+ const bdaddr_t *bdaddr, const char *name)
+{
+ char addr[18];
+
+ ba2str(bdaddr, addr);
+
+ return create_name(buf, size, STORAGEDIR, addr, name);
+}
+
+static int store_battery_char(struct characteristic *chr)
+{
+ char filename[PATH_MAX + 1], addr[18], key[23];
+ bdaddr_t sba, dba;
+ char level[4];
+
+ adapter_get_address(device_get_adapter(chr->batt->dev), &sba);
+ device_get_address(chr->batt->dev, &dba, NULL);
+
+ create_filename(filename, PATH_MAX, &sba, "battery_gatt_client");
+
+ create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+
+ ba2str(&dba, addr);
+
+ snprintf(key, sizeof(key), BATTERY_KEY_FORMAT, addr, chr->attr.handle);
+ snprintf(level, sizeof(level), BATTERY_LEVEL_FORMAT, chr->level);
+
+ return textfile_caseput(filename, key, level);
+}
+
+static char *read_battery_char(struct characteristic *chr)
+{
+ char filename[PATH_MAX + 1], addr[18], key[23];
+ char *str, *strnew;
+ bdaddr_t sba, dba;
+
+ adapter_get_address(device_get_adapter(chr->batt->dev), &sba);
+ device_get_address(chr->batt->dev, &dba, NULL);
+
+ create_filename(filename, PATH_MAX, &sba, "battery_gatt_client");
+
+ ba2str(&dba, addr);
+ snprintf(key, sizeof(key), BATTERY_KEY_FORMAT, addr, chr->attr.handle);
+
+ str = textfile_caseget(filename, key);
+ if (str == NULL)
+ return NULL;
+
+ strnew = g_strdup(str);
+ g_free(str);
+
+ return strnew;
+}
+
+static void del_battery_char(struct characteristic *chr)
+{
+ char filename[PATH_MAX + 1], addr[18], key[23];
+ bdaddr_t sba, dba;
+
+ adapter_get_address(device_get_adapter(chr->batt->dev), &sba);
+ device_get_address(chr->batt->dev, &dba, NULL);
+
+ create_filename(filename, PATH_MAX, &sba, "battery_gatt_client");
+
+ ba2str(&dba, addr);
+ snprintf(key, sizeof(key), BATTERY_KEY_FORMAT, addr, chr->attr.handle);
+
+ textfile_casedel(filename, key);
+}
+
+static gboolean read_battery_level_value(struct characteristic *chr)
+{
+ char *str;
+
+ if (!chr)
+ return FALSE;
+
+ str = read_battery_char(chr);
+ if (!str)
+ return FALSE;
+
+ chr->level = atoi(str);
+
+ btd_device_set_battery_opt(chr->devbatt, BATTERY_OPT_LEVEL, chr->level,
+ BATTERY_OPT_INVALID);
+
+ g_free(str);
+ return TRUE;
+}
+
static void char_free(gpointer user_data)
{
struct characteristic *c = user_data;
+ del_battery_char(c);
+
g_slist_free_full(c->desc, g_free);
btd_device_remove_battery(c->devbatt);
@@ -146,6 +245,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)
@@ -309,6 +410,7 @@ static void discover_desc_cb(guint8 status, const guint8 *pdu, guint16 len,
}
att_data_list_free(list);
+
}
static void configure_battery_cb(GSList *characteristics, guint8 status,
@@ -345,6 +447,9 @@ static void configure_battery_cb(GSList *characteristics, guint8 status,
ch->devbatt = btd_device_add_battery(ch->batt->dev);
+ if (!read_battery_level_value(ch))
+ process_batteryservice_char(ch);
+
btd_device_set_battery_opt(ch->devbatt,
BATTERY_OPT_REFRESH_FUNC,
batterylevel_refresh_cb,
@@ -422,7 +527,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->canNotify)
+ if (!read_battery_level_value(c) && !c->canNotify)
process_batteryservice_char(c);
}
}
--
1.7.9.5
^ permalink raw reply related
* Re: [RFCv1 01/20] Bluetooth: Add new l2cap_chan struct members for high speed channels
From: Andrei Emeltchenko @ 2012-09-20 10:39 UTC (permalink / raw)
To: Mat Martineau; +Cc: linux-bluetooth, gustavo, sunnyk
In-Reply-To: <1347387691-5285-2-git-send-email-mathewm@codeaurora.org>
Hi Mat,
On Tue, Sep 11, 2012 at 11:21:12AM -0700, Mat Martineau wrote:
> An L2CAP channel using high speed continues to be associated with a
> BR/EDR l2cap_conn, while also tracking an additional hci_conn
> (representing a physical link on a high speed controller) and hci_chan
> (representing a logical link). There may only be one physical link
> between two high speed controllers. Each physical link may contain
> several logical links, with each logical link representing a channel
> with specific quality of service.
>
> During a channel move, the destination channel id, current move state,
> and role (initiator vs. responder) are tracked and used by the channel
> move state machine. The ident value associated with a move request
> must also be stored in order to use it in later move responses.
>
> The active channel is stored in local_amp_id.
>
> Signed-off-by: Mat Martineau <mathewm@codeaurora.org>
> ---
> include/net/bluetooth/l2cap.h | 29 +++++++++++++++++++++++++++++
> net/bluetooth/l2cap_core.c | 5 +++++
> 2 files changed, 34 insertions(+)
>
> diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
> index 7ed8e35..6b6fb27 100644
> --- a/include/net/bluetooth/l2cap.h
> +++ b/include/net/bluetooth/l2cap.h
> @@ -433,6 +433,8 @@ struct l2cap_chan {
> struct sock *sk;
>
> struct l2cap_conn *conn;
> + struct hci_conn *hs_hcon;
Do we need hs_hcon if we have hs_hchan ?
> + struct hci_chan *hs_hchan;
> struct kref kref;
>
> __u8 state;
> @@ -476,6 +478,11 @@ struct l2cap_chan {
> unsigned long conn_state;
> unsigned long flags;
>
> + __u8 local_amp_id;
> + __u8 move_id;
So this is Destination AMP ctrl id, would this be better to name it like
move_dst_amp_id or dst_amp_id;
...
Best regards
Andrei Emeltchenko
^ permalink raw reply
* Re: [PATCH v3 06/10] battery: Get Battery ID
From: Anderson Lizardo @ 2012-09-20 10:46 UTC (permalink / raw)
To: chen.ganir; +Cc: linux-bluetooth
In-Reply-To: <1348129663-1701-7-git-send-email-chen.ganir@ti.com>
Hi Chen,
On Thu, Sep 20, 2012 at 4:27 AM, <chen.ganir@ti.com> wrote:
> @@ -150,31 +200,35 @@ static void configure_battery_cb(GSList *characteristics, guint8 status,
>
> for (l = characteristics; l; l = l->next) {
> struct gatt_char *c = l->data;
> - struct characteristic *ch;
> - uint16_t start, end;
> -
> - ch = g_new0(struct characteristic, 1);
> - ch->attr.handle = c->handle;
> - ch->attr.properties = c->properties;
> - ch->attr.value_handle = c->value_handle;
> - memcpy(ch->attr.uuid, c->uuid, MAX_LEN_UUID_STR + 1);
> - ch->batt = batt;
>
> - batt->chars = g_slist_append(batt->chars, ch);
> -
> - start = c->value_handle + 1;
> -
> - if (l->next != NULL) {
> - struct gatt_char *c = l->next->data;
> - if (start == c->handle)
> + if (g_strcmp0(c->uuid, BATTERY_LEVEL_UUID) == 0) {
Minor comment, but looks like it would be cleaner if you used:
if (g_strcmp0(c->uuid, BATTERY_LEVEL_UUID) != 0)
continue;
and avoided all this shifting and one more level of indentation.
> + struct characteristic *ch;
> + uint16_t start, end;
> +
> + ch = g_new0(struct characteristic, 1);
> + ch->attr.handle = c->handle;
> + ch->attr.properties = c->properties;
> + ch->attr.value_handle = c->value_handle;
> + memcpy(ch->attr.uuid, c->uuid, MAX_LEN_UUID_STR + 1);
> + ch->batt = batt;
> +
> + batt->chars = g_slist_append(batt->chars, ch);
> +
> + start = c->value_handle + 1;
> +
> + if (l->next != NULL) {
> + struct gatt_char *c = l->next->data;
> + if (start == c->handle)
> + continue;
> + end = c->handle - 1;
> + } else if (c->value_handle != batt->svc_range->end)
> + end = batt->svc_range->end;
> + else
> continue;
> - end = c->handle - 1;
> - } else if (c->value_handle != batt->svc_range->end)
> - end = batt->svc_range->end;
> - else
> - continue;
>
> - gatt_find_info(batt->attrib, start, end, discover_desc_cb, ch);
> + gatt_find_info(batt->attrib, start, end,
> + discover_desc_cb, ch);
> + }
> }
> }
Regards,
--
Anderson Lizardo
Instituto Nokia de Tecnologia - INdT
Manaus - Brazil
^ permalink raw reply
* Re: [PATCH v3 09/10] battery: Add support for notifications
From: Anderson Lizardo @ 2012-09-20 10:54 UTC (permalink / raw)
To: chen.ganir; +Cc: linux-bluetooth
In-Reply-To: <1348129663-1701-10-git-send-email-chen.ganir@ti.com>
Hi Chen,
On Thu, Sep 20, 2012 at 4:27 AM, <chen.ganir@ti.com> wrote:
> @@ -140,6 +156,18 @@ static void process_batteryservice_char(struct characteristic *ch)
> }
> }
>
> +static void batterylevel_enable_notify_cb(guint8 status, const guint8 *pdu,
> + guint16 len, gpointer user_data)
> +{
> + struct characteristic *ch = (struct characteristic *)user_data;
Casting above seems unnecessary (gpointer is typedef to void*).
> +
> + if (status != 0) {
> + error("Could not enable batt level notification.");
> + ch->canNotify = FALSE;
This camelCase is inconsistent with other struct fields on the same file.
> + process_batteryservice_char(ch);
> + }
> +}
> +
> static gint device_battery_cmp(gconstpointer a, gconstpointer b)
> {
> const struct characteristic *ch = a;
Regards,
--
Anderson Lizardo
Instituto Nokia de Tecnologia - INdT
Manaus - Brazil
^ permalink raw reply
* Re: [PATCH v3 00/10] Implement Generic battery and LE Battery client
From: Anderson Lizardo @ 2012-09-20 10:56 UTC (permalink / raw)
To: chen.ganir; +Cc: linux-bluetooth
In-Reply-To: <1348129663-1701-1-git-send-email-chen.ganir@ti.com>
Hi Chen,
On Thu, Sep 20, 2012 at 4:27 AM, <chen.ganir@ti.com> wrote:
> From: Chen Ganir <chen.ganir@ti.com>
>
> This patch set replaces previous patch sets which implemented the LE battery
> GATT Client. This patch set implements a generic device battery D-Bus interface
> that can be used to get remote device battery status using D-Bus. In addition,
> This patch set also implements the GATT Battery client, which uses the generic
> device battery to expose LE device battery status.
>
> see doc/battery-api.txt and doc/device-api.txt for more information.
>
> This is version 2 of the patch set, including multiple style and other comments
> reported on the ML. This version is rebased on the latest code.
Besides some minor style comments (found on this last round of
review), patch set looks good to me.
Regards,
--
Anderson Lizardo
Instituto Nokia de Tecnologia - INdT
Manaus - Brazil
^ permalink raw reply
* Re: [PATCH v3 09/10] battery: Add support for notifications
From: Chen Ganir @ 2012-09-20 11:00 UTC (permalink / raw)
To: Anderson Lizardo; +Cc: linux-bluetooth
In-Reply-To: <CAJdJm_P07N-VwgnHy=1m3D68086dP9fFy5AmkhZC_3b4d2xpmg@mail.gmail.com>
Anderson,
On 09/20/2012 01:54 PM, Anderson Lizardo wrote:
> Hi Chen,
>
> On Thu, Sep 20, 2012 at 4:27 AM, <chen.ganir@ti.com> wrote:
>> @@ -140,6 +156,18 @@ static void process_batteryservice_char(struct characteristic *ch)
>> }
>> }
>>
>> +static void batterylevel_enable_notify_cb(guint8 status, const guint8 *pdu,
>> + guint16 len, gpointer user_data)
>> +{
>> + struct characteristic *ch = (struct characteristic *)user_data;
>
> Casting above seems unnecessary (gpointer is typedef to void*).
>
I'll change that.
>> +
>> + if (status != 0) {
>> + error("Could not enable batt level notification.");
>> + ch->canNotify = FALSE;
>
> This camelCase is inconsistent with other struct fields on the same file.
>
Will be changed.
>> + process_batteryservice_char(ch);
>> + }
>> +}
>> +
>> static gint device_battery_cmp(gconstpointer a, gconstpointer b)
>> {
>> const struct characteristic *ch = a;
>
> Regards,
>
Thanks !
--
BR,
Chen Ganir
^ permalink raw reply
* Re: [PATCHv6 00/17] Bluetooth: Create AMP physical link
From: Andrei Emeltchenko @ 2012-09-20 11:01 UTC (permalink / raw)
To: linux-bluetooth; +Cc: mathewm, gustavo, marcel
In-Reply-To: <1347978509-12133-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>
ping
On Tue, Sep 18, 2012 at 05:28:12PM +0300, Andrei Emeltchenko wrote:
> From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
>
> This set of patches enhances A2MP protocol and creates physical
> link between AMP controllers. This is further iteration towards
> Bluetooth High Speed.
>
> Changes:
> * p6: Refactoring: moving code from pal.[ch] to amp.[ch]
> * p5: Fix issues reported by Mat in mailing list review
> * p4: Rebased against recent bluetooth-next, minor fixes
> * p3: Use hci_conn for representing physical link(type AMP_LINK) instead of
> struct phy_link, refactoring.
> * p2: Remove HCI callbacks and use amp_mgr global list, refactor code.
> * p1: Fixed locking issues, added basic logical link preparation.
> * v3: Remove workqueue from callback processing; change callback functions
> names according to reviewers recommendations; create global amp_mgr_list to
> have lookup to amp manager, physical and logical links so for those HCI events
> which might be identified by __handler__ we have lookup; remove extensive
> hexdump from gen_amp_key.
> * v2: Fix typos and bugs, add functionality: now physical connection
> might be established.
> * v1: Fix typos, change debug prints, refactor code for better
> splitting functionality.
>
> Andrei Emeltchenko (16):
> Bluetooth: Add HCI logical link cmds definitions
> Bluetooth: A2MP: Create amp_mgr global list
> Bluetooth: AMP: Use HCI cmd to Read AMP Info
> Bluetooth: AMP: Use HCI cmd to Read Loc AMP Assoc
> Bluetooth: A2MP: Process Discover Response
> Bluetooth: AMP: Physical link struct and heplers
> Bluetooth: AMP: Remote AMP ctrl definitions
> Bluetooth: AMP: Handle create / disc phylink req
> Bluetooth: A2MP: Process A2MP Getinfo Rsp
> Bluetooth: A2MP: Process A2MP Get AMP Assoc Rsp
> Bluetooth: Choose connection based on capabilities
> Bluetooth: AMP: Add AMP key calculation
> Bluetooth: AMP: Create Physical Link
> Bluetooth: AMP: Write remote AMP Assoc
> Bluetooth: A2MP: Add fallback to normal l2cap init sequence
> Bluetooth: AMP: Process Chan Selected event
>
> Dmitry Kasatkin (1):
> Bluetooth: Add function to derive AMP key using hmac
>
> include/net/bluetooth/a2mp.h | 22 ++
> include/net/bluetooth/amp.h | 47 +++++
> include/net/bluetooth/hci.h | 39 +++-
> include/net/bluetooth/hci_core.h | 11 +
> include/net/bluetooth/l2cap.h | 4 +
> net/bluetooth/Kconfig | 1 +
> net/bluetooth/Makefile | 2 +-
> net/bluetooth/a2mp.c | 423 +++++++++++++++++++++++++++++++++++---
> net/bluetooth/amp.c | 348 +++++++++++++++++++++++++++++++
> net/bluetooth/hci_event.c | 106 +++++++++-
> net/bluetooth/l2cap_core.c | 35 +++-
> 11 files changed, 1000 insertions(+), 38 deletions(-)
> create mode 100644 include/net/bluetooth/amp.h
> create mode 100644 net/bluetooth/amp.c
>
> --
> 1.7.9.5
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox