* Re: Dropping connection (bit off-topic)
From: John Tobias @ 2012-09-13 17:50 UTC (permalink / raw)
To: Anderson Lizardo; +Cc: Vinicius Costa Gomes, linux-bluetooth
In-Reply-To: <CAJdJm_OfccWTVuphRQfjfouY3m8_HgSeGwE-XSyHetzy+tjFFw@mail.gmail.com>
Hi Anderson,
Here are the logs after reading the characteristic from my iPad apps
that do the advertising.
HCI sniffer - Bluetooth packet analyzer ver 2.2
device: hci0 snap_len: 1028 filter: 0xffffffff
< HCI Command: LE Set Scan Parameters (0x08|0x000b) plen 7
type 0x01 (active)
interval 10.000ms window 10.000ms
own address: 0x00 (Public) policy: All
> HCI Event: Command Complete (0x0e) plen 4
LE Set Scan Parameters (0x08|0x000b) ncmd 1
status 0x00
< HCI Command: LE Set Scan Enable (0x08|0x000c) plen 2
value 0x01 (scanning enabled)
filter duplicates 0x01 (enabled)
> HCI Event: Command Complete (0x0e) plen 4
LE Set Scan Enable (0x08|0x000c) ncmd 1
status 0x00
> HCI Event: LE Meta Event (0x3e) plen 43
LE Advertising Report
ADV_IND - Connectable undirected advertising (0)
bdaddr 60:36:25:4A:6B:75 (Random)
Flags: 0x1a
Unknown type 0x07 with 16 bytes data
Complete local name: 'Appl0001'
RSSI: -62
> HCI Event: LE Meta Event (0x3e) plen 12
LE Advertising Report
SCAN_RSP - Scan Response (4)
bdaddr 60:36:25:4A:6B:75 (Random)
RSSI: -62
> HCI Event: LE Meta Event (0x3e) plen 43
LE Advertising Report
ADV_IND - Connectable undirected advertising (0)
bdaddr 60:36:25:4A:6B:75 (Random)
Flags: 0x1a
Unknown type 0x07 with 16 bytes data
Complete local name: 'Appl0001'
RSSI: -60
> HCI Event: LE Meta Event (0x3e) plen 12
LE Advertising Report
SCAN_RSP - Scan Response (4)
bdaddr 60:36:25:4A:6B:75 (Random)
RSSI: -60
> HCI Event: LE Meta Event (0x3e) plen 43
LE Advertising Report
ADV_IND - Connectable undirected advertising (0)
bdaddr 60:36:25:4A:6B:75 (Random)
Flags: 0x1a
Unknown type 0x07 with 16 bytes data
Complete local name: 'Appl0001'
RSSI: -62
> HCI Event: LE Meta Event (0x3e) plen 12
LE Advertising Report
SCAN_RSP - Scan Response (4)
bdaddr 60:36:25:4A:6B:75 (Random)
RSSI: -62
> HCI Event: LE Meta Event (0x3e) plen 43
LE Advertising Report
ADV_IND - Connectable undirected advertising (0)
bdaddr 60:36:25:4A:6B:75 (Random)
Flags: 0x1a
Unknown type 0x07 with 16 bytes data
Complete local name: 'Appl0001'
RSSI: -69
> HCI Event: LE Meta Event (0x3e) plen 12
LE Advertising Report
SCAN_RSP - Scan Response (4)
bdaddr 60:36:25:4A:6B:75 (Random)
RSSI: -69
< HCI Command: LE Set Scan Enable (0x08|0x000c) plen 2
value 0x00 (scanning disabled)
filter duplicates 0x01 (enabled)
> HCI Event: Command Complete (0x0e) plen 4
LE Set Scan Enable (0x08|0x000c) ncmd 1
status 0x00
< HCI Command: LE Create Connection (0x08|0x000d) plen 25
bdaddr 60:36:25:4A:6B:75 type 1
> HCI Event: Command Status (0x0f) plen 4
LE Create Connection (0x08|0x000d) status 0x00 ncmd 1
> HCI Event: LE Meta Event (0x3e) plen 19
LE Connection Complete
status 0x00 handle 76, role master
bdaddr 60:36:25:4A:6B:75 (Random)
> ACL data: handle 76 flags 0x02 dlen 11
ATT: Read By Type req (0x08)
start 0x0001, end 0xffff
type-uuid 0x2a00
< ACL data: handle 76 flags 0x00 dlen 11
ATT: Read By Type req (0x08)
start 0x0001, end 0xffff
type-uuid 0x2803
> HCI Event: Number of Completed Packets (0x13) plen 5
handle 76 packets 1
> ACL data: handle 76 flags 0x02 dlen 27
ATT: Read By Type resp (0x09)
length: 7
handle 0x0002, value 0x02 0x03 0x00 0x00 0x2a
handle 0x0004, value 0x02 0x05 0x00 0x01 0x2a
handle 0x0007, value 0x20 0x08 0x00 0x05 0x2a
< ACL data: handle 76 flags 0x00 dlen 11
ATT: Read By Type req (0x08)
start 0x0008, end 0xffff
type-uuid 0x2803
> HCI Event: Number of Completed Packets (0x13) plen 5
handle 76 packets 1
> ACL data: handle 76 flags 0x02 dlen 27
ATT: Read By Type resp (0x09)
length: 21
handle 0x000b, value 0x02 0x0c 0x00 0x31 0x3d 0x35 0x06 0x1e
0x60 0x70 0xa3 0x8d 0x4e 0x58 0x9c 0x2d 0x6a 0x3c 0x16
< ACL data: handle 76 flags 0x00 dlen 11
ATT: Read By Type req (0x08)
start 0x000c, end 0xffff
type-uuid 0x2803
> HCI Event: Number of Completed Packets (0x13) plen 5
handle 76 packets 1
> ACL data: handle 76 flags 0x02 dlen 27
ATT: Read By Type resp (0x09)
length: 21
handle 0x000d, value 0x8a 0x0e 0x00 0x32 0x3d 0x35 0x06 0x1e
0x60 0x70 0xa3 0x8d 0x4e 0x58 0x9c 0x2d 0x6a 0x3c 0x16
< ACL data: handle 76 flags 0x00 dlen 11
ATT: Read By Type req (0x08)
start 0x000e, end 0xffff
type-uuid 0x2803
> HCI Event: Number of Completed Packets (0x13) plen 5
handle 76 packets 1
> ACL data: handle 76 flags 0x02 dlen 27
ATT: Read By Type resp (0x09)
length: 21
handle 0x0010, value 0x88 0x11 0x00 0x33 0x3d 0x35 0x06 0x1e
0x60 0x70 0xa3 0x8d 0x4e 0x58 0x9c 0x2d 0x6a 0x3c 0x16
< ACL data: handle 76 flags 0x00 dlen 11
ATT: Read By Type req (0x08)
start 0x0011, end 0xffff
type-uuid 0x2803
> HCI Event: Number of Completed Packets (0x13) plen 5
handle 76 packets 1
> ACL data: handle 76 flags 0x02 dlen 27
ATT: Read By Type resp (0x09)
length: 21
handle 0x0013, value 0x9a 0x14 0x00 0x52 0x72 0x3a 0x71 0xae
0x82 0x0c 0xae 0xe0 0x49 0x1d 0x18 0xc2 0xb4 0xd8 0x37
< ACL data: handle 76 flags 0x00 dlen 11
ATT: Read By Type req (0x08)
start 0x0014, end 0xffff
type-uuid 0x2803
> HCI Event: Number of Completed Packets (0x13) plen 5
handle 76 packets 1
> ACL data: handle 76 flags 0x02 dlen 27
ATT: Read By Type resp (0x09)
length: 21
handle 0x0017, value 0x9a 0x18 0x00 0x36 0x72 0x3a 0x71 0xae
0x82 0x0c 0xae 0xe0 0x49 0x1d 0x18 0xc2 0xb4 0xd8 0x37
< ACL data: handle 76 flags 0x00 dlen 11
ATT: Read By Type req (0x08)
start 0x0018, end 0xffff
type-uuid 0x2803
> HCI Event: Number of Completed Packets (0x13) plen 5
handle 76 packets 1
> ACL data: handle 76 flags 0x02 dlen 27
ATT: Read By Type resp (0x09)
length: 21
handle 0x001b, value 0x9a 0x1c 0x00 0x37 0x72 0x3a 0x71 0xae
0x82 0x0c 0xae 0xe0 0x49 0x1d 0x18 0xc2 0xb4 0xd8 0x37
< ACL data: handle 76 flags 0x00 dlen 11
ATT: Read By Type req (0x08)
start 0x001c, end 0xffff
type-uuid 0x2803
> HCI Event: Number of Completed Packets (0x13) plen 5
handle 76 packets 1
> ACL data: handle 76 flags 0x02 dlen 27
ATT: Read By Type resp (0x09)
length: 21
handle 0x001f, value 0x8a 0x20 0x00 0x38 0x72 0x3a 0x71 0xae
0x82 0x0c 0xae 0xe0 0x49 0x1d 0x18 0xc2 0xb4 0xd8 0x37
< ACL data: handle 76 flags 0x00 dlen 11
ATT: Read By Type req (0x08)
start 0x0020, end 0xffff
type-uuid 0x2803
> HCI Event: Number of Completed Packets (0x13) plen 5
handle 76 packets 1
> ACL data: handle 76 flags 0x02 dlen 27
ATT: Read By Type resp (0x09)
length: 21
handle 0x0022, value 0x98 0x23 0x00 0x40 0x72 0x3a 0x71 0xae
0x82 0x0c 0xae 0xe0 0x49 0x1d 0x18 0xc2 0xb4 0xd8 0x37
< ACL data: handle 76 flags 0x00 dlen 11
ATT: Read By Type req (0x08)
start 0x0023, end 0xffff
type-uuid 0x2803
> HCI Event: Number of Completed Packets (0x13) plen 5
handle 76 packets 1
> ACL data: handle 76 flags 0x02 dlen 27
ATT: Read By Type resp (0x09)
length: 21
handle 0x0026, value 0x9a 0x27 0x00 0x41 0x72 0x3a 0x71 0xae
0x82 0x0c 0xae 0xe0 0x49 0x1d 0x18 0xc2 0xb4 0xd8 0x37
< ACL data: handle 76 flags 0x00 dlen 11
ATT: Read By Type req (0x08)
start 0x0027, end 0xffff
type-uuid 0x2803
> HCI Event: Number of Completed Packets (0x13) plen 5
handle 76 packets 1
> ACL data: handle 76 flags 0x02 dlen 27
ATT: Read By Type resp (0x09)
length: 21
handle 0x002a, value 0x98 0x2b 0x00 0x42 0x72 0x3a 0x71 0xae
0x82 0x0c 0xae 0xe0 0x49 0x1d 0x18 0xc2 0xb4 0xd8 0x37
< ACL data: handle 76 flags 0x00 dlen 11
ATT: Read By Type req (0x08)
start 0x002b, end 0xffff
type-uuid 0x2803
> HCI Event: Number of Completed Packets (0x13) plen 5
handle 76 packets 1
> ACL data: handle 76 flags 0x02 dlen 27
ATT: Read By Type resp (0x09)
length: 21
handle 0x002e, value 0x88 0x2f 0x00 0x60 0x72 0x3a 0x71 0xae
0x82 0x0c 0xae 0xe0 0x49 0x1d 0x18 0xc2 0xb4 0xd8 0x37
< ACL data: handle 76 flags 0x00 dlen 11
ATT: Read By Type req (0x08)
start 0x002f, end 0xffff
type-uuid 0x2803
> HCI Event: Number of Completed Packets (0x13) plen 5
handle 76 packets 1
> ACL data: handle 76 flags 0x02 dlen 27
ATT: Read By Type resp (0x09)
length: 21
handle 0x0031, value 0x88 0x32 0x00 0x61 0x72 0x3a 0x71 0xae
0x82 0x0c 0xae 0xe0 0x49 0x1d 0x18 0xc2 0xb4 0xd8 0x37
< ACL data: handle 76 flags 0x00 dlen 11
ATT: Read By Type req (0x08)
start 0x0032, end 0xffff
type-uuid 0x2803
> HCI Event: Number of Completed Packets (0x13) plen 5
handle 76 packets 1
> ACL data: handle 76 flags 0x02 dlen 27
ATT: Read By Type resp (0x09)
length: 21
handle 0x0034, value 0x12 0x35 0x00 0x62 0x72 0x3a 0x71 0xae
0x82 0x0c 0xae 0xe0 0x49 0x1d 0x18 0xc2 0xb4 0xd8 0x37
< ACL data: handle 76 flags 0x00 dlen 11
ATT: Read By Type req (0x08)
start 0x0035, end 0xffff
type-uuid 0x2803
> HCI Event: Number of Completed Packets (0x13) plen 5
handle 76 packets 1
> ACL data: handle 76 flags 0x02 dlen 27
ATT: Read By Type resp (0x09)
length: 21
handle 0x0037, value 0x8a 0x38 0x00 0x39 0x72 0x3a 0x71 0xae
0x82 0x0c 0xae 0xe0 0x49 0x1d 0x18 0xc2 0xb4 0xd8 0x37
< ACL data: handle 76 flags 0x00 dlen 11
ATT: Read By Type req (0x08)
start 0x0038, end 0xffff
type-uuid 0x2803
> HCI Event: Number of Completed Packets (0x13) plen 5
handle 76 packets 1
> ACL data: handle 76 flags 0x02 dlen 9
ATT: Error (0x01)
Error: Attribute not found (10)
Read By Type req (0x08) on handle 0x0039
> HCI Event: Disconn Complete (0x05) plen 4
status 0x00 handle 76 reason 0x13
Reason: Remote User Terminated Connection
Regards,
John
On Thu, Sep 13, 2012 at 3:53 AM, Anderson Lizardo
<anderson.lizardo@openbossa.org> wrote:
> Hi John,
>
> On Wed, Sep 12, 2012 at 10:52 PM, John Tobias <john.tobias.ph@gmail.com> wrote:
>> Hello again,
>>
>> I enabled the GATT in my bluetoothd and found out that there was an
>> unimplemented attribute (below) and might be the reason why the iPhone
>> connection got disconnected after 30 secs.
>>
>> 2012-09-12 15:36:55.419980 > ACL data: handle 76 flags 0x02 dlen 9
>> ATT: Error (0x01)
>> Error: Attribute not found (10)
>> Read By Type req (0x08) on handle 0x0039
>>
>> I would like to know if anyone here has a patch?.
>
> Just this snippet does not say much. "Attribute not found" errors are
> common during service/characteristic discovery because they indicate
> that the discovery has finished.
>
> Could you post the whole hcidump since the connection establishment up
> to the disconnection? That should help detecting the problem.
>
> Best Regards,
> --
> Anderson Lizardo
> Instituto Nokia de Tecnologia - INdT
> Manaus - Brazil
^ permalink raw reply
* Re: Connecting to Bluetooth Low Energy devices
From: Anderson Lizardo @ 2012-09-13 16:54 UTC (permalink / raw)
To: Philipp Claves; +Cc: linux-bluetooth
In-Reply-To: <67399724.T38U7nJAul@arawn>
Hi Philipp,
On Thu, Sep 13, 2012 at 11:34 AM, Philipp Claves
<claves@budelmann-elektronik.com> wrote:
> Hello
>
> Trying to get started with Bluetooth Low Energy devices, i used hcitool and
> gatttool to enumerate device attributes, but did not get far:
>
> # hcitool lescan
> LE Scan ...
> <MAC-Device1> Battery V1.0
> <MAC-Device1> (unknown)
> <MAC-Device2> Battery V1.0
> <MAC-Device2> (unknown)
> ^C
>
> # gatttool -b <MAC-Device1> -I
> [ ][<MAC-Device1>][LE]> connect
> Connecting... connect error: connect error: Connection refused (111)
> [ ][<MAC-Device1>][LE]>
>
> This is all i get.
Which kernel version are you running?
> Am i doing something obviously wrong?
> Any tips where to get more information about the error (dmesg shows nothing)?
run "hcidump -X" and check the logs while you run "hcitool lescan".
Then check the type of advertising those devices are sending. They
should be connectable advertisings to be able to connect to them. Also
check the address type, if it is "Random" you need to pass "-t random"
to gatttool.
Regards,
--
Anderson Lizardo
Instituto Nokia de Tecnologia - INdT
Manaus - Brazil
^ permalink raw reply
* Re: [PATCHv4 16/17] Bluetooth: A2MP: Add fallback to normal l2cap init sequence
From: Mat Martineau @ 2012-09-13 16:39 UTC (permalink / raw)
To: Andrei Emeltchenko; +Cc: linux-bluetooth, gustavo
In-Reply-To: <1347437192-24694-17-git-send-email-Andrei.Emeltchenko.news@gmail.com>
Andrei -
On Wed, 12 Sep 2012, Andrei Emeltchenko wrote:
> From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
>
> When there is no remote AMP controller found fallback to normal
> L2CAP sequence.
>
> Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
> ---
> include/net/bluetooth/l2cap.h | 1 +
> net/bluetooth/a2mp.c | 28 ++++++++++++++++++++++++++++
> net/bluetooth/l2cap_core.c | 2 +-
> 3 files changed, 30 insertions(+), 1 deletion(-)
>
> diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
> index aba830f..0967f9e 100644
> --- a/include/net/bluetooth/l2cap.h
> +++ b/include/net/bluetooth/l2cap.h
> @@ -769,5 +769,6 @@ int l2cap_ertm_init(struct l2cap_chan *chan);
> void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan);
> void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan);
> void l2cap_chan_del(struct l2cap_chan *chan, int err);
> +void l2cap_send_conn_req(struct l2cap_chan *chan);
>
> #endif /* __L2CAP_H */
> diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
> index 39e0f95..05522ea 100644
> --- a/net/bluetooth/a2mp.c
> +++ b/net/bluetooth/a2mp.c
> @@ -181,6 +181,7 @@ static int a2mp_discover_rsp(struct amp_mgr *mgr, struct sk_buff *skb,
> u16 len = le16_to_cpu(hdr->len);
> struct a2mp_cl *cl;
> u16 ext_feat;
> + bool found = false;
>
> if (len < sizeof(*rsp))
> return -EINVAL;
> @@ -211,6 +212,7 @@ static int a2mp_discover_rsp(struct amp_mgr *mgr, struct sk_buff *skb,
> if (cl->id != HCI_BREDR_ID && cl->type == HCI_AMP) {
> struct a2mp_info_req req;
>
> + found = true;
> req.id = cl->id;
> a2mp_send(mgr, A2MP_GETINFO_REQ, __next_ident(mgr),
> sizeof(req), &req);
> @@ -220,6 +222,32 @@ static int a2mp_discover_rsp(struct amp_mgr *mgr, struct sk_buff *skb,
> cl = (void *) skb_pull(skb, sizeof(*cl));
> }
>
> + /* Fall back to L2CAP init sequence */
> + if (!found) {
> + struct l2cap_conn *conn = mgr->l2cap_conn;
> + struct l2cap_chan *chan;
> +
> + mutex_lock(&conn->chan_lock);
> +
> + list_for_each_entry(chan, &conn->chan_l, list) {
> +
> + BT_DBG("chan %p state %s", chan,
> + state_to_string(chan->state));
> +
> + if (chan->chan_type == L2CAP_CHAN_CONN_FIX_A2MP)
> + continue;
> +
> + l2cap_chan_lock(chan);
> +
> + if (chan->state == BT_CONNECT)
> + l2cap_send_conn_req(chan);
> +
> + l2cap_chan_unlock(chan);
> + }
> +
> + mutex_unlock(&conn->chan_lock);
> + }
> +
> return 0;
> }
>
> diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
> index cfe047f..d2ab82c 100644
> --- a/net/bluetooth/l2cap_core.c
> +++ b/net/bluetooth/l2cap_core.c
> @@ -958,7 +958,7 @@ static bool __amp_capable(struct l2cap_chan *chan)
> return false;
> }
>
> -static void l2cap_send_conn_req(struct l2cap_chan *chan)
> +void l2cap_send_conn_req(struct l2cap_chan *chan)
> {
> struct l2cap_conn *conn = chan->conn;
> struct l2cap_conn_req req;
> --
> 1.7.9.5
>
>
Here's another place where we have duplicated functionality. This
patch has BR/EDR fallback too:
[RFCv1 13/20] Bluetooth: Handle physical link completion
You can call l2cap_physical_cfm() with a failure result instead of
calling l2cap_send_conn_req() directly.
--
Mat Martineau
The Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation
^ permalink raw reply
* Re: [PATCHv4 11/17] Bluetooth: Choose connection based on capabilities
From: Mat Martineau @ 2012-09-13 16:26 UTC (permalink / raw)
To: Andrei Emeltchenko; +Cc: linux-bluetooth, gustavo
In-Reply-To: <1347437192-24694-12-git-send-email-Andrei.Emeltchenko.news@gmail.com>
Andrei -
On Wed, 12 Sep 2012, Andrei Emeltchenko wrote:
> From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
>
> Choose which L2CAP connection to establish by checking support
> for HS and remote side supported features.
>
> Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
> ---
> include/net/bluetooth/a2mp.h | 2 ++
> include/net/bluetooth/l2cap.h | 1 +
> net/bluetooth/a2mp.c | 34 +++++++++++++++++++++++++++++-----
> net/bluetooth/l2cap_core.c | 33 ++++++++++++++++++++++++++++-----
> 4 files changed, 60 insertions(+), 10 deletions(-)
>
> diff --git a/include/net/bluetooth/a2mp.h b/include/net/bluetooth/a2mp.h
> index 93967f1..6e88a80 100644
> --- a/include/net/bluetooth/a2mp.h
> +++ b/include/net/bluetooth/a2mp.h
> @@ -23,6 +23,7 @@ struct amp_mgr {
> struct list_head list;
> struct l2cap_conn *l2cap_conn;
> struct l2cap_chan *a2mp_chan;
> + struct l2cap_chan *bredr_chan;
> struct kref kref;
> __u8 ident;
> __u8 handle;
> @@ -135,6 +136,7 @@ struct l2cap_chan *a2mp_channel_create(struct l2cap_conn *conn,
> struct sk_buff *skb);
> struct amp_mgr *amp_mgr_lookup_by_state(u8 state);
> void a2mp_send(struct amp_mgr *mgr, u8 code, u8 ident, u16 len, void *data);
> +void a2mp_discover_amp(struct l2cap_chan *chan);
> void a2mp_send_getinfo_rsp(struct hci_dev *hdev);
> void a2mp_send_getampassoc_rsp(struct hci_dev *hdev, u8 status);
>
> diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
> index 7ed8e35..aba830f 100644
> --- a/include/net/bluetooth/l2cap.h
> +++ b/include/net/bluetooth/l2cap.h
> @@ -767,6 +767,7 @@ int l2cap_chan_check_security(struct l2cap_chan *chan);
> void l2cap_chan_set_defaults(struct l2cap_chan *chan);
> int l2cap_ertm_init(struct l2cap_chan *chan);
> void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan);
> +void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan);
> void l2cap_chan_del(struct l2cap_chan *chan, int err);
>
> #endif /* __L2CAP_H */
> diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
> index 42bce4a..c550589 100644
> --- a/net/bluetooth/a2mp.c
> +++ b/net/bluetooth/a2mp.c
> @@ -629,7 +629,7 @@ static struct l2cap_ops a2mp_chan_ops = {
> .ready = l2cap_chan_no_ready,
> };
>
> -static struct l2cap_chan *a2mp_chan_open(struct l2cap_conn *conn)
> +static struct l2cap_chan *a2mp_chan_open(struct l2cap_conn *conn, bool locked)
> {
> struct l2cap_chan *chan;
> int err;
> @@ -664,7 +664,10 @@ static struct l2cap_chan *a2mp_chan_open(struct l2cap_conn *conn)
>
> chan->conf_state = 0;
>
> - l2cap_chan_add(conn, chan);
> + if (locked)
> + __l2cap_chan_add(conn, chan);
> + else
> + l2cap_chan_add(conn, chan);
>
> chan->remote_mps = chan->omtu;
> chan->mps = chan->omtu;
> @@ -703,7 +706,7 @@ int amp_mgr_put(struct amp_mgr *mgr)
> return kref_put(&mgr->kref, &_mgr_destroy);
> }
>
> -static struct amp_mgr *amp_mgr_create(struct l2cap_conn *conn)
> +static struct amp_mgr *amp_mgr_create(struct l2cap_conn *conn, bool locked)
> {
> struct amp_mgr *mgr;
> struct l2cap_chan *chan;
> @@ -716,7 +719,7 @@ static struct amp_mgr *amp_mgr_create(struct l2cap_conn *conn)
>
> mgr->l2cap_conn = conn;
>
> - chan = a2mp_chan_open(conn);
> + chan = a2mp_chan_open(conn, locked);
> if (!chan) {
> kfree(mgr);
> return NULL;
> @@ -745,7 +748,7 @@ struct l2cap_chan *a2mp_channel_create(struct l2cap_conn *conn,
> {
> struct amp_mgr *mgr;
>
> - mgr = amp_mgr_create(conn);
> + mgr = amp_mgr_create(conn, false);
> if (!mgr) {
> BT_ERR("Could not create AMP manager");
> return NULL;
> @@ -833,3 +836,24 @@ void a2mp_send_getampassoc_rsp(struct hci_dev *hdev, u8 status)
> amp_mgr_put(mgr);
> kfree(rsp);
> }
> +
> +void a2mp_discover_amp(struct l2cap_chan *chan)
> +{
> + struct l2cap_conn *conn = chan->conn;
> + struct amp_mgr *mgr = conn->hcon->amp_mgr;
> + struct a2mp_discov_req req;
> +
> + BT_DBG("chan %p conn %p mgr %p", chan, conn, mgr);
> +
> + if (!mgr) {
> + mgr = amp_mgr_create(conn, true);
> + if (!mgr)
> + return;
> + }
> +
> + mgr->bredr_chan = chan;
> +
> + req.mtu = cpu_to_le16(L2CAP_A2MP_DEFAULT_MTU);
> + req.ext_feat = 0;
> + a2mp_send(mgr, A2MP_DISCOVER_REQ, 1, sizeof(req), &req);
> +}
> diff --git a/net/bluetooth/l2cap_core.c b/net/bluetooth/l2cap_core.c
> index 9732f03..cfe047f 100644
> --- a/net/bluetooth/l2cap_core.c
> +++ b/net/bluetooth/l2cap_core.c
> @@ -455,7 +455,7 @@ void l2cap_chan_set_defaults(struct l2cap_chan *chan)
> set_bit(FLAG_FORCE_ACTIVE, &chan->flags);
> }
>
> -static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
> +void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
> {
> BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn,
> __le16_to_cpu(chan->psm), chan->dcid);
> @@ -946,6 +946,18 @@ static inline int __l2cap_no_conn_pending(struct l2cap_chan *chan)
> return !test_bit(CONF_CONNECT_PEND, &chan->conf_state);
> }
>
> +static bool __amp_capable(struct l2cap_chan *chan)
> +{
> + struct l2cap_conn *conn = chan->conn;
> +
> + if (enable_hs &&
> + chan->chan_policy == BT_CHANNEL_POLICY_AMP_PREFERRED &&
> + conn->fixed_chan_mask & L2CAP_FC_A2MP)
> + return true;
> + else
> + return false;
> +}
> +
> static void l2cap_send_conn_req(struct l2cap_chan *chan)
> {
> struct l2cap_conn *conn = chan->conn;
> @@ -972,6 +984,16 @@ static void l2cap_chan_ready(struct l2cap_chan *chan)
> chan->ops->ready(chan);
> }
>
> +static void l2cap_choose_conn(struct l2cap_chan *chan)
I find this function name a little confusing - "choose" sounds like it
is just making a decision. This function also takes the action of
starting physical link setup or sending a connection request, which is
more than just "choosing".
l2cap_start_connection, maybe?
> +{
> + if (__amp_capable(chan)) {
> + BT_DBG("chan %p AMP capable: discover AMPs", chan);
> + a2mp_discover_amp(chan);
> + } else {
> + l2cap_send_conn_req(chan);
> + }
> +}
> +
> static void l2cap_do_start(struct l2cap_chan *chan)
> {
> struct l2cap_conn *conn = chan->conn;
> @@ -986,8 +1008,9 @@ static void l2cap_do_start(struct l2cap_chan *chan)
> return;
>
> if (l2cap_chan_check_security(chan) &&
> - __l2cap_no_conn_pending(chan))
> - l2cap_send_conn_req(chan);
> + __l2cap_no_conn_pending(chan)) {
> + l2cap_choose_conn(chan);
> + }
> } else {
> struct l2cap_info_req req;
> req.type = __constant_cpu_to_le16(L2CAP_IT_FEAT_MASK);
> @@ -1082,7 +1105,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
> continue;
> }
>
> - l2cap_send_conn_req(chan);
> + l2cap_choose_conn(chan);
>
> } else if (chan->state == BT_CONNECT2) {
> struct l2cap_conn_rsp rsp;
> @@ -5454,7 +5477,7 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
>
> if (chan->state == BT_CONNECT) {
> if (!status) {
> - l2cap_send_conn_req(chan);
> + l2cap_choose_conn(chan);
> } else {
> __set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
> }
> --
> 1.7.9.5
--
Mat Martineau
The Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation
^ permalink raw reply
* Re: [PATCHv4 07/17] Bluetooth: AMP: Remote AMP ctrl definitions
From: Mat Martineau @ 2012-09-13 15:50 UTC (permalink / raw)
To: Andrei Emeltchenko; +Cc: linux-bluetooth, gustavo
In-Reply-To: <1347437192-24694-8-git-send-email-Andrei.Emeltchenko.news@gmail.com>
Andrei -
On Wed, 12 Sep 2012, Andrei Emeltchenko wrote:
> From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
>
> Create remote AMP controllers structure. It is used to keep information
> about discovered remote AMP controllers by A2MP protocol.
>
> Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
> ---
> include/net/bluetooth/a2mp.h | 3 ++
> include/net/bluetooth/pal.h | 14 ++++++++
> net/bluetooth/a2mp.c | 5 +++
> net/bluetooth/pal.c | 81 ++++++++++++++++++++++++++++++++++++++++++
> 4 files changed, 103 insertions(+)
>
> diff --git a/include/net/bluetooth/a2mp.h b/include/net/bluetooth/a2mp.h
> index f9010c0..93967f1 100644
> --- a/include/net/bluetooth/a2mp.h
> +++ b/include/net/bluetooth/a2mp.h
> @@ -31,6 +31,9 @@ struct amp_mgr {
> READ_LOC_AMP_ASSOC,
> } state;
> unsigned long flags;
> +
> + struct list_head amp_ctrls;
> + struct mutex amp_ctrls_lock;
> };
>
> struct a2mp_cmd {
> diff --git a/include/net/bluetooth/pal.h b/include/net/bluetooth/pal.h
> index a0f441b..918a4be 100644
> --- a/include/net/bluetooth/pal.h
> +++ b/include/net/bluetooth/pal.h
> @@ -20,6 +20,20 @@
> #include <net/bluetooth/a2mp.h>
> #include <net/bluetooth/amp.h>
>
> +struct amp_ctrl {
> + struct list_head list;
> + struct kref kref;
> + __u8 id;
> + __u16 assoc_len_so_far;
> + __u16 assoc_rem_len;
> + __u16 assoc_len;
> + __u8 *assoc;
> +};
I think you have the necessary information here. There should be no
need to also track the remote device in the amp_ctrl struct because
the amp_mgr that owns the list of controllers is only referring to one
remote device, right?
> +
> +int amp_ctrl_put(struct amp_ctrl *ctrl);
> +struct amp_ctrl *amp_ctrl_add(struct amp_mgr *mgr);
> +struct amp_ctrl *amp_ctrl_lookup(struct amp_mgr *mgr, u8 id);
> +void amp_ctrl_list_flush(struct amp_mgr *mgr);
> struct hci_conn *phylink_add(struct hci_dev *hdev, struct amp_mgr *mgr,
> u8 remote_id);
>
> diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
> index 8f236db..36bf0f4 100644
> --- a/net/bluetooth/a2mp.c
> +++ b/net/bluetooth/a2mp.c
> @@ -585,6 +585,7 @@ static void amp_mgr_destroy(struct kref *kref)
> list_del(&mgr->list);
> mutex_unlock(&_mgr_list_lock);
>
> + amp_ctrl_list_flush(mgr);
> kfree(mgr);
> }
>
> @@ -623,6 +624,10 @@ static struct amp_mgr *amp_mgr_create(struct l2cap_conn *conn)
> list_add(&mgr->list, &_mgr_list);
> mutex_unlock(&_mgr_list_lock);
>
> + /* Remote AMP ctrl list initialization */
> + INIT_LIST_HEAD(&mgr->amp_ctrls);
> + mutex_init(&mgr->amp_ctrls_lock);
> +
> kref_init(&mgr->kref);
>
> return mgr;
> diff --git a/net/bluetooth/pal.c b/net/bluetooth/pal.c
> index 3377ad1..7548644 100644
> --- a/net/bluetooth/pal.c
> +++ b/net/bluetooth/pal.c
> @@ -13,6 +13,87 @@
>
> #include <net/bluetooth/pal.h>
>
> +/* Remote AMP Controllers handling */
> +static void amp_ctrl_get(struct amp_ctrl *ctrl)
> +{
> + BT_DBG("ctrl %p orig refcnt %d", ctrl,
> + atomic_read(&ctrl->kref.refcount));
> +
> + kref_get(&ctrl->kref);
> +}
> +
> +static void amp_ctrl_destroy(struct kref *kref)
> +{
> + struct amp_ctrl *ctrl = container_of(kref, struct amp_ctrl, kref);
> +
> + BT_DBG("ctrl %p", ctrl);
> +
> + if (ctrl->assoc)
> + kfree(ctrl->assoc);
> +
> + kfree(ctrl);
> +}
> +
> +int amp_ctrl_put(struct amp_ctrl *ctrl)
> +{
> + BT_DBG("ctrl %p orig refcnt %d", ctrl,
> + atomic_read(&ctrl->kref.refcount));
> +
> + return kref_put(&ctrl->kref, &_ctrl_destroy);
> +}
> +
> +struct amp_ctrl *amp_ctrl_add(struct amp_mgr *mgr)
> +{
> + struct amp_ctrl *ctrl;
> +
> + ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL);
> + if (!ctrl)
> + return NULL;
> +
> + mutex_lock(&mgr->amp_ctrls_lock);
> + list_add(&ctrl->list, &mgr->amp_ctrls);
> + mutex_unlock(&mgr->amp_ctrls_lock);
> +
> + kref_init(&ctrl->kref);
> +
> + BT_DBG("mgr %p ctrl %p", mgr, ctrl);
> +
> + return ctrl;
> +}
> +
> +void amp_ctrl_list_flush(struct amp_mgr *mgr)
> +{
> + struct amp_ctrl *ctrl, *n;
> +
> + BT_DBG("mgr %p", mgr);
> +
> + mutex_lock(&mgr->amp_ctrls_lock);
> + list_for_each_entry_safe(ctrl, n, &mgr->amp_ctrls, list) {
> + list_del(&ctrl->list);
> + amp_ctrl_put(ctrl);
> + }
> + mutex_unlock(&mgr->amp_ctrls_lock);
> +}
> +
> +struct amp_ctrl *amp_ctrl_lookup(struct amp_mgr *mgr, u8 id)
> +{
> + struct amp_ctrl *ctrl = NULL;
> +
> + mutex_lock(&mgr->amp_ctrls_lock);
> + list_for_each_entry(ctrl, &mgr->amp_ctrls, list) {
> + if (ctrl->id == id)
> + break;
> + }
> + mutex_unlock(&mgr->amp_ctrls_lock);
> +
> + BT_DBG("mgr %p id %d ctrl %p", mgr, id, ctrl);
> +
> + if (ctrl)
> + amp_ctrl_get(ctrl);
> +
> + return ctrl;
> +}
> +
> /* Physical Link interface */
> static u8 __next_handle(struct amp_mgr *mgr)
> {
> --
> 1.7.9.5
--
Mat Martineau
The Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation
^ permalink raw reply
* Re: [PATCHv4 06/17] Bluetooth: AMP: Physical link struct and heplers
From: Mat Martineau @ 2012-09-13 15:40 UTC (permalink / raw)
To: Andrei Emeltchenko; +Cc: linux-bluetooth, gustavo
In-Reply-To: <1347437192-24694-7-git-send-email-Andrei.Emeltchenko.news@gmail.com>
On Wed, 12 Sep 2012, Andrei Emeltchenko wrote:
> From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
>
> Define physical link structures. Physical links are represented by
> hci_conn structure. For BR/EDR we use type ACL_LINK and for AMP
> we use AMP_LINK.
>
> Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
> ---
> include/net/bluetooth/hci.h | 1 +
> include/net/bluetooth/hci_core.h | 20 ++++++++++++++++++
> include/net/bluetooth/pal.h | 26 +++++++++++++++++++++++
> net/bluetooth/Makefile | 2 +-
> net/bluetooth/a2mp.c | 1 +
> net/bluetooth/pal.c | 42 ++++++++++++++++++++++++++++++++++++++
> 6 files changed, 91 insertions(+), 1 deletion(-)
> create mode 100644 include/net/bluetooth/pal.h
> create mode 100644 net/bluetooth/pal.c
>
> diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
> index 1cb8b55..4c41b8c 100644
> --- a/include/net/bluetooth/hci.h
> +++ b/include/net/bluetooth/hci.h
> @@ -207,6 +207,7 @@ enum {
> #define ESCO_LINK 0x02
> /* Low Energy links do not have defined link type. Use invented one */
> #define LE_LINK 0x80
> +#define AMP_LINK 0x81
>
> /* LMP features */
> #define LMP_3SLOT 0x01
> diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
> index 1174218..4ae5293 100644
> --- a/include/net/bluetooth/hci_core.h
> +++ b/include/net/bluetooth/hci_core.h
> @@ -316,6 +316,7 @@ struct hci_conn {
>
> __u8 remote_cap;
> __u8 remote_auth;
> + __u8 remote_id;
> bool flush_key;
>
> unsigned int sent;
> @@ -510,6 +511,25 @@ static inline struct hci_conn *hci_conn_hash_lookup_handle(struct hci_dev *hdev,
> return NULL;
> }
>
> +static inline struct hci_conn *hci_conn_hash_lookup_id(struct hci_dev *hdev,
> + __u8 remote_id)
> +{
> + struct hci_conn_hash *h = &hdev->conn_hash;
> + struct hci_conn *c;
> +
> + rcu_read_lock();
> +
> + list_for_each_entry_rcu(c, &h->list, list) {
> + if (c->remote_id == remote_id) {
> + rcu_read_unlock();
> + return c;
> + }
> + }
> + rcu_read_unlock();
> +
> + return NULL;
> +}
> +
If there are multiple AMP physical links to different devices, the
remote_id probably isn't enough information to look up a physical
link. Most of the time the remote_id will be "1", so there will
probably be multiple hci_conns with the same remote_id.
l2cap_conn + remote_id should be unique, though.
> static inline struct hci_conn *hci_conn_hash_lookup_ba(struct hci_dev *hdev,
> __u8 type, bdaddr_t *ba)
> {
> diff --git a/include/net/bluetooth/pal.h b/include/net/bluetooth/pal.h
> new file mode 100644
> index 0000000..a0f441b
> --- /dev/null
> +++ b/include/net/bluetooth/pal.h
> @@ -0,0 +1,26 @@
> +/*
> + Copyright (c) 2011,2012 Intel Corp.
> +
> + This program is free software; you can redistribute it and/or modify
> + it under the terms of the GNU General Public License version 2 and
> + only version 2 as published by the Free Software Foundation.
> +
> + 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.
> +*/
> +
> +#ifndef __PAL_H
> +#define __PAL_H
> +
> +#include <net/bluetooth/bluetooth.h>
> +#include <net/bluetooth/hci_core.h>
> +#include <net/bluetooth/l2cap.h>
> +#include <net/bluetooth/a2mp.h>
> +#include <net/bluetooth/amp.h>
> +
> +struct hci_conn *phylink_add(struct hci_dev *hdev, struct amp_mgr *mgr,
> + u8 remote_id);
> +
> +#endif /* __PAL_H */
> diff --git a/net/bluetooth/Makefile b/net/bluetooth/Makefile
> index dea6a28..3f76fc2 100644
> --- a/net/bluetooth/Makefile
> +++ b/net/bluetooth/Makefile
> @@ -10,4 +10,4 @@ obj-$(CONFIG_BT_HIDP) += hidp/
>
> bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o \
> hci_sock.o hci_sysfs.o l2cap_core.o l2cap_sock.o smp.o sco.o lib.o \
> - a2mp.o amp.o
> + a2mp.o amp.o pal.o
> diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
> index c876997..8f236db 100644
> --- a/net/bluetooth/a2mp.c
> +++ b/net/bluetooth/a2mp.c
> @@ -17,6 +17,7 @@
> #include <net/bluetooth/l2cap.h>
> #include <net/bluetooth/a2mp.h>
> #include <net/bluetooth/amp.h>
> +#include <net/bluetooth/pal.h>
>
> /* Global AMP Manager list */
> LIST_HEAD(amp_mgr_list);
> diff --git a/net/bluetooth/pal.c b/net/bluetooth/pal.c
> new file mode 100644
> index 0000000..3377ad1
> --- /dev/null
> +++ b/net/bluetooth/pal.c
> @@ -0,0 +1,42 @@
> +/*
> + Copyright (c) 2011,2012 Intel Corp.
> +
> + This program is free software; you can redistribute it and/or modify
> + it under the terms of the GNU General Public License version 2 and
> + only version 2 as published by the Free Software Foundation.
> +
> + 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.
> +*/
> +
> +#include <net/bluetooth/pal.h>
> +
> +/* Physical Link interface */
> +static u8 __next_handle(struct amp_mgr *mgr)
> +{
> + if (++mgr->handle == 0)
> + mgr->handle = 1;
> +
> + return mgr->handle;
> +}
> +
> +struct hci_conn *phylink_add(struct hci_dev *hdev, struct amp_mgr *mgr,
> + u8 remote_id)
> +{
> + struct hci_conn *hcon;
> +
> + hcon = hci_conn_add(hdev, AMP_LINK, BDADDR_ANY);
> + if (!hcon)
> + return NULL;
> +
> + hcon->state = BT_CONNECT;
> + hcon->out = true;
> + hcon->attempt++;
> + hcon->handle = __next_handle(mgr);
> + hcon->remote_id = remote_id;
> + hcon->amp_mgr = mgr;
> +
> + return hcon;
> +}
> --
> 1.7.9.5
--
Mat Martineau
The Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation
^ permalink raw reply
* Connecting to Bluetooth Low Energy devices
From: Philipp Claves @ 2012-09-13 15:34 UTC (permalink / raw)
To: linux-bluetooth
Hello
Trying to get started with Bluetooth Low Energy devices, i used hcitool and
gatttool to enumerate device attributes, but did not get far:
# hcitool lescan
LE Scan ...
<MAC-Device1> Battery V1.0
<MAC-Device1> (unknown)
<MAC-Device2> Battery V1.0
<MAC-Device2> (unknown)
^C
# gatttool -b <MAC-Device1> -I
[ ][<MAC-Device1>][LE]> connect
Connecting... connect error: connect error: Connection refused (111)
[ ][<MAC-Device1>][LE]>
This is all i get.
The devices are Nordic Semiconductor nRF8001 based and currently run a simple
BTLE demo application by Nordic Semiconductor. It does not use bind/paring but
simple connect. Unfornately that doesn't seem to work.
The host uses an of-the-shelf USB Bluetooth 4.0 Stick with a Broadcom
BCM20702A0 Chip inside.
Am i doing something obviously wrong?
Any tips where to get more information about the error (dmesg shows nothing)?
Regards
Philipp Claves
--
Budelmann Elektronik GmbH
Von-Renesse-Weg 60
48163 Münster
Germany
Tel. +49 (0)2501 9208440
Fax +49 (0)2501 5887024
claves@budelmann-elektronik.com
www.budelmann-elektronik.com
^ permalink raw reply
* Re: [PATCHv4 04/17] Bluetooth: AMP: Use HCI cmd to Read Loc AMP Assoc
From: Mat Martineau @ 2012-09-13 15:28 UTC (permalink / raw)
To: Andrei Emeltchenko; +Cc: linux-bluetooth, gustavo
In-Reply-To: <1347437192-24694-5-git-send-email-Andrei.Emeltchenko.news@gmail.com>
Andrei -
On Wed, 12 Sep 2012, Andrei Emeltchenko wrote:
> From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
>
> When receiving A2MP Get AMP Assoc Request execute Read Local AMP Assoc
> HCI command to AMP controller. If the AMP Assoc data is larger then it
> can fit to HCI event only fragment is read. When all fragments are read
> send A2MP Get AMP Assoc Response.
>
> Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
> ---
> include/net/bluetooth/a2mp.h | 2 ++
> include/net/bluetooth/amp.h | 21 +++++++++++++++++
> include/net/bluetooth/hci.h | 2 ++
> include/net/bluetooth/hci_core.h | 8 +++++++
> net/bluetooth/Makefile | 2 +-
> net/bluetooth/a2mp.c | 48 +++++++++++++++++++++++++++++++++-----
> net/bluetooth/amp.c | 45 +++++++++++++++++++++++++++++++++++
> net/bluetooth/hci_event.c | 41 ++++++++++++++++++++++++++++++++
> 8 files changed, 162 insertions(+), 7 deletions(-)
> create mode 100644 include/net/bluetooth/amp.h
> create mode 100644 net/bluetooth/amp.c
>
> diff --git a/include/net/bluetooth/a2mp.h b/include/net/bluetooth/a2mp.h
> index c21268a..f9010c0 100644
> --- a/include/net/bluetooth/a2mp.h
> +++ b/include/net/bluetooth/a2mp.h
> @@ -28,6 +28,7 @@ struct amp_mgr {
> __u8 handle;
> enum {
> READ_LOC_AMP_INFO,
> + READ_LOC_AMP_ASSOC,
> } state;
> unsigned long flags;
> };
> @@ -132,5 +133,6 @@ struct l2cap_chan *a2mp_channel_create(struct l2cap_conn *conn,
> struct amp_mgr *amp_mgr_lookup_by_state(u8 state);
> void a2mp_send(struct amp_mgr *mgr, u8 code, u8 ident, u16 len, void *data);
> void a2mp_send_getinfo_rsp(struct hci_dev *hdev);
> +void a2mp_send_getampassoc_rsp(struct hci_dev *hdev, u8 status);
>
> #endif /* __A2MP_H */
> diff --git a/include/net/bluetooth/amp.h b/include/net/bluetooth/amp.h
> new file mode 100644
> index 0000000..e861675
> --- /dev/null
> +++ b/include/net/bluetooth/amp.h
> @@ -0,0 +1,21 @@
> +/*
> + Copyright (c) 2011,2012 Intel Corp.
> +
> + This program is free software; you can redistribute it and/or modify
> + it under the terms of the GNU General Public License version 2 and
> + only version 2 as published by the Free Software Foundation.
> +
> + 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.
> +*/
> +
> +#ifndef __AMP_H
> +#define __AMP_H
> +
> +void amp_read_loc_info(struct hci_dev *hdev, struct amp_mgr *mgr);
> +void amp_read_loc_assoc_frag(struct hci_dev *hdev, u8 phy_handle);
> +void amp_read_loc_assoc(struct hci_dev *hdev, struct amp_mgr *mgr);
> +
> +#endif /* __AMP_H */
> diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
> index 42aae18..1cb8b55 100644
> --- a/include/net/bluetooth/hci.h
> +++ b/include/net/bluetooth/hci.h
> @@ -33,6 +33,8 @@
> #define HCI_LINK_KEY_SIZE 16
> #define HCI_AMP_LINK_KEY_SIZE (2 * HCI_LINK_KEY_SIZE)
>
> +#define HCI_MAX_AMP_ASSOC_SIZE 672
> +
> /* HCI dev events */
> #define HCI_DEV_REG 1
> #define HCI_DEV_UNREG 2
> diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
> index 6a3337e..1174218 100644
> --- a/include/net/bluetooth/hci_core.h
> +++ b/include/net/bluetooth/hci_core.h
> @@ -124,6 +124,12 @@ struct le_scan_params {
>
> #define HCI_MAX_SHORT_NAME_LENGTH 10
>
> +struct amp_assoc {
> + __u16 len;
> + __u16 offset;
> + __u8 data[HCI_MAX_AMP_ASSOC_SIZE];
> +};
> +
> #define NUM_REASSEMBLY 4
> struct hci_dev {
> struct list_head list;
> @@ -177,6 +183,8 @@ struct hci_dev {
> __u32 amp_max_flush_to;
> __u32 amp_be_flush_to;
>
> + struct amp_assoc loc_assoc;
> +
> __u8 flow_ctl_mode;
>
> unsigned int auto_accept_delay;
> diff --git a/net/bluetooth/Makefile b/net/bluetooth/Makefile
> index fa6d94a..dea6a28 100644
> --- a/net/bluetooth/Makefile
> +++ b/net/bluetooth/Makefile
> @@ -10,4 +10,4 @@ obj-$(CONFIG_BT_HIDP) += hidp/
>
> bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o \
> hci_sock.o hci_sysfs.o l2cap_core.o l2cap_sock.o smp.o sco.o lib.o \
> - a2mp.o
> + a2mp.o amp.o
> diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
> index 7b98250..27ebf31 100644
> --- a/net/bluetooth/a2mp.c
> +++ b/net/bluetooth/a2mp.c
> @@ -16,6 +16,7 @@
> #include <net/bluetooth/hci_core.h>
> #include <net/bluetooth/l2cap.h>
> #include <net/bluetooth/a2mp.h>
> +#include <net/bluetooth/amp.h>
>
> /* Global AMP Manager list */
> LIST_HEAD(amp_mgr_list);
> @@ -232,15 +233,16 @@ static int a2mp_getampassoc_req(struct amp_mgr *mgr, struct sk_buff *skb,
>
> a2mp_send(mgr, A2MP_GETAMPASSOC_RSP, hdr->ident, sizeof(rsp),
> &rsp);
> - goto clean;
> - }
>
> - /* Placeholder for HCI Read AMP Assoc */
> + if (hdev)
> + hci_dev_put(hdev);
>
> -clean:
> - if (hdev)
> - hci_dev_put(hdev);
> + goto done;
> + }
> +
> + amp_read_loc_assoc(hdev, mgr);
>
> +done:
> skb_pull(skb, sizeof(*req));
> return 0;
> }
> @@ -624,3 +626,37 @@ void a2mp_send_getinfo_rsp(struct hci_dev *hdev)
> a2mp_send(mgr, A2MP_GETINFO_RSP, mgr->ident, sizeof(rsp), &rsp);
> amp_mgr_put(mgr);
> }
> +
> +void a2mp_send_getampassoc_rsp(struct hci_dev *hdev, u8 status)
> +{
> + struct amp_mgr *mgr;
> + struct amp_assoc *loc_assoc = &hdev->loc_assoc;
> + struct a2mp_amp_assoc_rsp *rsp;
> + size_t len;
> +
> + mgr = amp_mgr_lookup_by_state(READ_LOC_AMP_ASSOC);
What if multiple amp managers are in the READ_LOC_AMP_ASSOC state?
Is that possible if multiple remote devices send GETAMPASSOC at the
same time?
> + if (!mgr)
> + return;
> +
> + BT_DBG("%s mgr %p", hdev->name, mgr);
> +
> + len = sizeof(struct a2mp_amp_assoc_rsp) + loc_assoc->len;
> + rsp = kzalloc(len, GFP_KERNEL);
> + if (!rsp) {
> + amp_mgr_put(mgr);
> + return;
> + }
> +
> + rsp->id = hdev->id;
> +
> + if (status) {
> + rsp->status = A2MP_STATUS_INVALID_CTRL_ID;
> + } else {
> + rsp->status = A2MP_STATUS_SUCCESS;
> + memcpy(rsp->amp_assoc, loc_assoc->data, loc_assoc->len);
> + }
> +
> + a2mp_send(mgr, A2MP_GETAMPASSOC_RSP, mgr->ident, len, rsp);
> + amp_mgr_put(mgr);
> + kfree(rsp);
> +}
> diff --git a/net/bluetooth/amp.c b/net/bluetooth/amp.c
> new file mode 100644
> index 0000000..2d4e79e
> --- /dev/null
> +++ b/net/bluetooth/amp.c
> @@ -0,0 +1,45 @@
> +/*
> + Copyright (c) 2011,2012 Intel Corp.
> +
> + This program is free software; you can redistribute it and/or modify
> + it under the terms of the GNU General Public License version 2 and
> + only version 2 as published by the Free Software Foundation.
> +
> + 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.
> +*/
> +
> +#include <net/bluetooth/bluetooth.h>
> +#include <net/bluetooth/hci.h>
> +#include <net/bluetooth/hci_core.h>
> +#include <net/bluetooth/a2mp.h>
> +#include <net/bluetooth/amp.h>
> +
> +void amp_read_loc_assoc_frag(struct hci_dev *hdev, u8 phy_handle)
> +{
> + struct hci_cp_read_local_amp_assoc cp;
> + struct amp_assoc *loc_assoc = &hdev->loc_assoc;
> +
> + BT_DBG("%s handle %d", hdev->name, phy_handle);
> +
> + cp.phy_handle = phy_handle;
> + cp.max_len = cpu_to_le16(hdev->amp_assoc_size);
> + cp.len_so_far = cpu_to_le16(loc_assoc->offset);
> +
> + hci_send_cmd(hdev, HCI_OP_READ_LOCAL_AMP_ASSOC, sizeof(cp), &cp);
> +}
> +
> +void amp_read_loc_assoc(struct hci_dev *hdev, struct amp_mgr *mgr)
> +{
> + struct hci_cp_read_local_amp_assoc cp;
> +
> + memset(&hdev->loc_assoc, 0, sizeof(struct amp_assoc));
> + memset(&cp, 0, sizeof(cp));
> +
> + cp.max_len = cpu_to_le16(hdev->amp_assoc_size);
> +
> + mgr->state = READ_LOC_AMP_ASSOC;
> + hci_send_cmd(hdev, HCI_OP_READ_LOCAL_AMP_ASSOC, sizeof(cp), &cp);
> +}
> diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
> index 5ae5121..6cc44cf 100644
> --- a/net/bluetooth/hci_event.c
> +++ b/net/bluetooth/hci_event.c
> @@ -31,6 +31,7 @@
> #include <net/bluetooth/hci_core.h>
> #include <net/bluetooth/mgmt.h>
> #include <net/bluetooth/a2mp.h>
> +#include <net/bluetooth/amp.h>
>
> /* Handle HCI Event packets */
>
> @@ -866,6 +867,42 @@ a2mp_rsp:
> a2mp_send_getinfo_rsp(hdev);
> }
>
> +static void hci_cc_read_local_amp_assoc(struct hci_dev *hdev,
> + struct sk_buff *skb)
> +{
> + struct hci_rp_read_local_amp_assoc *rp = (void *) skb->data;
> + struct amp_assoc *assoc = &hdev->loc_assoc;
> + size_t rem_len, frag_len;
> +
> + BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
> +
> + if (rp->status)
> + goto a2mp_rsp;
> +
> + frag_len = skb->len - sizeof(*rp);
> + rem_len = __le16_to_cpu(rp->rem_len);
> +
> + if (rem_len > frag_len) {
> + BT_DBG("frag_len %d rem_len %d", frag_len, rem_len);
> +
> + memcpy(assoc->data + assoc->offset, rp->frag, frag_len);
> + assoc->offset += frag_len;
> +
> + /* Read other fragments */
> + amp_read_loc_assoc_frag(hdev, rp->phy_handle);
> +
> + return;
> + }
> +
> + memcpy(assoc->data + assoc->offset, rp->frag, rem_len);
> + assoc->len = assoc->offset + rem_len;
> + assoc->offset = 0;
> +
> +a2mp_rsp:
> + /* Send A2MP Rsp when all fragments are received */
> + a2mp_send_getampassoc_rsp(hdev, rp->status);
> +}
> +
> static void hci_cc_delete_stored_link_key(struct hci_dev *hdev,
> struct sk_buff *skb)
> {
> @@ -2302,6 +2339,10 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
> hci_cc_read_local_amp_info(hdev, skb);
> break;
>
> + case HCI_OP_READ_LOCAL_AMP_ASSOC:
> + hci_cc_read_local_amp_assoc(hdev, skb);
> + break;
> +
> case HCI_OP_DELETE_STORED_LINK_KEY:
> hci_cc_delete_stored_link_key(hdev, skb);
> break;
> --
> 1.7.9.5
--
Mat Martineau
The Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation
^ permalink raw reply
* Re: [PATCHv4 02/17] Bluetooth: A2MP: Create amp_mgr global list
From: Mat Martineau @ 2012-09-13 15:02 UTC (permalink / raw)
To: Andrei Emeltchenko; +Cc: linux-bluetooth, gustavo
In-Reply-To: <1347437192-24694-3-git-send-email-Andrei.Emeltchenko.news@gmail.com>
Andrei -
On Wed, 12 Sep 2012, Andrei Emeltchenko wrote:
> From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
>
> Create amp_mgr_list global list which will be used by different
> hci devices to find amp_mgr.
>
> Signed-off-by: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
> ---
> include/net/bluetooth/a2mp.h | 8 ++++++++
> net/bluetooth/a2mp.c | 29 +++++++++++++++++++++++++++++
> 2 files changed, 37 insertions(+)
>
> diff --git a/include/net/bluetooth/a2mp.h b/include/net/bluetooth/a2mp.h
> index 6a76e0a..e56d656 100644
> --- a/include/net/bluetooth/a2mp.h
> +++ b/include/net/bluetooth/a2mp.h
> @@ -20,11 +20,15 @@
> #define A2MP_FEAT_EXT 0x8000
>
> struct amp_mgr {
> + struct list_head list;
> struct l2cap_conn *l2cap_conn;
> struct l2cap_chan *a2mp_chan;
> struct kref kref;
> __u8 ident;
> __u8 handle;
> + enum {
> + READ_LOC_AMP_INFO,
> + } state;
> unsigned long flags;
> };
>
> @@ -118,9 +122,13 @@ struct a2mp_physlink_rsp {
> #define A2MP_STATUS_PHYS_LINK_EXISTS 0x05
> #define A2MP_STATUS_SECURITY_VIOLATION 0x06
>
> +extern struct list_head amp_mgr_list;
> +extern struct mutex amp_mgr_list_lock;
> +
> void amp_mgr_get(struct amp_mgr *mgr);
> int amp_mgr_put(struct amp_mgr *mgr);
> struct l2cap_chan *a2mp_channel_create(struct l2cap_conn *conn,
> struct sk_buff *skb);
> +struct amp_mgr *amp_mgr_lookup_by_state(u8 state);
>
> #endif /* __A2MP_H */
> diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
> index 0760d1f..6b7a4b4 100644
> --- a/net/bluetooth/a2mp.c
> +++ b/net/bluetooth/a2mp.c
> @@ -17,6 +17,10 @@
> #include <net/bluetooth/l2cap.h>
> #include <net/bluetooth/a2mp.h>
>
> +/* Global AMP Manager list */
> +LIST_HEAD(amp_mgr_list);
> +DEFINE_MUTEX(amp_mgr_list_lock);
> +
> /* A2MP build & send command helper functions */
> static struct a2mp_cmd *__a2mp_build(u8 code, u8 ident, u16 len, void *data)
> {
> @@ -516,6 +520,10 @@ static void amp_mgr_destroy(struct kref *kref)
>
> BT_DBG("mgr %p", mgr);
>
> + mutex_lock(&_mgr_list_lock);
> + list_del(&mgr->list);
> + mutex_unlock(&_mgr_list_lock);
> +
> kfree(mgr);
> }
>
> @@ -550,6 +558,10 @@ static struct amp_mgr *amp_mgr_create(struct l2cap_conn *conn)
>
> conn->hcon->amp_mgr = mgr;
>
> + mutex_lock(&_mgr_list_lock);
> + list_add(&mgr->list, &_mgr_list);
> + mutex_unlock(&_mgr_list_lock);
> +
> kref_init(&mgr->kref);
Should the reference count be initialized before adding to the list?
>
> return mgr;
> @@ -570,3 +582,20 @@ struct l2cap_chan *a2mp_channel_create(struct l2cap_conn *conn,
>
> return mgr->a2mp_chan;
> }
> +
> +struct amp_mgr *amp_mgr_lookup_by_state(u8 state)
> +{
> + struct amp_mgr *mgr;
> +
> + mutex_lock(&_mgr_list_lock);
> + list_for_each_entry(mgr, &_mgr_list, list) {
> + if (mgr->state == state) {
> + amp_mgr_get(mgr);
> + mutex_unlock(&_mgr_list_lock);
> + return mgr;
> + }
> + }
> + mutex_unlock(&_mgr_list_lock);
> +
> + return NULL;
> +}
> --
> 1.7.9.5
--
Mat Martineau
The Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
hosted by The Linux Foundation
^ permalink raw reply
* Re: [PATCH v2 09/10] battery: Add support for notifications
From: Anderson Lizardo @ 2012-09-13 14:50 UTC (permalink / raw)
To: chen.ganir; +Cc: linux-bluetooth
In-Reply-To: <1347541403-11780-10-git-send-email-chen.ganir@ti.com>
Hi Chen,
On Thu, Sep 13, 2012 at 9:03 AM, <chen.ganir@ti.com> wrote:
> static void battery_free(gpointer user_data)
> {
> struct battery *batt = user_data;
> @@ -99,6 +109,14 @@ static void battery_free(gpointer user_data)
> if (batt->attrib != NULL)
> g_attrib_unref(batt->attrib);
>
> + if (batt->attrib != NULL) {
You are still repeating the if (batt->attrib != NULL) check here like
Joao mentioned (see above). Instead, you should merge the "if
(batt->attnotid)" block into the existing "if (batt->attrib != NULL)"
block.
> + 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);
> g_free(batt);
Regards,
--
Anderson Lizardo
Instituto Nokia de Tecnologia - INdT
Manaus - Brazil
^ permalink raw reply
* Re: [PATCH v2 08/10] battery: Read Battery level characteristic
From: Anderson Lizardo @ 2012-09-13 14:47 UTC (permalink / raw)
To: chen.ganir; +Cc: linux-bluetooth
In-Reply-To: <1347541403-11780-9-git-send-email-chen.ganir@ti.com>
Hi Chen,
On Thu, Sep 13, 2012 at 9:03 AM, <chen.ganir@ti.com> wrote:
> +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) {
> + error("Failed to read Battery Level: Protocol error\n");
> + return;
> + }
You should check for vlen < 0 instead. See dec_read_resp()
implementation (there may be other places with this bug in bluez as
well, feel free to fix them if you find).
Also note that messages in error() should not contain "\n" (I've seen
this in other patches on the series as well).
> +
> + if (vlen < 1) {
> + error("Failed to read Battery Level: Wrong pdu len");
> + return;
> + }
What about checking for "vlen != 1" instead ?
> +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 NULL;
Shouldn't it be a "continue" above instead of "return NULL" ?
Otherwise the loop will never go past the first server.
> +
> + return b->data;
> + }
> +
> + return NULL;
> +}
Regards,
--
Anderson Lizardo
Instituto Nokia de Tecnologia - INdT
Manaus - Brazil
^ permalink raw reply
* Re: Wii Balance Board vs. bluez
From: David Herrmann @ 2012-09-13 14:39 UTC (permalink / raw)
To: Florian Echtler; +Cc: linux-bluetooth
In-Reply-To: <CANq1E4RmacRAkTVtRt2JH_+V=qn1AH3iJWZZS_LCqmj_yt4DoQ@mail.gmail.com>
[-- Attachment #1: Type: text/plain, Size: 804 bytes --]
On Thu, Sep 13, 2012 at 4:38 PM, David Herrmann
<dh.herrmann@googlemail.com> wrote:
> Hi Florian
>
> On Thu, Sep 13, 2012 at 7:59 AM, Florian Echtler <floe@butterbrot.org> wrote:
>>
>>
>> David Herrmann <dh.herrmann@googlemail.com> wrote:
>>>However, if you are willing to test it, I will send some patches which
>>>will implement it.
>> Absolutely, I'd be happy to test.
>
> Please see the appended patch. You have to apply it to your kernel
> tree and recompile the hid-wiimote driver. No other sources are
> changed so you don't need to reboot or install the new kernel. Just
> install the new hid-wiimote.ko module.
>
> One of the 5 input devices should then report the wiimote weight
> sensor data. (the input device with name "Wii Remote Balance Board").
Forgot to attach the patch... Here it is.
[-- Attachment #2: wiimote_balance_board.patch --]
[-- Type: application/octet-stream, Size: 3082 bytes --]
diff --git a/drivers/hid/hid-wiimote-ext.c b/drivers/hid/hid-wiimote-ext.c
index d37cd09..ae7c1b6 100644
--- a/drivers/hid/hid-wiimote-ext.c
+++ b/drivers/hid/hid-wiimote-ext.c
@@ -34,6 +34,7 @@ enum wiiext_type {
WIIEXT_NONE, /* placeholder */
WIIEXT_CLASSIC, /* Nintendo classic controller */
WIIEXT_NUNCHUCK, /* Nintendo nunchuck controller */
+ WIIEXT_BALANCE_BOARD, /* Nintendo balance board controller */
};
enum wiiext_keys {
@@ -151,6 +152,11 @@ static __u8 ext_read(struct wiimote_ext *ext)
type = WIIEXT_NUNCHUCK;
else if (rmem[0] == 0x01 && rmem[1] == 0x01)
type = WIIEXT_CLASSIC;
+ else if (rmem[0] == 0x04 && rmem[1] == 0x02)
+ type = WIIEXT_BALANCE_BOARD;
+ else
+ hid_info(ext->wdata->hdev, "Unknown extension device (%x%x)\n",
+ rmem[0], rmem[1]);
}
wiimote_cmd_release(ext->wdata);
@@ -509,6 +515,48 @@ static void handler_classic(struct wiimote_ext *ext, const __u8 *payload)
input_sync(ext->input);
}
+static void handler_balance_board(struct wiimote_ext *ext, const __u8 *payload)
+{
+ __s16 tr, br, tl, bl;
+
+ /* Byte | 8 7 6 5 4 3 2 1 |
+ * -----+--------------------------+
+ * 1 | Top Right <15:8> |
+ * 2 | Top Right <7:0> |
+ * -----+--------------------------+
+ * 3 | Bottom Right <15:8> |
+ * 4 | Bottom Right <7:0> |
+ * -----+--------------------------+
+ * 5 | Top Left <15:8> |
+ * 6 | Top Left <7:0> |
+ * -----+--------------------------+
+ * 7 | Bottom Left <15:8> |
+ * 8 | Bottom Left <7:0> |
+ * -----+--------------------------+
+ *
+ * These values represent the weight-measurements of the Wii-balance
+ * board with 16bit precision.
+ *
+ * The balance-board is never reported interleaved with motionp.
+ */
+
+ tr = payload[0] << 8;
+ tr |= payload[1];
+ br = payload[2] << 8;
+ br |= payload[3];
+ tl = payload[4] << 8;
+ tl |= payload[5];
+ bl = payload[6] << 8;
+ bl |= payload[7];
+
+ input_report_abs(ext->input, ABS_HAT0X, tl);
+ input_report_abs(ext->input, ABS_HAT0Y, tr);
+ input_report_abs(ext->input, ABS_HAT1X, bl);
+ input_report_abs(ext->input, ABS_HAT1Y, br);
+
+ input_sync(ext->input);
+}
+
/* call this with state.lock spinlock held */
void wiiext_handle(struct wiimote_data *wdata, const __u8 *payload)
{
@@ -523,6 +571,8 @@ void wiiext_handle(struct wiimote_data *wdata, const __u8 *payload)
handler_nunchuck(ext, payload);
} else if (ext->ext_type == WIIEXT_CLASSIC) {
handler_classic(ext, payload);
+ } else if (ext->ext_type == WIIEXT_BALANCE_BOARD) {
+ handler_balance_board(ext, payload);
}
}
@@ -551,6 +601,11 @@ static ssize_t wiiext_show(struct device *dev, struct device_attribute *attr,
return sprintf(buf, "motionp+classic\n");
else
return sprintf(buf, "classic\n");
+ } else if (type == WIIEXT_BALANCE_BOARD) {
+ if (motionp)
+ return sprintf(buf, "motionp+balanceboard\n");
+ else
+ return sprintf(buf, "balanceboard\n");
} else {
if (motionp)
return sprintf(buf, "motionp\n");
^ permalink raw reply related
* Re: Wii Balance Board vs. bluez
From: David Herrmann @ 2012-09-13 14:38 UTC (permalink / raw)
To: Florian Echtler; +Cc: linux-bluetooth
In-Reply-To: <ed6fbaf1-1410-4539-a36e-1d6d6f6220b5@email.android.com>
Hi Florian
On Thu, Sep 13, 2012 at 7:59 AM, Florian Echtler <floe@butterbrot.org> wrote:
>
>
> David Herrmann <dh.herrmann@googlemail.com> wrote:
>>However, if you are willing to test it, I will send some patches which
>>will implement it.
> Absolutely, I'd be happy to test.
Please see the appended patch. You have to apply it to your kernel
tree and recompile the hid-wiimote driver. No other sources are
changed so you don't need to reboot or install the new kernel. Just
install the new hid-wiimote.ko module.
One of the 5 input devices should then report the wiimote weight
sensor data. (the input device with name "Wii Remote Balance Board").
>>Ouh, I see. I will send a patch fixing this to the BlueZ mailing list.
>>I will put you on CC if you don't mind.
> Thanks, I'll test this later today.
>
> One additional question: it looks like this problem with the pairing is going
> to pop up again with 3rd-party controllers, the new Wii U controller etc.
> Would it make sense to create a new PIN option which users can select
> explicitly?
No. First: there are very restrictive time-constraints on most of
these devices so user-input would be too slow. Second: The BlueZ
maintainers don't like this approach.
So just send an email to the linux-bluetooth mailing list and we will
add quirks to BlueZ so new devices will work, too.
Regards
David
^ permalink raw reply
* [PATCH v5 17/17] heartrate: Add test script
From: Andrzej Kaczmarek @ 2012-09-13 14:31 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Rafal Garbat
In-Reply-To: <1347546711-19961-1-git-send-email-andrzej.kaczmarek@tieto.com>
From: Rafal Garbat <rafal.garbat@tieto.com>
---
Makefile.tools | 4 +-
test/test-heartrate | 103 ++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 105 insertions(+), 2 deletions(-)
create mode 100755 test/test-heartrate
diff --git a/Makefile.tools b/Makefile.tools
index d3b6f57..f59a7c4 100644
--- a/Makefile.tools
+++ b/Makefile.tools
@@ -209,7 +209,7 @@ EXTRA_DIST += test/sap_client.py test/hsplay test/hsmicro \
test/test-network test/simple-agent test/simple-service \
test/simple-endpoint test/test-audio test/test-input \
test/test-sap-server test/test-oob test/test-attrib \
- test/test-proximity test/test-thermometer test/test-health \
- test/test-health-sink test/service-record.dtd \
+ test/test-proximity test/test-thermometer test/test-heartrate \
+ test/test-health test/test-health-sink test/service-record.dtd \
test/service-did.xml test/service-spp.xml test/service-opp.xml \
test/service-ftp.xml test/simple-player test/test-nap
diff --git a/test/test-heartrate b/test/test-heartrate
new file mode 100755
index 0000000..316375d
--- /dev/null
+++ b/test/test-heartrate
@@ -0,0 +1,103 @@
+#!/usr/bin/python
+
+from __future__ import absolute_import, print_function, unicode_literals
+
+'''
+Heart Rate Monitor test script
+'''
+
+import gobject
+
+import sys
+import dbus
+import dbus.service
+import dbus.mainloop.glib
+from optparse import OptionParser, make_option
+
+class Watcher(dbus.service.Object):
+ @dbus.service.method("org.bluez.HeartRateWatcher",
+ in_signature="oa{sv}", out_signature="")
+ def MeasurementReceived(self, device, measure):
+ print("Measurement received from %s" % device)
+ print("Value: ", measure["Value"])
+
+ if "Energy" in measure:
+ print("Energy: ", measure["Energy"])
+
+ if "Contact" in measure:
+ print("Contact: ", measure["Contact"])
+
+ if "Interval" in measure:
+ for i in measure["Interval"]:
+ print("Interval: ", i)
+
+if __name__ == "__main__":
+ dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
+
+ bus = dbus.SystemBus()
+
+ manager = dbus.Interface(bus.get_object("org.bluez", "/"),
+ "org.bluez.Manager")
+
+ option_list = [
+ make_option("-i", "--adapter", action="store",
+ type="string", dest="adapter"),
+ make_option("-b", "--device", action="store",
+ type="string", dest="address"),
+ ]
+
+ parser = OptionParser(option_list=option_list)
+
+ (options, args) = parser.parse_args()
+
+ if not options.address:
+ print("Usage: %s [-i <adapter>] -b <bdaddr> [cmd]" % (sys.argv[0]))
+ print("Possible commands:")
+ print("\tReset")
+ sys.exit(1)
+
+ if options.adapter:
+ adapter_path = manager.FindAdapter(options.adapter)
+ else:
+ adapter_path = manager.DefaultAdapter()
+
+ adapter = dbus.Interface(bus.get_object("org.bluez", adapter_path),
+ "org.bluez.Adapter")
+
+ heartrateManager = dbus.Interface(bus.get_object("org.bluez",
+ adapter_path), "org.bluez.HeartRateManager")
+
+ path = "/test/watcher"
+ heartrateManager.RegisterWatcher(path)
+
+ device_path = adapter.FindDevice(options.address)
+
+ device = dbus.Interface(bus.get_object("org.bluez", device_path),
+ "org.bluez.Device")
+
+ heartrate = dbus.Interface(bus.get_object("org.bluez",
+ device_path), "org.bluez.HeartRate")
+
+ watcher = Watcher(bus, path)
+
+ properties = heartrate.GetProperties()
+
+ if "Location" in properties:
+ print("Sensor location: %s" % properties["Location"])
+ else:
+ print("Sensor location is not supported")
+
+ if len(args) > 0:
+ if args[0] == "Reset":
+ reset_sup = properties["ResetSupported"]
+ if reset_sup:
+ heartrate.Reset()
+ else:
+ print("Reset not supported")
+ sys.exit(1)
+ else:
+ print("unknown command")
+ sys.exit(1)
+
+ mainloop = gobject.MainLoop()
+ mainloop.run()
--
1.7.11.3
^ permalink raw reply related
* [PATCH v5 16/17] heartrate: Add HeartRateWatcher interface to default policy
From: Andrzej Kaczmarek @ 2012-09-13 14:31 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Rafal Garbat
In-Reply-To: <1347546711-19961-1-git-send-email-andrzej.kaczmarek@tieto.com>
From: Rafal Garbat <rafal.garbat@tieto.com>
---
src/bluetooth.conf | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/bluetooth.conf b/src/bluetooth.conf
index 664dbd9..77a9371 100644
--- a/src/bluetooth.conf
+++ b/src/bluetooth.conf
@@ -16,6 +16,7 @@
<allow send_interface="org.bluez.MediaPlayer"/>
<allow send_interface="org.bluez.Watcher"/>
<allow send_interface="org.bluez.ThermometerWatcher"/>
+ <allow send_interface="org.bluez.HeartRateWatcher"/>
</policy>
<policy at_console="true">
--
1.7.11.3
^ permalink raw reply related
* [PATCH v5 15/17] heartrate: Add GetProperties method
From: Andrzej Kaczmarek @ 2012-09-13 14:31 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Rafal Garbat
In-Reply-To: <1347546711-19961-1-git-send-email-andrzej.kaczmarek@tieto.com>
From: Rafal Garbat <rafal.garbat@tieto.com>
---
profiles/heartrate/heartrate.c | 57 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 57 insertions(+)
diff --git a/profiles/heartrate/heartrate.c b/profiles/heartrate/heartrate.c
index 48d3cd1..43f94c1 100644
--- a/profiles/heartrate/heartrate.c
+++ b/profiles/heartrate/heartrate.c
@@ -104,6 +104,25 @@ struct watcher {
static GSList *heartrate_adapters = NULL;
+static const char * const location_type[] = {
+ "Other",
+ "Chest",
+ "Wrist",
+ "Finger",
+ "Hand",
+ "Earlobe",
+ "Foot"
+};
+
+static const gchar *location2str(uint8_t value)
+{
+ if (value < G_N_ELEMENTS(location_type))
+ return location_type[value];
+
+ error("Location type %d reserved for future use", value);
+ return NULL;
+}
+
static gint cmp_adapter(gconstpointer a, gconstpointer b)
{
const struct heartrate_adapter *hra = a;
@@ -410,6 +429,41 @@ static DBusMessage *unregister_watcher(DBusConnection *conn, DBusMessage *msg,
return dbus_message_new_method_return(msg);
}
+static DBusMessage *get_properties(DBusConnection *conn, DBusMessage *msg,
+ void *data)
+{
+ struct heartrate *hr = 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);
+
+ if (hr->has_location) {
+ char *loc = g_strdup(location2str(hr->location));
+
+ dict_append_entry(&dict, "Location", DBUS_TYPE_STRING, &loc);
+
+ g_free(loc);
+ }
+
+ dict_append_entry(&dict, "ResetSupported", DBUS_TYPE_BOOLEAN,
+ &hr->has_cp_reset);
+
+ dbus_message_iter_close_container(&iter, &dict);
+
+ return reply;
+}
+
static gint process_att_reset(struct heartrate *hr)
{
struct characteristic *ch;
@@ -458,6 +512,9 @@ static const GDBusMethodTable heartrate_manager_methods[] = {
};
static const GDBusMethodTable heartrate_device_methods[] = {
+ { GDBUS_METHOD("GetProperties",
+ NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
+ get_properties) },
{ GDBUS_METHOD("Reset", NULL, NULL,
control_point_reset) },
{ }
--
1.7.11.3
^ permalink raw reply related
* [PATCH v5 14/17] heartrate: Add Reset method
From: Andrzej Kaczmarek @ 2012-09-13 14:31 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Andrzej Kaczmarek
In-Reply-To: <1347546711-19961-1-git-send-email-andrzej.kaczmarek@tieto.com>
This patch adds Reset method on HeartRate interface to reset Energy Expended.
---
profiles/heartrate/heartrate.c | 58 +++++++++++++++++++++++++++++++++++++++++-
1 file changed, 57 insertions(+), 1 deletion(-)
diff --git a/profiles/heartrate/heartrate.c b/profiles/heartrate/heartrate.c
index 6549d4b..48d3cd1 100644
--- a/profiles/heartrate/heartrate.c
+++ b/profiles/heartrate/heartrate.c
@@ -43,6 +43,7 @@
#define HEART_RATE_MANAGER_IFACE "org.bluez.HeartRateManager"
#define HEART_RATE_WATCHER_IFACE "org.bluez.HeartRateWatcher"
+#define HEART_RATE_IFACE "org.bluez.HeartRate"
#define MIN_NOTIFICATION_LEN 3 /* 1-byte opcode + 2-byte handle */
@@ -409,6 +410,43 @@ static DBusMessage *unregister_watcher(DBusConnection *conn, DBusMessage *msg,
return dbus_message_new_method_return(msg);
}
+static gint process_att_reset(struct heartrate *hr)
+{
+ struct characteristic *ch;
+ char *msg;
+ uint8_t atval;
+
+ if (hr->attrib == NULL)
+ return -1;
+
+ ch = get_characteristic(hr, HEART_RATE_CONTROL_POINT_UUID);
+ if (ch == NULL)
+ return -1;
+
+ atval = 0x01;
+ msg = g_strdup("Reset Control Point");
+
+ gatt_write_char(hr->attrib, ch->attr.value_handle, &atval,
+ 1, char_write_cb, msg);
+ return 0;
+}
+
+static DBusMessage *control_point_reset(DBusConnection *conn, DBusMessage *msg,
+ void *data)
+{
+ struct heartrate *hr = data;
+
+ if (!hr->has_cp_reset)
+ return btd_error_not_supported(msg);
+
+ if (process_att_reset(hr) < 0)
+ return btd_error_not_available(msg);
+
+ DBG("Energy Expended Value has been reset");
+
+ return dbus_message_new_method_return(msg);
+}
+
static const GDBusMethodTable heartrate_manager_methods[] = {
{ GDBUS_METHOD("RegisterWatcher",
GDBUS_ARGS({ "agent", "o" }), NULL,
@@ -419,6 +457,12 @@ static const GDBusMethodTable heartrate_manager_methods[] = {
{ }
};
+static const GDBusMethodTable heartrate_device_methods[] = {
+ { GDBUS_METHOD("Reset", NULL, NULL,
+ control_point_reset) },
+ { }
+};
+
static void read_sensor_location_cb(guint8 status, const guint8 *pdu,
guint16 len, gpointer user_data)
{
@@ -819,6 +863,16 @@ int heartrate_device_register(struct btd_device *device,
hr->dev = btd_device_ref(device);
hr->hra = hra;
+ if (!g_dbus_register_interface(get_dbus_connection(),
+ device_get_path(device), HEART_RATE_IFACE,
+ heartrate_device_methods, NULL, NULL,
+ hr, destroy_heartrate_device)) {
+ error("D-Bus failed to register %s interface",
+ HEART_RATE_IFACE);
+ destroy_heartrate_device(hr);
+ return -EIO;
+ }
+
hra->devices = g_slist_prepend(hra->devices, hr);
hr->svc_range = g_new0(struct att_range, 1);
@@ -854,5 +908,7 @@ void heartrate_device_unregister(struct btd_device *device)
hra->devices = g_slist_remove(hra->devices, hr);
- destroy_heartrate_device(hr);
+ g_dbus_unregister_interface(get_dbus_connection(),
+ device_get_path(device),
+ HEART_RATE_IFACE);
}
--
1.7.11.3
^ permalink raw reply related
* [PATCH v5 13/17] heartrate: Process Heart Rate Measurement characteristics
From: Andrzej Kaczmarek @ 2012-09-13 14:31 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Andrzej Kaczmarek
In-Reply-To: <1347546711-19961-1-git-send-email-andrzej.kaczmarek@tieto.com>
---
profiles/heartrate/heartrate.c | 171 +++++++++++++++++++++++++++++++++++++++++
1 file changed, 171 insertions(+)
diff --git a/profiles/heartrate/heartrate.c b/profiles/heartrate/heartrate.c
index f78d91d..6549d4b 100644
--- a/profiles/heartrate/heartrate.c
+++ b/profiles/heartrate/heartrate.c
@@ -42,9 +42,16 @@
#include "log.h"
#define HEART_RATE_MANAGER_IFACE "org.bluez.HeartRateManager"
+#define HEART_RATE_WATCHER_IFACE "org.bluez.HeartRateWatcher"
#define MIN_NOTIFICATION_LEN 3 /* 1-byte opcode + 2-byte handle */
+#define HR_VALUE_FORMAT 0x01
+#define SENSOR_CONTACT_DETECTED 0x02
+#define SENSOR_CONTACT_SUPPORT 0x04
+#define ENERGY_EXP_STATUS 0x08
+#define RR_INTERVAL 0x10
+
struct heartrate_adapter {
struct btd_adapter *adapter;
GSList *devices;
@@ -76,6 +83,17 @@ struct descriptor {
bt_uuid_t uuid;
};
+struct measurement {
+ struct heartrate *hr;
+ uint16_t value;
+ gboolean has_energy;
+ uint16_t energy;
+ gboolean has_contact;
+ gboolean contact;
+ uint16_t num_interval;
+ uint16_t *interval;
+};
+
struct watcher {
struct heartrate_adapter *hra;
guint id;
@@ -123,6 +141,14 @@ static gint cmp_descriptor(gconstpointer a, gconstpointer b)
return bt_uuid_cmp(&desc->uuid, uuid);
}
+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 gint cmp_watcher(gconstpointer a, gconstpointer b)
{
const struct watcher *watcher = a;
@@ -552,12 +578,157 @@ static void configure_heartrate_cb(GSList *characteristics, guint8 status,
}
}
+static void update_watcher(gpointer data, gpointer user_data)
+{
+ struct watcher *w = data;
+ struct measurement *m = user_data;
+ struct heartrate *hr = m->hr;
+ const gchar *path = device_get_path(hr->dev);
+ DBusMessageIter iter;
+ DBusMessageIter dict;
+ DBusMessage *msg;
+
+ msg = dbus_message_new_method_call(w->srv, w->path,
+ HEART_RATE_WATCHER_IFACE,
+ "MeasurementReceived");
+ if (msg == NULL)
+ return;
+
+ dbus_message_iter_init_append(msg, &iter);
+
+ dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH , &path);
+
+ 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, "Value", DBUS_TYPE_UINT16, &m->value);
+
+ if (m->has_energy)
+ dict_append_entry(&dict, "Energy", DBUS_TYPE_UINT16,
+ &m->energy);
+
+ if (m->has_contact)
+ dict_append_entry(&dict, "Contact", DBUS_TYPE_BOOLEAN,
+ &m->contact);
+
+ if (m->num_interval > 0)
+ dict_append_array(&dict, "Interval", DBUS_TYPE_UINT16,
+ &m->interval, m->num_interval);
+
+ dbus_message_iter_close_container(&iter, &dict);
+
+ dbus_message_set_no_reply(msg, TRUE);
+ g_dbus_send_message(get_dbus_connection(), msg);
+}
+
+static void recv_measurement(struct heartrate *hr, struct measurement *m)
+{
+ GSList *wlist = hr->hra->watchers;
+
+ m->hr = hr;
+
+ g_slist_foreach(wlist, update_watcher, m);
+}
+
+static void proc_measurement(struct heartrate *hr, const uint8_t *pdu,
+ uint16_t len)
+{
+ struct measurement m;
+ uint8_t flags;
+
+ if (len < 4) {
+ error("Mandatory flags are not provided");
+ return;
+ }
+
+ flags = pdu[3];
+
+ pdu += 4;
+ len -= 4;
+
+ memset(&m, 0, sizeof(m));
+
+ if (flags & HR_VALUE_FORMAT) {
+ if (len < 2) {
+ error("Heart Rate Measurement field missing");
+ return;
+ }
+
+ m.value = att_get_u16(pdu);
+ pdu += 2;
+ len -= 2;
+ } else {
+ if (len < 1) {
+ error("Heart Rate Measurement field missing");
+ return;
+ }
+
+ m.value = *pdu;
+ pdu++;
+ len--;
+ }
+
+ if (flags & ENERGY_EXP_STATUS) {
+ if (len < 2) {
+ error("Energy Expended field missing");
+ return;
+ }
+
+ m.has_energy = TRUE;
+ m.energy = att_get_u16(pdu);
+ pdu += 2;
+ len -= 2;
+ }
+
+ if (flags & RR_INTERVAL) {
+ int i;
+
+ if (len == 0 || (len % 2 != 0)) {
+ error("RR-Interval field malformed");
+ return;
+ }
+
+ m.num_interval = len / 2;
+ m.interval = g_new(uint16_t, m.num_interval);
+
+ for (i = 0; i < m.num_interval; pdu += 2, i++)
+ m.interval[i] = att_get_u16(pdu);
+ }
+
+ if (flags & SENSOR_CONTACT_SUPPORT) {
+ m.has_contact = TRUE;
+ m.contact = !!(flags & SENSOR_CONTACT_DETECTED);
+ }
+
+ recv_measurement(hr, &m);
+
+ g_free(m.interval);
+}
+
static void notify_handler(const uint8_t *pdu, uint16_t len, gpointer user_data)
{
+ struct heartrate *hr = user_data;
+ const struct characteristic *ch;
+ uint16_t handle;
+ GSList *l;
+
if (len < MIN_NOTIFICATION_LEN) {
error("Bad pdu received");
return;
}
+
+ handle = att_get_u16(&pdu[1]);
+ l = g_slist_find_custom(hr->chars, &handle, cmp_char_val_handle);
+ if (l == NULL) {
+ error("Unexpected handle: 0x%04x", handle);
+ return;
+ }
+
+ ch = l->data;
+ if (g_strcmp0(ch->attr.uuid, HEART_RATE_MEASUREMENT_UUID) == 0)
+ proc_measurement(hr, pdu, len);
}
static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
--
1.7.11.3
^ permalink raw reply related
* [PATCH v5 12/17] heartrate: Handle characteristics value changed notification
From: Andrzej Kaczmarek @ 2012-09-13 14:31 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Andrzej Kaczmarek
In-Reply-To: <1347546711-19961-1-git-send-email-andrzej.kaczmarek@tieto.com>
This patch adds stub for handling characteristics value changed notification.
---
profiles/heartrate/heartrate.c | 23 ++++++++++++++++++++++-
1 file changed, 22 insertions(+), 1 deletion(-)
diff --git a/profiles/heartrate/heartrate.c b/profiles/heartrate/heartrate.c
index 4591e56..f78d91d 100644
--- a/profiles/heartrate/heartrate.c
+++ b/profiles/heartrate/heartrate.c
@@ -43,6 +43,8 @@
#define HEART_RATE_MANAGER_IFACE "org.bluez.HeartRateManager"
+#define MIN_NOTIFICATION_LEN 3 /* 1-byte opcode + 2-byte handle */
+
struct heartrate_adapter {
struct btd_adapter *adapter;
GSList *devices;
@@ -54,6 +56,7 @@ struct heartrate {
struct heartrate_adapter *hra;
GAttrib *attrib;
guint attioid;
+ guint attionotid;
struct att_range *svc_range;
GSList *chars;
gboolean has_location;
@@ -176,8 +179,10 @@ static void destroy_heartrate_device(gpointer user_data)
if (hr->attioid > 0)
btd_device_remove_attio_callback(hr->dev, hr->attioid);
- if (hr->attrib != NULL)
+ if (hr->attrib != NULL) {
+ g_attrib_unregister(hr->attrib, hr->attionotid);
g_attrib_unref(hr->attrib);
+ }
if (hr->chars != NULL)
g_slist_free_full(hr->chars, destroy_char);
@@ -547,6 +552,14 @@ static void configure_heartrate_cb(GSList *characteristics, guint8 status,
}
}
+static void notify_handler(const uint8_t *pdu, uint16_t len, gpointer user_data)
+{
+ if (len < MIN_NOTIFICATION_LEN) {
+ error("Bad pdu received");
+ return;
+ }
+}
+
static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
{
struct heartrate *hr = user_data;
@@ -555,6 +568,9 @@ static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
hr->attrib = g_attrib_ref(attrib);
+ hr->attionotid = g_attrib_register(hr->attrib,
+ ATT_OP_HANDLE_NOTIFY, notify_handler, hr, NULL);
+
gatt_discover_char(hr->attrib, hr->svc_range->start,
hr->svc_range->end, NULL,
configure_heartrate_cb, hr);
@@ -566,6 +582,11 @@ static void attio_disconnected_cb(gpointer user_data)
DBG("GATT Disconnected");
+ if (hr->attionotid > 0) {
+ g_attrib_unregister(hr->attrib, hr->attionotid);
+ hr->attionotid = 0;
+ }
+
g_attrib_unref(hr->attrib);
hr->attrib = NULL;
}
--
1.7.11.3
^ permalink raw reply related
* [PATCH v5 11/17] heartrate: Read Heart Rate Control Point characteristics
From: Andrzej Kaczmarek @ 2012-09-13 14:31 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Andrzej Kaczmarek
In-Reply-To: <1347546711-19961-1-git-send-email-andrzej.kaczmarek@tieto.com>
This patch reads and stores Heart Rate Control Point characteristics value.
---
profiles/heartrate/heartrate.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/profiles/heartrate/heartrate.c b/profiles/heartrate/heartrate.c
index 150a675..4591e56 100644
--- a/profiles/heartrate/heartrate.c
+++ b/profiles/heartrate/heartrate.c
@@ -58,6 +58,7 @@ struct heartrate {
GSList *chars;
gboolean has_location;
uint8_t location;
+ gboolean has_cp_reset;
};
struct characteristic {
@@ -420,6 +421,7 @@ static void process_heartrate_char(struct characteristic *ch)
{
if (g_strcmp0(ch->attr.uuid, HEART_RATE_CONTROL_POINT_UUID) == 0) {
DBG("Heart Rate Control Point reset supported by client");
+ ch->hr->has_cp_reset = TRUE;
} else if (g_strcmp0(ch->attr.uuid, BODY_SENSOR_LOCATION_UUID) == 0) {
DBG("Body Sensor Location supported by client");
gatt_read_char(ch->hr->attrib, ch->attr.value_handle, 0,
--
1.7.11.3
^ permalink raw reply related
* [PATCH v5 10/17] heartrate: Read Body Sensor Location characteristics
From: Andrzej Kaczmarek @ 2012-09-13 14:31 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Rafal Garbat
In-Reply-To: <1347546711-19961-1-git-send-email-andrzej.kaczmarek@tieto.com>
From: Rafal Garbat <rafal.garbat@tieto.com>
This patch reads and stores Body Sensor Location characteristics value.
---
profiles/heartrate/heartrate.c | 40 +++++++++++++++++++++++++++++++++++++---
1 file changed, 37 insertions(+), 3 deletions(-)
diff --git a/profiles/heartrate/heartrate.c b/profiles/heartrate/heartrate.c
index 9d29ee0..150a675 100644
--- a/profiles/heartrate/heartrate.c
+++ b/profiles/heartrate/heartrate.c
@@ -56,6 +56,8 @@ struct heartrate {
guint attioid;
struct att_range *svc_range;
GSList *chars;
+ gboolean has_location;
+ uint8_t location;
};
struct characteristic {
@@ -385,12 +387,44 @@ static const GDBusMethodTable heartrate_manager_methods[] = {
{ }
};
+static void read_sensor_location_cb(guint8 status, const guint8 *pdu,
+ guint16 len, gpointer user_data)
+{
+ struct characteristic *ch = user_data;
+ struct heartrate *hr = ch->hr;
+ uint8_t value;
+ ssize_t vlen;
+
+ if (status != 0) {
+ error("Body Sensor Location value read failed: %s",
+ att_ecode2str(status));
+ return;
+ }
+
+ vlen = dec_read_resp(pdu, len, &value, sizeof(value));
+ if (vlen < 0) {
+ error("Protocol error.");
+ return;
+ }
+
+ if (vlen != 1) {
+ error("Invalid length for Body Sensor Location");
+ return;
+ }
+
+ hr->has_location = TRUE;
+ hr->location = value;
+}
+
static void process_heartrate_char(struct characteristic *ch)
{
- if (g_strcmp0(ch->attr.uuid, HEART_RATE_CONTROL_POINT_UUID) == 0)
- DBG("Heart Rate Control Point supported by client");
- else if (g_strcmp0(ch->attr.uuid, BODY_SENSOR_LOCATION_UUID) == 0)
+ if (g_strcmp0(ch->attr.uuid, HEART_RATE_CONTROL_POINT_UUID) == 0) {
+ DBG("Heart Rate Control Point reset supported by client");
+ } else if (g_strcmp0(ch->attr.uuid, BODY_SENSOR_LOCATION_UUID) == 0) {
DBG("Body Sensor Location supported by client");
+ gatt_read_char(ch->hr->attrib, ch->attr.value_handle, 0,
+ read_sensor_location_cb, ch);
+ }
}
static void process_heartrate_desc(struct descriptor *desc)
--
1.7.11.3
^ permalink raw reply related
* [PATCH v5 09/17] heartrate: Enable measurement when watchers are registered
From: Andrzej Kaczmarek @ 2012-09-13 14:31 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Andrzej Kaczmarek
In-Reply-To: <1347546711-19961-1-git-send-email-andrzej.kaczmarek@tieto.com>
This patch will enable measurement notification when first watcher is
registered or when device is connected and watcher is already registered.
Measurement will be disabled when last watcher is unregistered.
---
profiles/heartrate/heartrate.c | 129 ++++++++++++++++++++++++++++++++++++++++-
1 file changed, 128 insertions(+), 1 deletion(-)
diff --git a/profiles/heartrate/heartrate.c b/profiles/heartrate/heartrate.c
index a223fe0..9d29ee0 100644
--- a/profiles/heartrate/heartrate.c
+++ b/profiles/heartrate/heartrate.c
@@ -101,6 +101,22 @@ static gint cmp_device(gconstpointer a, gconstpointer b)
return -1;
}
+static gint cmp_char_uuid(gconstpointer a, gconstpointer b)
+{
+ const struct characteristic *ch = a;
+ const char *uuid = b;
+
+ return g_strcmp0(ch->attr.uuid, uuid);
+}
+
+static gint cmp_descriptor(gconstpointer a, gconstpointer b)
+{
+ const struct descriptor *desc = a;
+ const bt_uuid_t *uuid = b;
+
+ return bt_uuid_cmp(&desc->uuid, uuid);
+}
+
static gint cmp_watcher(gconstpointer a, gconstpointer b)
{
const struct watcher *watcher = a;
@@ -181,6 +197,91 @@ static void destroy_heartrate_adapter(gpointer user_data)
g_free(hra);
}
+static struct characteristic *get_characteristic(struct heartrate *hr,
+ const char *uuid)
+{
+ GSList *l;
+
+ l = g_slist_find_custom(hr->chars, uuid, cmp_char_uuid);
+ if (l == NULL)
+ return NULL;
+
+ return l->data;
+}
+
+static struct descriptor *get_descriptor(struct characteristic *ch,
+ const bt_uuid_t *uuid)
+{
+ GSList *l;
+
+ l = g_slist_find_custom(ch->desc, uuid, cmp_descriptor);
+ if (l == NULL)
+ return NULL;
+
+ return l->data;
+}
+
+static void char_write_cb(guint8 status, const guint8 *pdu, guint16 len,
+ gpointer user_data)
+{
+ char *msg = user_data;
+
+ if (status != 0)
+ error("%s failed", msg);
+
+ g_free(msg);
+}
+
+static void measurement_toggle(struct heartrate *hr, gboolean enable)
+{
+ struct characteristic *ch;
+ struct descriptor *desc;
+ bt_uuid_t btuuid;
+ uint8_t atval[2];
+ char *msg;
+
+ if (hr->attrib == NULL)
+ return;
+
+ ch = get_characteristic(hr, HEART_RATE_MEASUREMENT_UUID);
+ if (ch == NULL) {
+ DBG("Heart Rate Measurement characteristic not found");
+ return;
+ }
+
+ bt_uuid16_create(&btuuid, GATT_CLIENT_CHARAC_CFG_UUID);
+ desc = get_descriptor(ch, &btuuid);
+ if (desc == NULL) {
+ DBG("Client Characteristic Configuration descriptor not found");
+ return;
+ }
+
+ if (enable) {
+ att_put_u16(GATT_CLIENT_CHARAC_CFG_NOTIF_BIT, atval);
+ msg = g_strdup("Enable measurement");
+ } else {
+ att_put_u16(0x0000, atval);
+ msg = g_strdup("Disable measurement");
+ }
+
+ gatt_write_char(hr->attrib, desc->handle, atval, 2, char_write_cb, msg);
+
+}
+
+static void measurement_enable(gpointer data, gpointer user_data)
+{
+ struct heartrate *hr = data;
+
+ measurement_toggle(hr, TRUE);
+}
+
+static void measurement_disable(gpointer data, gpointer user_data)
+{
+ struct heartrate *hr = data;
+
+ measurement_toggle(hr, FALSE);
+}
+
static void watcher_exit(DBusConnection *conn, void *user_data)
{
struct watcher *watcher = user_data;
@@ -190,6 +291,9 @@ static void watcher_exit(DBusConnection *conn, void *user_data)
hr->watchers = g_slist_remove(hr->watchers, watcher);
g_dbus_remove_watch(conn, watcher->id);
+
+ if (g_slist_length(hr->watchers) == 0)
+ g_slist_foreach(hr->devices, measurement_disable, 0);
}
static struct watcher *find_watcher(GSList *list, const char *sender,
@@ -236,6 +340,9 @@ static DBusMessage *register_watcher(DBusConnection *conn, DBusMessage *msg,
watcher->id = g_dbus_add_disconnect_watch(conn, sender, watcher_exit,
watcher, destroy_watcher);
+ if (g_slist_length(hra->watchers) == 0)
+ g_slist_foreach(hra->devices, measurement_enable, 0);
+
hra->watchers = g_slist_prepend(hra->watchers, watcher);
return dbus_message_new_method_return(msg);
@@ -262,6 +369,9 @@ static DBusMessage *unregister_watcher(DBusConnection *conn, DBusMessage *msg,
hr->watchers = g_slist_remove(hr->watchers, watcher);
g_dbus_remove_watch(get_dbus_connection(), watcher->id);
+ if (g_slist_length(hr->watchers) == 0)
+ g_slist_foreach(hr->devices, measurement_disable, 0);
+
return dbus_message_new_method_return(msg);
}
@@ -291,9 +401,26 @@ static void process_heartrate_desc(struct descriptor *desc)
bt_uuid16_create(&btuuid, GATT_CLIENT_CHARAC_CFG_UUID);
- if (bt_uuid_cmp(&desc->uuid, &btuuid) == 0)
+ if (bt_uuid_cmp(&desc->uuid, &btuuid) == 0) {
+ uint8_t atval[2];
+ char *msg;
+
+ if (g_strcmp0(ch->attr.uuid, HEART_RATE_MEASUREMENT_UUID) != 0)
+ goto done;
+
+ if (g_slist_length(ch->hr->hra->watchers) == 0)
+ return;
+
+ att_put_u16(GATT_CLIENT_CHARAC_CFG_NOTIF_BIT, atval);
+ msg = g_strdup("Enable measurement");
+
+ gatt_write_char(ch->hr->attrib, desc->handle,
+ atval, 2, char_write_cb, msg);
+
return;
+ }
+done:
bt_uuid_to_string(&desc->uuid, uuidstr, MAX_LEN_UUID_STR);
DBG("Ignored descriptor %s in characteristic %s", uuidstr,
ch->attr.uuid);
--
1.7.11.3
^ permalink raw reply related
* [PATCH v5 08/17] heartrate: Add HeartRateManager interface
From: Andrzej Kaczmarek @ 2012-09-13 14:31 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Rafal Garbat
In-Reply-To: <1347546711-19961-1-git-send-email-andrzej.kaczmarek@tieto.com>
From: Rafal Garbat <rafal.garbat@tieto.com>
This patch adds support for org.bluez.HeartRateManager interface on adapters
which allows to register and unregister per-adapter watcher.
---
profiles/heartrate/heartrate.c | 155 ++++++++++++++++++++++++++++++++++++++++-
1 file changed, 154 insertions(+), 1 deletion(-)
diff --git a/profiles/heartrate/heartrate.c b/profiles/heartrate/heartrate.c
index eec8ae0..a223fe0 100644
--- a/profiles/heartrate/heartrate.c
+++ b/profiles/heartrate/heartrate.c
@@ -24,13 +24,16 @@
#include <config.h>
#endif
+#include <gdbus.h>
#include <errno.h>
#include <stdbool.h>
#include <glib.h>
#include <bluetooth/uuid.h>
#include "adapter.h"
+#include "dbus-common.h"
#include "device.h"
+#include "error.h"
#include "gattrib.h"
#include "attio.h"
#include "att.h"
@@ -38,9 +41,12 @@
#include "heartrate.h"
#include "log.h"
+#define HEART_RATE_MANAGER_IFACE "org.bluez.HeartRateManager"
+
struct heartrate_adapter {
struct btd_adapter *adapter;
GSList *devices;
+ GSList *watchers;
};
struct heartrate {
@@ -64,6 +70,13 @@ struct descriptor {
bt_uuid_t uuid;
};
+struct watcher {
+ struct heartrate_adapter *hra;
+ guint id;
+ char *srv;
+ char *path;
+};
+
static GSList *heartrate_adapters = NULL;
static gint cmp_adapter(gconstpointer a, gconstpointer b)
@@ -88,6 +101,19 @@ static gint cmp_device(gconstpointer a, gconstpointer b)
return -1;
}
+static gint cmp_watcher(gconstpointer a, gconstpointer b)
+{
+ const struct watcher *watcher = a;
+ const struct watcher *match = b;
+ int ret;
+
+ ret = g_strcmp0(watcher->srv, match->srv);
+ if (ret != 0)
+ return ret;
+
+ return g_strcmp0(watcher->path, match->path);
+}
+
static struct heartrate_adapter *
find_heartrate_adapter(struct btd_adapter *adapter)
{
@@ -108,6 +134,22 @@ static void destroy_char(gpointer user_data)
g_free(c);
}
+static void remove_watcher(gpointer user_data)
+{
+ struct watcher *watcher = user_data;
+
+ g_dbus_remove_watch(get_dbus_connection(), watcher->id);
+}
+
+static void destroy_watcher(gpointer user_data)
+{
+ struct watcher *watcher = user_data;
+
+ g_free(watcher->path);
+ g_free(watcher->srv);
+ g_free(watcher);
+}
+
static void destroy_heartrate_device(gpointer user_data)
{
struct heartrate *hr = user_data;
@@ -133,9 +175,106 @@ static void destroy_heartrate_adapter(gpointer user_data)
if (hra->devices != NULL)
g_slist_free_full(hra->devices, destroy_heartrate_device);
+ if (hra->watchers != NULL)
+ g_slist_free_full(hra->watchers, remove_watcher);
+
g_free(hra);
}
+static void watcher_exit(DBusConnection *conn, void *user_data)
+{
+ struct watcher *watcher = user_data;
+ struct heartrate_adapter *hr = watcher->hra;
+
+ DBG("Heart Rate watcher %s disconnected", watcher->path);
+
+ hr->watchers = g_slist_remove(hr->watchers, watcher);
+ g_dbus_remove_watch(conn, watcher->id);
+}
+
+static struct watcher *find_watcher(GSList *list, const char *sender,
+ const char *path)
+{
+ struct watcher *match;
+ GSList *l;
+
+ match = g_new0(struct watcher, 1);
+ match->srv = g_strdup(sender);
+ match->path = g_strdup(path);
+
+ l = g_slist_find_custom(list, match, cmp_watcher);
+ destroy_watcher(match);
+
+ if (l != NULL)
+ return l->data;
+
+ return NULL;
+}
+
+static DBusMessage *register_watcher(DBusConnection *conn, DBusMessage *msg,
+ void *data)
+{
+ const char *sender = dbus_message_get_sender(msg);
+ struct heartrate_adapter *hra = data;
+ struct watcher *watcher;
+ char *path;
+
+ if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
+ DBUS_TYPE_INVALID))
+ return btd_error_invalid_args(msg);
+
+ watcher = find_watcher(hra->watchers, sender, path);
+ if (watcher != NULL)
+ return btd_error_already_exists(msg);
+
+ DBG("Heart Rate watcher %s registered", path);
+
+ watcher = g_new0(struct watcher, 1);
+ watcher->srv = g_strdup(sender);
+ watcher->path = g_strdup(path);
+ watcher->hra = hra;
+ watcher->id = g_dbus_add_disconnect_watch(conn, sender, watcher_exit,
+ watcher, destroy_watcher);
+
+ hra->watchers = g_slist_prepend(hra->watchers, watcher);
+
+ return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *unregister_watcher(DBusConnection *conn, DBusMessage *msg,
+ void *data)
+{
+ const char *sender = dbus_message_get_sender(msg);
+ struct heartrate_adapter *hr = data;
+ struct watcher *watcher;
+ char *path;
+
+ if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
+ DBUS_TYPE_INVALID))
+ return btd_error_invalid_args(msg);
+
+ watcher = find_watcher(hr->watchers, sender, path);
+ if (watcher == NULL)
+ return btd_error_does_not_exist(msg);
+
+ DBG("Heart Rate watcher %s unregistered", path);
+
+ hr->watchers = g_slist_remove(hr->watchers, watcher);
+ g_dbus_remove_watch(get_dbus_connection(), watcher->id);
+
+ return dbus_message_new_method_return(msg);
+}
+
+static const GDBusMethodTable heartrate_manager_methods[] = {
+ { GDBUS_METHOD("RegisterWatcher",
+ GDBUS_ARGS({ "agent", "o" }), NULL,
+ register_watcher) },
+ { GDBUS_METHOD("UnregisterWatcher",
+ GDBUS_ARGS({ "agent", "o" }), NULL,
+ unregister_watcher) },
+ { }
+};
+
static void process_heartrate_char(struct characteristic *ch)
{
if (g_strcmp0(ch->attr.uuid, HEART_RATE_CONTROL_POINT_UUID) == 0)
@@ -275,6 +414,18 @@ int heartrate_adapter_register(struct btd_adapter *adapter)
hra = g_new0(struct heartrate_adapter, 1);
hra->adapter = adapter;
+ if (!g_dbus_register_interface(get_dbus_connection(),
+ adapter_get_path(adapter),
+ HEART_RATE_MANAGER_IFACE,
+ heartrate_manager_methods,
+ NULL, NULL, hra,
+ destroy_heartrate_adapter)) {
+ error("D-Bus failed to register %s interface",
+ HEART_RATE_MANAGER_IFACE);
+ destroy_heartrate_adapter(hra);
+ return -EIO;
+ }
+
heartrate_adapters = g_slist_prepend(heartrate_adapters, hra);
return 0;
@@ -290,7 +441,9 @@ void heartrate_adapter_unregister(struct btd_adapter *adapter)
heartrate_adapters = g_slist_remove(heartrate_adapters, hra);
- destroy_heartrate_adapter(hra);
+ g_dbus_unregister_interface(get_dbus_connection(),
+ adapter_get_path(hra->adapter),
+ HEART_RATE_MANAGER_IFACE);
}
int heartrate_device_register(struct btd_device *device,
--
1.7.11.3
^ permalink raw reply related
* [PATCH v5 07/17] heartrate: Process characteristics descriptors
From: Andrzej Kaczmarek @ 2012-09-13 14:31 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Rafal Garbat
In-Reply-To: <1347546711-19961-1-git-send-email-andrzej.kaczmarek@tieto.com>
From: Rafal Garbat <rafal.garbat@tieto.com>
This patch adds stub to process discovered characteristics descriptors.
---
lib/uuid.h | 1 +
profiles/heartrate/heartrate.c | 18 ++++++++++++++++++
2 files changed, 19 insertions(+)
diff --git a/lib/uuid.h b/lib/uuid.h
index 0a9db51..15a80a0 100644
--- a/lib/uuid.h
+++ b/lib/uuid.h
@@ -64,6 +64,7 @@ extern "C" {
#define SAP_UUID "0000112D-0000-1000-8000-00805f9b34fb"
#define HEART_RATE_UUID "0000180d-0000-1000-8000-00805f9b34fb"
+#define HEART_RATE_MEASUREMENT_UUID "00002a37-0000-1000-8000-00805f9b34fb"
#define HEART_RATE_CONTROL_POINT_UUID "00002a39-0000-1000-8000-00805f9b34fb"
#define BODY_SENSOR_LOCATION_UUID "00002a38-0000-1000-8000-00805f9b34fb"
diff --git a/profiles/heartrate/heartrate.c b/profiles/heartrate/heartrate.c
index 69d6d51..eec8ae0 100644
--- a/profiles/heartrate/heartrate.c
+++ b/profiles/heartrate/heartrate.c
@@ -144,6 +144,22 @@ static void process_heartrate_char(struct characteristic *ch)
DBG("Body Sensor Location supported by client");
}
+static void process_heartrate_desc(struct descriptor *desc)
+{
+ struct characteristic *ch = desc->ch;
+ 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)
+ return;
+
+ bt_uuid_to_string(&desc->uuid, uuidstr, MAX_LEN_UUID_STR);
+ DBG("Ignored descriptor %s in characteristic %s", uuidstr,
+ ch->attr.uuid);
+}
+
static void discover_desc_cb(guint8 status, const guint8 *pdu,
guint16 len, gpointer user_data)
{
@@ -177,6 +193,8 @@ static void discover_desc_cb(guint8 status, const guint8 *pdu,
desc->uuid = att_get_uuid128(value + 2);
ch->desc = g_slist_append(ch->desc, desc);
+
+ process_heartrate_desc(desc);
}
att_data_list_free(list);
--
1.7.11.3
^ permalink raw reply related
* [PATCH v5 06/17] heartrate: Discover characteristics descriptors
From: Andrzej Kaczmarek @ 2012-09-13 14:31 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Rafal Garbat
In-Reply-To: <1347546711-19961-1-git-send-email-andrzej.kaczmarek@tieto.com>
From: Rafal Garbat <rafal.garbat@tieto.com>
---
profiles/heartrate/heartrate.c | 72 +++++++++++++++++++++++++++++++++++++++++-
1 file changed, 71 insertions(+), 1 deletion(-)
diff --git a/profiles/heartrate/heartrate.c b/profiles/heartrate/heartrate.c
index 02a4617..69d6d51 100644
--- a/profiles/heartrate/heartrate.c
+++ b/profiles/heartrate/heartrate.c
@@ -55,6 +55,13 @@ struct heartrate {
struct characteristic {
struct gatt_char attr;
struct heartrate *hr;
+ GSList *desc;
+};
+
+struct descriptor {
+ struct characteristic *ch;
+ uint16_t handle;
+ bt_uuid_t uuid;
};
static GSList *heartrate_adapters = NULL;
@@ -92,6 +99,15 @@ find_heartrate_adapter(struct btd_adapter *adapter)
return l->data;
}
+static void destroy_char(gpointer user_data)
+{
+ struct characteristic *c = user_data;
+
+ g_slist_free_full(c->desc, g_free);
+
+ g_free(c);
+}
+
static void destroy_heartrate_device(gpointer user_data)
{
struct heartrate *hr = user_data;
@@ -103,7 +119,7 @@ static void destroy_heartrate_device(gpointer user_data)
g_attrib_unref(hr->attrib);
if (hr->chars != NULL)
- g_slist_free_full(hr->chars, g_free);
+ g_slist_free_full(hr->chars, destroy_char);
btd_device_unref(hr->dev);
g_free(hr->svc_range);
@@ -128,6 +144,44 @@ static void process_heartrate_char(struct characteristic *ch)
DBG("Body Sensor Location supported by client");
}
+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_heartrate_cb(GSList *characteristics, guint8 status,
gpointer user_data)
{
@@ -143,6 +197,7 @@ static void configure_heartrate_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;
@@ -154,6 +209,21 @@ static void configure_heartrate_cb(GSList *characteristics, guint8 status,
hr->chars = g_slist_append(hr->chars, ch);
process_heartrate_char(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 != hr->svc_range->end) {
+ end = hr->svc_range->end;
+ } else {
+ continue;
+ }
+
+ gatt_find_info(hr->attrib, start, end, discover_desc_cb, ch);
}
}
--
1.7.11.3
^ permalink raw reply related
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