* [PATCH] Bluetooth: Add support for BCM20702A0 [04ca, 2003]
From: acho @ 2012-09-06 6:57 UTC (permalink / raw)
To: marcel, gustavo, johan.hedberg, linux-bluetooth
Cc: oneukum, acho, jlee, resler
From: "Cho, Yu-Chen" <acho@suse.com>
Add another vendor specific ID for BCM20702A0.
output of usb-devices:
T: Bus=01 Lev=02 Prnt=02 Port=03 Cnt=02 Dev#= 4 Spd=12 MxCh= 0
D: Ver= 2.00 Cls=ff(vend.) Sub=01 Prot=01 MxPS=64 #Cfgs= 1
P: Vendor=04ca ProdID=2003 Rev= 1.12
S: Manufacturer=Broadcom Corp
S: Product=BCM20702A0
S: SerialNumber=446D57861623
C:* #Ifs= 4 Cfg#= 1 Atr=e0 MxPwr= 0mA
I:* If#= 0 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E: Ad=81(I) Atr=03(Int.) MxPS= 16 Ivl=1ms
E: Ad=82(I) Atr=02(Bulk) MxPS= 64 Ivl=0ms
E: Ad=02(O) Atr=02(Bulk) MxPS= 64 Ivl=0ms
I:* If#= 1 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E: Ad=83(I) Atr=01(Isoc) MxPS= 0 Ivl=1ms
E: Ad=03(O) Atr=01(Isoc) MxPS= 0 Ivl=1ms
I: If#= 1 Alt= 1 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E: Ad=83(I) Atr=01(Isoc) MxPS= 9 Ivl=1ms
E: Ad=03(O) Atr=01(Isoc) MxPS= 9 Ivl=1ms
I: If#= 1 Alt= 2 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E: Ad=83(I) Atr=01(Isoc) MxPS= 17 Ivl=1ms
E: Ad=03(O) Atr=01(Isoc) MxPS= 17 Ivl=1ms
I: If#= 1 Alt= 3 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E: Ad=83(I) Atr=01(Isoc) MxPS= 25 Ivl=1ms
E: Ad=03(O) Atr=01(Isoc) MxPS= 25 Ivl=1ms
I: If#= 1 Alt= 4 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E: Ad=83(I) Atr=01(Isoc) MxPS= 33 Ivl=1ms
E: Ad=03(O) Atr=01(Isoc) MxPS= 33 Ivl=1ms
I: If#= 1 Alt= 5 #EPs= 2 Cls=ff(vend.) Sub=01 Prot=01 Driver=btusb
E: Ad=83(I) Atr=01(Isoc) MxPS= 49 Ivl=1ms
E: Ad=03(O) Atr=01(Isoc) MxPS= 49 Ivl=1ms
I:* If#= 2 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=ff Driver=(none)
E: Ad=84(I) Atr=02(Bulk) MxPS= 32 Ivl=0ms
E: Ad=04(O) Atr=02(Bulk) MxPS= 32 Ivl=0ms
I:* If#= 3 Alt= 0 #EPs= 0 Cls=fe(app. ) Sub=01 Prot=01 Driver=(none)
Signed-off-by: Cho, Yu-Chen <acho@suse.com>
---
drivers/bluetooth/btusb.c | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index f077f4d..75943c3 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -93,6 +93,7 @@ static struct usb_device_id btusb_table[] = {
{ USB_DEVICE(0x0c10, 0x0000) },
/* Broadcom BCM20702A0 */
+ { USB_DEVICE(0x04ca, 0x2003) },
{ USB_DEVICE(0x0489, 0xe042) },
{ USB_DEVICE(0x0a5c, 0x21e3) },
{ USB_DEVICE(0x0a5c, 0x21e6) },
--
1.7.7
^ permalink raw reply related
* Re: Agenda for Linux Wireless (802.11/Bluetooth/NFC) Mini-Summit 2012 (Barcelona!)
From: John W. Linville @ 2012-09-05 19:54 UTC (permalink / raw)
To: Marcel Holtmann; +Cc: linux-wireless, linux-bluetooth, alexander.smirnov
In-Reply-To: <1346874819.21200.109.camel@aeonflux>
On Wed, Sep 05, 2012 at 12:53:39PM -0700, Marcel Holtmann wrote:
> Hi John,
>
> > The time for our meeting in Barcelona is drawing near. I think it
> > is time that we start nailing-down the agenda.
> >
> > We have one room on the first day, and three rooms on the second day.
> > I figure that the Bluetooth and 802.11 groups should each get a
> > break-out room for their own in-depth discussons on the second day and
> > the third room can be used for more general topics and presentations.
> >
> > With that said, there are still a number of slots available for
> > presentations or discussion topics. This is especially true for the
> > 802.11 group... Please step-up with some suggested topics!
> >
> > Below is my strawman agenda proposal. Please make suggestions for
> > improvements!
> >
> > Day 1
> > -----
> >
> > Everyone together in a single room...
> >
> > Time Topic Speaker
> > ---- ----- -------
> > 0930 Welcome/Intro/Agenda John Linville
> >
> > 1000 802.15.4 stack, 6lowpan Alexander Smirnov
> >
> > 1100 Break
> >
> > 1130 Virtual Bluetooth AMP Controller for mac80211 Andrei Emeltchenko
>
> can we swap this talk with my Bluetooth overview talk. So that we get
> all the overview talks on the first day. And keep the breakout talks on
> the next day.
Sure, no problem.
Now, if we only had a few 802.11-related topics...
--
John W. Linville Someday the world will need a hero, and you
linville@tuxdriver.com might be all we have. Be ready.
^ permalink raw reply
* Re: Agenda for Linux Wireless (802.11/Bluetooth/NFC) Mini-Summit 2012 (Barcelona!)
From: Marcel Holtmann @ 2012-09-05 19:53 UTC (permalink / raw)
To: John W. Linville; +Cc: linux-wireless, linux-bluetooth, alexander.smirnov
In-Reply-To: <20120822201930.GC14913@tuxdriver.com>
Hi John,
> The time for our meeting in Barcelona is drawing near. I think it
> is time that we start nailing-down the agenda.
>
> We have one room on the first day, and three rooms on the second day.
> I figure that the Bluetooth and 802.11 groups should each get a
> break-out room for their own in-depth discussons on the second day and
> the third room can be used for more general topics and presentations.
>
> With that said, there are still a number of slots available for
> presentations or discussion topics. This is especially true for the
> 802.11 group... Please step-up with some suggested topics!
>
> Below is my strawman agenda proposal. Please make suggestions for
> improvements!
>
> Day 1
> -----
>
> Everyone together in a single room...
>
> Time Topic Speaker
> ---- ----- -------
> 0930 Welcome/Intro/Agenda John Linville
>
> 1000 802.15.4 stack, 6lowpan Alexander Smirnov
>
> 1100 Break
>
> 1130 Virtual Bluetooth AMP Controller for mac80211 Andrei Emeltchenko
can we swap this talk with my Bluetooth overview talk. So that we get
all the overview talks on the first day. And keep the breakout talks on
the next day.
> 1230 Lunch
>
> 1400 NFC "state of the union", etc. Ortiz / Elias / Chlad
>
> 1500 Break
>
> ...
>
> 1800 Adjourn
>
>
> Day 2
> -----
>
> 802.11 break-out room...
>
> Time Topic Speaker
> ---- ----- -------
> 1000 Regulatory updates Luis Rodriguez
>
> 1100 Break
>
> ...
>
> 1800 Adjourn
We could move the mac80211 AMP controller here.
> Bluetooth break-out room...
>
> Time Topic Speaker
> ---- ----- -------
> 1000 Bluetooth: state of the union Marcel Holtmann
>
> 1100 Break
>
> 1130 status and roadmap of Bluetooth LE Joao Paulo Rechi Vita
And then just continue with the LE topic. Then we only have two parallel
tracks on Friday.
>
> 1230 Lunch
>
> ...
>
> 1800 Adjourn
>
>
> Presentation room...
>
> Time Topic Speaker
> ---- ----- -------
> 1000 wireless community networks Nick Kossifidis
>
> 1100 Break
>
> 1130 "a short overview what we do in ConnMan" Wagner / Flykt
>
> 1230 Lunch
>
> 1400 oFono / mobile wireless Denis Kenzior
>
> 1500 Break
>
> ...
>
> 1800 Adjourn
>
>
> So...suggestions??
>
Regards
Marcel
^ permalink raw reply
* Re: [PATCH] Add support for Logitech Harmony Adapter for PS3
From: David Dillow @ 2012-09-05 19:28 UTC (permalink / raw)
To: Bastien Nocera; +Cc: linux-bluetooth
In-Reply-To: <1346870088.2680.30.camel@novo.hadess.net>
On Wed, 2012-09-05 at 19:34 +0100, Bastien Nocera wrote:
> On Thu, 2012-08-30 at 22:06 -0400, David Dillow wrote:
> > This emulates a Sony BD Remote for the Logitech Harmony series of
> > universal remotes.
>
> Can't test this, but looks good to me.
Good point, I should mention that this is working quite well for my
MythTV setup downstairs...
^ permalink raw reply
* Re: [PATCH] Add support for Logitech Harmony Adapter for PS3
From: Bastien Nocera @ 2012-09-05 18:34 UTC (permalink / raw)
To: David Dillow; +Cc: linux-bluetooth
In-Reply-To: <1346378760.7976.2.camel@obelisk.thedillows.org>
On Thu, 2012-08-30 at 22:06 -0400, David Dillow wrote:
> This emulates a Sony BD Remote for the Logitech Harmony series of
> universal remotes.
Can't test this, but looks good to me.
> profiles/input/fakehid.c | 10 ++++++++++
> 1 files changed, 10 insertions(+), 0 deletions(-)
>
> diff --git a/profiles/input/fakehid.c b/profiles/input/fakehid.c
> index 3be1489..dd47287 100644
> --- a/profiles/input/fakehid.c
> +++ b/profiles/input/fakehid.c
> @@ -342,6 +342,16 @@ static struct fake_hid fake_hid_table[] = {
> .setup_uinput = ps3remote_setup_uinput,
> .devices = NULL,
> },
> + /* Logitech Harmony Adapter for PS3 */
> + {
> + .vendor = 0x046d,
> + .product = 0x0306,
> + .connect = fake_hid_common_connect,
> + .disconnect = fake_hid_common_disconnect,
> + .event = ps3remote_event,
> + .setup_uinput = ps3remote_setup_uinput,
> + .devices = NULL,
> + },
>
> { },
> };
>
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: [PATCH] bluetooth.h: fix compile issue when using in C++
From: Pacho Ramos @ 2012-09-05 17:56 UTC (permalink / raw)
To: Johan Hedberg
Cc: iwamatsu, pkg-bluetooth-maintainers, W. Trevor King,
linux-bluetooth, Patrick Ohly
In-Reply-To: <1346866033.17971.4.camel@belkin4>
[-- Attachment #1: Type: text/plain, Size: 1325 bytes --]
El mié, 05-09-2012 a las 19:27 +0200, Pacho Ramos escribió:
> El lun, 27-08-2012 a las 16:40 -0700, Johan Hedberg escribió:
> > Hi,
> >
> > On Fri, Aug 17, 2012, W. Trevor King wrote:
> > > On Wed, Aug 01, 2012 at 04:41:33PM +0200, Pacho Ramos wrote:
> > > > El dom, 29-07-2012 a las 09:52 +0200, Pacho Ramos escribió:
> > > > > Today I got a report downstream showing that old problem:
> > > > > http://permalink.gmane.org/gmane.linux.bluez.kernel/22306
> > > > >
> > > > > is still not fixed.
> > > > >
> > > > > Could you please commit debian patch to fix this?
> > > > > http://patch-tracker.debian.org/patch/series/view/bluez/4.101-1/09_fix_ftbfs_with_c99.patch
> > > >
> > > > Any news about this? Thanks
> > >
> > > Bump :)
> >
> > The patch would need to be sent as a proper git patch to this mailing
> > list. Particularly, we need proper author information for the patch as
> > well as a commit message explaining the background to the patch and why
> > it is correct (including a reference to the C++ standard and/or gcc
> > documentation).
> >
> > Johan
> >
>
> Will forward this message to patch authors and debian maintainers to let
> them reformat it with proper authoring.
Umm, it could be a gcc bug per:
https://bugzilla.redhat.com/show_bug.cgi?id=786966#c5
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 198 bytes --]
^ permalink raw reply
* Re: [PATCH] bluetooth.h: fix compile issue when using in C++
From: Pacho Ramos @ 2012-09-05 17:27 UTC (permalink / raw)
To: Johan Hedberg, iwamatsu, pkg-bluetooth-maintainers
Cc: W. Trevor King, linux-bluetooth, Patrick Ohly
In-Reply-To: <20120827234054.GA7793@x220.sheraton.com>
[-- Attachment #1: Type: text/plain, Size: 1112 bytes --]
El lun, 27-08-2012 a las 16:40 -0700, Johan Hedberg escribió:
> Hi,
>
> On Fri, Aug 17, 2012, W. Trevor King wrote:
> > On Wed, Aug 01, 2012 at 04:41:33PM +0200, Pacho Ramos wrote:
> > > El dom, 29-07-2012 a las 09:52 +0200, Pacho Ramos escribió:
> > > > Today I got a report downstream showing that old problem:
> > > > http://permalink.gmane.org/gmane.linux.bluez.kernel/22306
> > > >
> > > > is still not fixed.
> > > >
> > > > Could you please commit debian patch to fix this?
> > > > http://patch-tracker.debian.org/patch/series/view/bluez/4.101-1/09_fix_ftbfs_with_c99.patch
> > >
> > > Any news about this? Thanks
> >
> > Bump :)
>
> The patch would need to be sent as a proper git patch to this mailing
> list. Particularly, we need proper author information for the patch as
> well as a commit message explaining the background to the patch and why
> it is correct (including a reference to the C++ standard and/or gcc
> documentation).
>
> Johan
>
Will forward this message to patch authors and debian maintainers to let
them reformat it with proper authoring.
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 198 bytes --]
^ permalink raw reply
* Re: [PATCH BlueZ v5 00/14] LE General Connection Establishment procedure
From: Joao Paulo Rechi Vita @ 2012-09-05 17:15 UTC (permalink / raw)
To: Chen Ganir; +Cc: linux-bluetooth
In-Reply-To: <5046DC86.7030905@ti.com>
On Wed, Sep 5, 2012 at 2:00 AM, Chen Ganir <chen.ganir@ti.com> wrote:
> João,
>
>
> On 09/04/2012 10:04 PM, João Paulo Rechi Vita wrote:
>>
>> This series implement the LE General Connection Establishment procedure
>> for LE connections.
>>
>> If there are LE bonded devices marked for auto connection they are added
>> to a connect_list on the adapter. When there is any device on this list
>> scan is performed continuously. When a device is found the connect_list
>
> How do we stop this scan ? Do we need to remove all auto-connect settings?
>
The scan stops when there are no devices left on the connect_list. The
connect_list is the new interface to connect to LE devices, and it
will use the GCE procedure. The auto-connect flag here simply states
whether or not we should try to re-connect to a device after
disconnection (adding it back to the connect_list).
>
>> is checked. If that device is on the list scan is stopped and a
>> connection attempt is made to that device.
>
> Do we have a timeout for this ? What happens if we succeed ? Do we start
> scanning again if more devices are set to auto-connect ? What happens when
> we fail a connection ? Do we retry to the same or start scanning again ?
>
Yes, right now there is the L2CAP timeout of 40s for an LE connect. If
the connection fails the device is added back to the connect_list, on
the att_error_cb() on src/device.c. After a connect attempt finishes
(either with sucess or fail) we check if there are any devices on the
connect_list and if so, we restart scanning.
>
>>
>> If any client tries to perform discovery and the scan for the General
>> Connection Establishment procedure is active, the discovery request is
>> queued and performed right after the GCEP scan session finishes.
>>
> I'm am having difficulties understanding the logic here. You say that as
> long as we have bonded devices set for auto-connect, the GCE scan will run
> until a connection is made?. What happens if we do not find any device ? Do
> we scan forever?
>
Scan will be active until a all LE bonded devices are connected or
removed (unpaired).
> This is a bit of a problem - device discovery can not be queued. Discovering
> devices is a user initiated command, and it should run whenever a client
> requires it. When a user requests for a list of devices, he expects to get
> the list. He does not care about background logic. The proper logic here is
> to pause the background scanning, discover devices (if LE scan reveals
> bonded devices that have auto-connect setting they should connect and then
> resume the discovery). After Device discovery is terminated, background
> connect scan should be continued.
>
And that is exactly what is implemented right now :)
Thanks for the reviewing, Chen!
--
João Paulo Rechi Vita
Openbossa Labs - INdT
^ permalink raw reply
* Re: GSoC: Bluetooth Replayer update
From: Anton Weber @ 2012-09-05 14:19 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <CA+6PnXwQ58yTEVGSjKOFAgq3YZT2Oq4nED72boos7pkX6gOFiw@mail.gmail.com>
Hello everyone,
after last month's "pencils down" date, this will be my last project
update on the mailing list in this form.
Now that the deadlines have passed, my project is coming to an end, at
least within this year's Google Summer of Code.
But this doesn't mean that it's the last time I will work on it or
with BlueZ in general.
I have already submitted my Bluetooth Replayer utility to the mailing
list and updated the patch series today to include additional
documentation.
I am sure there is a lot of room to make the tool better and future
improvements will now depend on feedback from the BlueZ community.
To find out if the Bluetooth Replayer is in fact the useful debugging
tool I intended it to be, it is time to put it into practice and see
where to go on from here.
So please feel free to pull the patches off the mailing list (tagged
with 'replay') and give my work a try. You can find instructions on
how to use the tool in a quick tutorial or in the man page (both
included in the patches).
And of course everyone is very welcome to contribute himself. As
suggested by my mentor, one good idea for the future is to create a
small GUI that helps creating config files, a process which is rather
tedious at the moment.
If you have any questions, you can always contact me or my mentor
Anderson Lizardo directly.
Cheers,
Anton
^ permalink raw reply
* [PATCH BlueZ v3 6/6] replay: Add tutorial
From: Anton Weber @ 2012-09-05 14:14 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Anton Weber
In-Reply-To: <1346854462-12396-1-git-send-email-ant@antweb.me>
Add short tutorial to show example usage of btreplay.
---
doc/btreplay-tutorial.txt | 60 +++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 60 insertions(+)
create mode 100644 doc/btreplay-tutorial.txt
diff --git a/doc/btreplay-tutorial.txt b/doc/btreplay-tutorial.txt
new file mode 100644
index 0000000..61e96b6
--- /dev/null
+++ b/doc/btreplay-tutorial.txt
@@ -0,0 +1,60 @@
+BlueZ Bluetooth Replayer Tutorial
+*********************************
+
+Copyright (C) 2012 Anton Weber <ant@antweb.me>
+
+
+Create dump
+===========
+A dump can be recorded using the -b option of btmon.
+The best way to record a suitable dump is to disable the Bluetooth controller
+before recording. That way btmon also records the initialisation sequence.
+
+# sudo btmon -b testdump
+<plug in / enable Bluetooth contoller>
+<connect Bluetooth mouse>
+<move mouse around>
+<CTRL+C>
+
+
+Replay dump
+===========
+
+First make sure the VHCI driver is loaded:
+
+# sudo modprobe hci_vhci
+# ls /dev | grep vhci
+
+Now the dump can be replayed with btreplay. When the same machine is used to
+replay the dump, it is recommended to unplug / disable the Bluetooth controller
+to avoid conflicts.
+
+The simplest way to use the Bluetooth Replayer is to run
+
+# sudo btreplay testdump
+
+Some scenarios require minimal delay during the execution to be replayed
+correctly (such as the example above).
+One solution is to use the delta timing mode that adds delays according to the
+time difference between packets in the dump file.
+
+# sudo btreplay -d delta testdump
+
+Running btreplay with a dump from another machine can cause some issues with
+the initialisation sequence. The host might send out packets in a different
+order.
+btreplay will show several packets marked as "[Unknown] ! Wrong opcode" and
+the replay process can get stuck.
+When these packets are not relevant to the actual scenario, they can be ignored
+using a config file. For example, they can be passed on to the emulator.
+To do so, set the action for these packet types to 'emulate' in a config file.
+
+Example config contents:
+
+HCI_CMD_0x03|0x0001 action=emulate
+HCI_CMD_0x03|0x0018 action=emulate
+
+
+and run btreplay with this config file.
+
+# sudo btreplay -d delta -c testconfig testdump
--
1.7.9.5
^ permalink raw reply related
* [PATCH BlueZ v3 5/6] replay: Add man page
From: Anton Weber @ 2012-09-05 14:14 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Anton Weber
In-Reply-To: <1346854462-12396-1-git-send-email-ant@antweb.me>
---
Makefile.tools | 6 +-
tools/replay/btreplay.1 | 148 +++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 152 insertions(+), 2 deletions(-)
create mode 100644 tools/replay/btreplay.1
diff --git a/Makefile.tools b/Makefile.tools
index ba2db00..8b1e3de 100644
--- a/Makefile.tools
+++ b/Makefile.tools
@@ -94,11 +94,13 @@ endif
dist_man_MANS += tools/rfcomm.1 tools/l2ping.8 \
tools/hciattach.8 tools/hciconfig.8 \
- tools/hcitool.1 tools/sdptool.1 tools/ciptool.1
+ tools/hcitool.1 tools/sdptool.1 tools/ciptool.1 \
+ tools/replay/btreplay.1
else
EXTRA_DIST += tools/rfcomm.1 tools/l2ping.8 \
tools/hciattach.8 tools/hciconfig.8 \
- tools/hcitool.1 tools/sdptool.1 tools/ciptool.1
+ tools/hcitool.1 tools/sdptool.1 tools/ciptool.1 \
+ tools/replay/btreplay.1
endif
CLEANFILES += tools/lexer.c tools/parser.c tools/parser.h
diff --git a/tools/replay/btreplay.1 b/tools/replay/btreplay.1
new file mode 100644
index 0000000..36fd6c7
--- /dev/null
+++ b/tools/replay/btreplay.1
@@ -0,0 +1,148 @@
+.TH BTREPLAY 1 "August 2012" BlueZ "Linux System Administration "
+
+.SH NAME
+btreplay \- Bluetooth Replayer
+
+.SH SYNOPSIS
+.B btreplay
+.RB [\| \-d
+.IR none|delta \|]
+.RB [\| \-m
+.IR factor \|]
+.RB [\| \-t
+.IR timeout \|]
+.RB [\| \-c
+.IR config-file \|]
+.RB [\| \-v \|]
+.RI "" file " ..."
+
+.SH DESCRIPTION
+.B btreplay
+uses a VHCI interface to simulate HCI traffic from a recorded scenario. It
+reads packets from BTSnoop dump files and replays them on the virtual
+interface.
+.PP
+.TP
+.B "Delay modes"
+The delay mode handles the delay between two packets in the replay process.
+.br
+Following delay modes are supported:
+
+.BR "delta" ": use time difference between two packets (delta value) from the"
+dump for delay
+.br
+.BR "none" ": no delay"
+.TP
+.B "Delay modifier"
+Allows to speed up or slow down the overall packet delay. When used with
+delta delay mode, each delta value in the sequence is multiplied with the
+specified factor.
+.TP
+.B "Packet action"
+The action defines how packets are handled within the replay process.
+.BR "" "The default action is " "replay" "."
+
+.BR "replay" ": Replay packet from dump file"
+.br
+.BR "skip" ": Skip packet"
+.br
+.BR "emulate" ": Forward packet to emulator"
+.TP
+.B "Config file"
+A config file can alter attributes and actions for specific packets in the
+sequence or packet types.
+
+.SH OPTIONS
+.TP
+.BI "\-d, --delay-mode=" "none|delta"
+.RI "Specify delay mode (default is " "none" ")"
+.TP
+.BI "\-m, --delay-modifier=" "N"
+Set delay modifier to N (default is 1)
+.TP
+.BI "\-t, --timeout=" "N"
+.RI "Set timeout to " "N" " milliseconds when receiving packets from host."
+.br
+Set to -1 by default (no timeout)
+.TP
+.BI "\-c, --config=" "config-file"
+Use config file
+.TP
+.BI "\-v, --verbose"
+Enable verbose output
+.TP
+.BI \--version
+Give version information
+.TP
+.BI \--help
+Give a short usage message
+
+.SH CONFIG FILE FORMAT
+The config parser expects one definition per line. Each line has the syntax
+
+.in +4n
+.nf
+.I "scope key=value[,key=value,...]"
+.fi
+.in
+
+and must be terminated by EOF or '\\n'.
+
+.SS Scopes
+The scope defines which packets are affected by the configuration. All scopes
+that do not specify a particular position in the sequence are used as a type
+filter (i.e. they also apply to all incoming and outgoing packets, even if they
+are not in the sequence).
+.TP
+.B all
+All packets in the sequence
+.TP
+.B N
+Single packet
+.TP
+.B N-M
+Packet range (e.g. 2-10, from packet 2 to 10)
+.TP
+.B HCI_ACL
+ACL data packets
+.TP
+.B HCI_EVT_0xXX
+Event code
+.br
+(e.g. HCI_EVT_0x0e, all packets with event code 0x0e (Command Complete))
+.TP
+.B HCI_CMD_0xXX|0xXXXX
+Opcode
+.br
+(e.g. 0x03|0x0003, all packets with OGF 0x03 and OCF 0x0003 (Reset)).
+.br
+Also applies to corresponding Command Complete event packets.
+.PP
+(N and M being the packet position in the sequence, starting with 1)
+
+.SS Properties
+The properties define the configuration that should be applied to the scope.
+.RB "Every property has a " "key"
+.RI " and a " "value" " delimited by an equals sign."
+.TP
+.BI "action="replay|skip|emulate
+Set packet action
+.TP
+.BI "delta="value
+Override delta value (used in delta delay mode)
+
+.SS Example configuration
+all delta=300,action=replay
+.br
+1-4 action=emulate
+.br
+1 delta=500
+.br
+HCI_EVT_0x0e delta=0
+.br
+HCI_CMD_0x03|0x0003 action=emulate
+.br
+HCI_ACL action=replay
+.br
+.SH AUTHOR
+Written by Anton Weber <ant@antweb.me>
--
1.7.9.5
^ permalink raw reply related
* [PATCH BlueZ v3 4/6] replay: Add config file parser and skip action
From: Anton Weber @ 2012-09-05 14:14 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Anton Weber
In-Reply-To: <1346854462-12396-1-git-send-email-ant@antweb.me>
Add support for config files to manipulate the loaded sequence.
A config file can be specified with the new -c command line parameter.
The config syntax is:
scope key=value[,key=value,...]
e.g.:
all delta=300,action=replay
1-4 action=emulate
1 delta=500
HCI_EVT_0x0e delta=0
HCI_CMD_0x03|0x0003 action=emulate
HCI_ACL action=replay
The inital version supports the keys delta and action and
all scope types shown in the example.
HCISEQ_ACTION_SKIP allows to skip a packet in the sequence.
The action can be set in config files using "action=skip".
---
Makefile.tools | 1 +
tools/replay/config-parser.c | 506 ++++++++++++++++++++++++++++++++++++++++++
tools/replay/config-parser.h | 36 +++
tools/replay/hciseq.h | 3 +-
tools/replay/main.c | 117 +++++++++-
tools/replay/main.h | 2 -
6 files changed, 661 insertions(+), 4 deletions(-)
create mode 100644 tools/replay/config-parser.c
create mode 100644 tools/replay/config-parser.h
diff --git a/Makefile.tools b/Makefile.tools
index 8b3c8d8..ba2db00 100644
--- a/Makefile.tools
+++ b/Makefile.tools
@@ -72,6 +72,7 @@ emulator_btvirt_SOURCES = emulator/main.c monitor/bt.h \
tools_replay_btreplay_SOURCES = tools/replay/main.h tools/replay/main.c \
tools/replay/hciseq.h tools/replay/hciseq.c \
tools/replay/time.h tools/replay/time.c \
+ tools/replay/config-parser.h tools/replay/config-parser.c \
monitor/packet.h monitor/packet.c \
monitor/btsnoop.h monitor/btsnoop.c \
monitor/control.h monitor/control.c \
diff --git a/tools/replay/config-parser.c b/tools/replay/config-parser.c
new file mode 100644
index 0000000..5219eb9
--- /dev/null
+++ b/tools/replay/config-parser.c
@@ -0,0 +1,506 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ * Copyright (C) 2012 Anton Weber <ant@antweb.me>
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <sys/time.h>
+
+#include "config-parser.h"
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "monitor/bt.h"
+
+#define MAXLINE 128
+#define MAX_ATTR_KEY 32
+#define MAX_ATTR_VAL 32
+
+static struct hciseq_list *seq;
+static struct hciseq_type_cfg *type_cfg;
+
+static bool verbose;
+static int line;
+
+struct scope_list {
+ struct scope_node *head;
+};
+
+struct scope_node {
+ int pos;
+ struct hciseq_attr *attr;
+ struct scope_node *next;
+};
+
+struct attr_list {
+ struct attr_node *head;
+};
+
+struct attr_node {
+ char key[MAX_ATTR_KEY];
+ char val[MAX_ATTR_VAL];
+ struct attr_node *next;
+};
+
+static void attr_list_delete(struct attr_list *list)
+{
+ struct attr_node *node, *next;
+
+ if (list == NULL)
+ return;
+
+ node = list->head;
+ free(list);
+ while (node != NULL) {
+ next = node->next;
+ free(node);
+ node = next;
+ }
+}
+
+static void scope_list_delete(struct scope_list *list)
+{
+ struct scope_node *node, *next;
+
+ if (list == NULL)
+ return;
+
+ node = list->head;
+ free(list);
+ while (node != NULL) {
+ next = node->next;
+ free(node);
+ node = next;
+ }
+}
+
+static struct attr_list *parse_attrstr(char *attrstr)
+{
+ struct attr_list *list = NULL;
+ struct attr_node *node;
+ char *res;
+
+ do {
+ if (list == NULL) {
+ if ((res = strtok(attrstr, "=")) == NULL) {
+ /* nothing to parse */
+ return NULL;
+ }
+
+ list = malloc(sizeof(*list));
+ node = malloc(sizeof(*node));
+ list->head = node;
+ } else {
+ if ((res = strtok(NULL, "=")) == NULL) {
+ /* nothing left to parse */
+ break;
+ }
+
+ node->next = malloc(sizeof(*node));
+ node = node->next;
+ }
+
+ strncpy(node->key, res, sizeof(node->key));
+ node->key[sizeof(node->key) - 1] = '\0';
+
+ if ((res = strtok(NULL, ",")) == NULL) {
+ fprintf(stderr, "Invalid attribute");
+ goto err;
+ }
+ strncpy(node->val, res, sizeof(node->val));
+ node->val[sizeof(node->val) - 1] = '\0';
+
+ node->next = NULL;
+ } while (res != NULL);
+
+ return list;
+
+err:
+ attr_list_delete(list);
+ return NULL;
+}
+
+static int apply_attr(struct scope_node *scope_node,
+ struct attr_list *list)
+{
+ struct attr_node *attr_node = list->head;
+ struct hciseq_attr *attr = scope_node->attr;
+ long lval;
+
+ while (attr_node != NULL) {
+ if (strcmp(attr_node->key, "delta") == 0) {
+ /* delta */
+ lval = strtol(attr_node->val, NULL, 10);
+ if (errno == ERANGE || errno == EINVAL)
+ return 1;
+
+ if (verbose) {
+ printf("\t[%d] set delta to %ld\n",
+ scope_node->pos, lval);
+ }
+
+ attr->ts_diff.tv_sec = 0;
+ attr->ts_diff.tv_usec = lval;
+ } else if (strcmp(attr_node->key, "action") == 0) {
+ /* action */
+ if (strcmp(attr_node->val, "replay") == 0) {
+ lval = HCISEQ_ACTION_REPLAY;
+ if (verbose)
+ printf("\t[%d] set action to 'replay'\n",
+ scope_node->pos);
+ } else if (strcmp(attr_node->val, "emulate") == 0) {
+ lval = HCISEQ_ACTION_EMULATE;
+ if (verbose)
+ printf("\t[%d] set action to 'emulate'\n",
+ scope_node->pos);
+ } else if (strcmp(attr_node->val, "skip") == 0) {
+ lval = HCISEQ_ACTION_SKIP;
+ if (verbose)
+ printf("\t[%d] set action to 'skip'\n",
+ scope_node->pos);
+ } else {
+ return 1;
+ }
+
+ attr->action = lval;
+ }
+
+ attr_node = attr_node->next;
+ }
+
+ return 0;
+}
+
+static int apply_attr_scope(struct scope_list *scope,
+ struct attr_list *attr)
+{
+ struct scope_node *node = scope->head;
+
+ while (node != NULL) {
+ apply_attr(node, attr);
+ node = node->next;
+ }
+
+ return 0;
+}
+
+static struct scope_list *get_scope_range(int from, int to)
+{
+ struct scope_list *list = NULL;
+ struct scope_node *scope_node;
+ struct hciseq_node *seq_node = seq->current;
+ int pos = 1;
+
+ /* forward to 'from' */
+ while (pos < from) {
+ seq_node = seq_node->next;
+ pos++;
+ }
+
+ /* create scope list for range */
+ while (pos <= to) {
+ if (verbose)
+ printf("\tadd packet [%d]\n", pos);
+
+ if (list == NULL) {
+ list = malloc(sizeof(*list));
+ scope_node = malloc(sizeof(*scope_node));
+ list->head = scope_node;
+ } else {
+ scope_node->next = malloc(sizeof(*scope_node));
+ scope_node = scope_node->next;
+ }
+ scope_node->attr = seq_node->attr;
+ scope_node->pos = pos;
+ scope_node->next = NULL;
+
+ seq_node = seq_node->next;
+ pos++;
+ }
+
+ return list;
+}
+
+static struct scope_list *get_scope_type(uint8_t type, void *filter1,
+ void *filter2)
+{
+ struct scope_list *list = NULL;
+ struct scope_node *scope_node;
+ struct hciseq_node *seq_node = seq->current;
+ uint16_t opcode, node_opcode;
+ uint8_t node_ogf, ogf = 0x00;
+ uint16_t node_ocf, ocf = 0x0000;
+ uint8_t node_evt, evt = 0x00;
+ bool match;
+ int pos = 1;
+ struct hciseq_attr *attr;
+
+ if (type == BT_H4_CMD_PKT) {
+ ogf = *((uint8_t *) filter1);
+ ocf = *((uint16_t *) filter2);
+ opcode = cmd_opcode_pack(ogf, ocf);
+
+ if (opcode > 0x2FFF) {
+ attr = NULL;
+ } else {
+ attr = type_cfg->cmd[opcode];
+ if (attr == NULL) {
+ attr = malloc(sizeof(*attr));
+ type_cfg->cmd[opcode] = attr;
+ }
+ }
+ } else if (type == BT_H4_EVT_PKT) {
+ evt = *((uint8_t *) filter1);
+ attr = type_cfg->evt[evt];
+
+ if (attr == NULL) {
+ attr = malloc(sizeof(*attr));
+ type_cfg->evt[evt] = attr;
+ }
+ } else if (type == BT_H4_ACL_PKT) {
+ attr = type_cfg->acl;
+ if (attr == NULL) {
+ attr = malloc(sizeof(*attr));
+ type_cfg->acl = attr;
+ }
+ } else {
+ attr = NULL;
+ }
+
+ /* add matching packets in sequence */
+ while (seq_node != NULL) {
+ match = false;
+ if (((uint8_t *) seq_node->frame->data)[0] == type) {
+ if (type == BT_H4_CMD_PKT) {
+ node_opcode = *((uint16_t *)
+ (seq_node->frame->data + 1));
+ node_ogf = cmd_opcode_ogf(node_opcode);
+ node_ocf = cmd_opcode_ocf(node_opcode);
+ if (node_ogf == ogf && node_ocf == ocf)
+ match = true;
+ } else if (type == BT_H4_EVT_PKT) {
+ node_evt = ((uint8_t *) seq_node->frame->data)[1];
+ if (evt == node_evt)
+ match = true;
+ } else if (type == BT_H4_ACL_PKT) {
+ match = true;
+ }
+ }
+
+ if (match) {
+ if (verbose)
+ printf("\tadd packet [%d]\n", pos);
+
+ if (list == NULL) {
+ list = malloc(sizeof(*list));
+ scope_node = malloc(sizeof(*scope_node));
+ list->head = scope_node;
+ } else {
+ scope_node->next = malloc(sizeof(*scope_node));
+ scope_node = scope_node->next;
+ }
+ scope_node->attr = seq_node->attr;
+ scope_node->pos = pos;
+ scope_node->next = NULL;
+ }
+ seq_node = seq_node->next;
+ pos++;
+ }
+
+ /* add type config */
+ if (attr != NULL) {
+ if (list == NULL) {
+ list = malloc(sizeof(*list));
+ scope_node = malloc(sizeof(*scope_node));
+ list->head = scope_node;
+ } else {
+ scope_node->next = malloc(sizeof(*scope_node));
+ scope_node = scope_node->next;
+ }
+
+ scope_node->attr = attr;
+ scope_node->pos = 0;
+ scope_node->next = NULL;
+ }
+
+ return list;
+}
+
+static int parse_line(char *buf)
+{
+ char *scopestr, *attrstr;
+ struct scope_list *scope_list = NULL;
+ struct attr_list *attr_list;
+ uint8_t evt, ogf;
+ uint16_t ocf;
+ char *res;
+ int from, to;
+
+ line++;
+
+ /* split line into scope and attributes */
+ if ((scopestr = strtok(buf, " ")) == NULL)
+ return 1;
+
+ if ((attrstr = strtok(NULL, "\n")) == NULL)
+ return 1;
+
+ if (verbose)
+ printf("Parsing scope (%s)\n", scopestr);
+
+ if (strcmp(scopestr, "all") == 0) {
+ if (verbose)
+ printf("\tadd all\n");
+
+ scope_list = get_scope_range(0, seq->len);
+ } else if ((strncmp(scopestr, "HCI_", 4) == 0) && strlen(scopestr) >= 7) {
+ /* make sure scopestr is at least 7 chars long, so we can check for HCI_XXX */
+
+ if (strncmp(scopestr + 4, "ACL", 3) == 0) {
+ /* scope is HCI_ACL */
+ if (verbose)
+ printf("\tadd all HCI ACL data packets:");
+
+ scope_list = get_scope_type(BT_H4_ACL_PKT, NULL, NULL);
+ } else if (strncmp(scopestr + 4, "CMD", 3) == 0) {
+ /* scope is HCI_CMD_
+ * length must be exactly 19 (e.g. HCI_CMD_0x03|0x0003) */
+ if (strlen(scopestr) != 19 || scopestr[12] != '|')
+ return 1;
+
+ if (sscanf(scopestr + 8, "0x%2hhx", &ogf) <= 0)
+ return 1;
+
+ if (sscanf(scopestr + 13, "0x%4hx", &ocf) <= 0)
+ return 1;
+
+ if (verbose)
+ printf("\tadd all HCI command packets with opcode (0x%2.2x|0x%4.4x):\n",
+ ogf, ocf);
+
+ scope_list = get_scope_type(BT_H4_CMD_PKT, &ogf, &ocf);
+ } else if (strncmp(scopestr + 4, "EVT", 3) == 0) {
+ /* scope is CMD_EVT_
+ * length must be exactly 12 (e.g. HCI_EVT_0x0e) */
+ if (strlen(scopestr) != 12)
+ return 1;
+
+ if (sscanf(scopestr + 8, "0x%2hhx", &evt) <= 0)
+ return 1;
+
+ if (verbose)
+ printf("\tadd all HCI event packets with event type (0x%2.2x):\n",
+ evt);
+
+ scope_list = get_scope_type(BT_H4_EVT_PKT, &evt, NULL);
+ }
+ } else if (scopestr[0] >= 48 || scopestr[0] <= 57) {
+ /* first char is a digit */
+ if ((res = strtok(scopestr, "-")) == NULL)
+ return 1;
+
+ from = atoi(res);
+ if (from <= 0)
+ return 1;
+
+ if ((res = strtok(NULL, ":")) == NULL) {
+ /* just one packet */
+ if (verbose)
+ printf("\tadd packet single packet\n");
+
+ scope_list = get_scope_range(from, from);
+ } else {
+ /* range */
+ to = atoi(res);
+ if (to > seq->len)
+ return 1;
+
+ if (verbose)
+ printf("\tadd packets %d to %d\n", from, to);
+
+ scope_list = get_scope_range(from, to);
+ }
+
+ }
+
+ if (verbose)
+ printf("Parsing attributes (%s)\n", attrstr);
+
+ if ((attr_list = parse_attrstr(attrstr)) == NULL) {
+ return 1;
+ }
+
+ if (scope_list != NULL) {
+ apply_attr_scope(scope_list, attr_list);
+ scope_list_delete(scope_list);
+ } else {
+ if (verbose)
+ printf("Empty scope, skipping\n");
+ }
+
+ attr_list_delete(attr_list);
+
+ return 0;
+}
+
+int parse_config(char *path, struct hciseq_list *_seq,
+ struct hciseq_type_cfg *_type_cfg, bool _verbose)
+{
+ char *buf;
+ FILE *file;
+
+ seq = _seq;
+ type_cfg = _type_cfg;
+ verbose = _verbose;
+ line = 0;
+
+ printf("Reading config file...\n");
+
+ buf = malloc(sizeof(char) * MAXLINE);
+ if (buf == NULL) {
+ fprintf(stderr, "Failed to allocate buffer\n");
+ return 1;
+ }
+
+ if ((file = fopen(path, "r")) == NULL) {
+ perror("Failed to open config file");
+ return 1;
+ }
+
+ while (fgets(buf, MAXLINE, file) != NULL) {
+ if (parse_line(buf)) {
+ fprintf(stderr, "Error parsing config file - line %d\n",
+ line);
+ free(buf);
+ return 1;
+ }
+ }
+
+ printf("Done\n\n");
+ fclose(file);
+ free(buf);
+
+ return 0;
+}
diff --git a/tools/replay/config-parser.h b/tools/replay/config-parser.h
new file mode 100644
index 0000000..265628d
--- /dev/null
+++ b/tools/replay/config-parser.h
@@ -0,0 +1,36 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ * Copyright (C) 2012 Anton Weber <ant@antweb.me>
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include "hciseq.h"
+
+struct hciseq_type_cfg {
+ struct hciseq_attr *cmd[9216]; /*
+ * opcodes 0x0000 - 0x23FF
+ * (OGF 0x01 - 0x08)
+ */
+ struct hciseq_attr *evt[256]; /* events 0x00 - 0xFF */
+ struct hciseq_attr *acl;
+};
+
+int parse_config(char *path, struct hciseq_list *_seq,
+ struct hciseq_type_cfg *_type_cfg, bool _verbose);
diff --git a/tools/replay/hciseq.h b/tools/replay/hciseq.h
index 1454147..fa589a3 100644
--- a/tools/replay/hciseq.h
+++ b/tools/replay/hciseq.h
@@ -43,7 +43,8 @@ struct frame {
enum hciseq_action {
HCISEQ_ACTION_REPLAY = 0,
- HCISEQ_ACTION_EMULATE = 1
+ HCISEQ_ACTION_EMULATE = 1,
+ HCISEQ_ACTION_SKIP = 2
};
struct hciseq_list {
diff --git a/tools/replay/main.c b/tools/replay/main.c
index dc281b0..d4f748f 100644
--- a/tools/replay/main.c
+++ b/tools/replay/main.c
@@ -41,6 +41,7 @@
#include "main.h"
#include "time.h"
+#include "config-parser.h"
#include "lib/bluetooth.h"
#include "lib/hci.h"
#include "emulator/btdev.h"
@@ -56,6 +57,7 @@
#define TIMING_DELTA 1
static struct hciseq_list dumpseq;
+static struct hciseq_type_cfg type_cfg;
static int fd;
static int pos = 1;
@@ -281,6 +283,35 @@ static void btdev_recv(struct frame *frm)
btdev_receive_h4(btdev, frm->data, frm->data_len);
}
+static struct hciseq_attr *get_type_attr(struct frame *frm)
+{
+ uint8_t pkt_type = ((const uint8_t *) frm->data)[0];
+ uint16_t opcode;
+ uint8_t evt;
+
+ switch (pkt_type) {
+ case BT_H4_CMD_PKT:
+ opcode = *((uint16_t *) (frm->data + 1));
+ if (opcode > 0x2FFF)
+ return NULL;
+ return type_cfg.cmd[opcode];
+ case BT_H4_EVT_PKT:
+ evt = *((uint8_t *) (frm->data + 1));
+
+ /* use attributes of opcode for 'Command Complete' events */
+ if (evt == 0x0e) {
+ opcode = *((uint16_t *) (frm->data + 4));
+ return type_cfg.cmd[opcode];
+ }
+
+ return type_cfg.evt[evt];
+ case BT_H4_ACL_PKT:
+ return type_cfg.acl;
+ default:
+ return NULL;
+ }
+}
+
static bool check_match(struct frame *l, struct frame *r, char *msg)
{
uint8_t type_l = ((const uint8_t *) l->data)[0];
@@ -341,6 +372,7 @@ static bool process_in()
{
static struct frame frm;
static uint8_t data[HCI_MAX_FRAME_SIZE];
+ struct hciseq_attr *attr;
int n;
bool match;
char msg[MAX_MSG];
@@ -362,6 +394,38 @@ static bool process_in()
msg[0] = '\0';
match = check_match(dumpseq.current->frame, &frm, msg);
+ /* check type config */
+ attr = get_type_attr(&frm);
+ if (attr != NULL) {
+ if (attr->action == HCISEQ_ACTION_SKIP) {
+ if (match) {
+ printf("[%4d/%4d] SKIPPING\n", pos,
+ dumpseq.len);
+ return 1;
+ } else {
+ printf("[ Unknown ] %s\n ",
+ msg);
+ dump_frame(&frm);
+ printf(" SKIPPING\n");
+ return 0;
+ }
+ }
+ if (attr->action == HCISEQ_ACTION_EMULATE) {
+ if (match) {
+ printf("[%4d/%4d] EMULATING\n", pos,
+ dumpseq.len);
+ } else {
+ printf("[ Unknown ] %s\n ",
+ msg);
+ printf("EMULATING\n");
+ }
+
+ btdev_recv(&frm);
+
+ return match;
+ }
+ }
+
/* process packet if match */
if (match) {
printf("[%4d/%4d] ", pos, dumpseq.len);
@@ -381,12 +445,20 @@ static bool process_in()
static bool process_out()
{
uint8_t pkt_type;
+ struct hciseq_attr *attr;
/* emulator sends response automatically */
if (dumpseq.current->attr->action == HCISEQ_ACTION_EMULATE) {
return 1;
}
+ /* use type config if set */
+ attr = get_type_attr(dumpseq.current->frame);
+ if (attr != NULL) {
+ if (attr->action == HCISEQ_ACTION_SKIP || attr->action == HCISEQ_ACTION_EMULATE)
+ return true;
+ }
+
pkt_type = ((const uint8_t *) dumpseq.current->frame->data)[0];
switch (pkt_type) {
@@ -412,6 +484,15 @@ static void process()
gettimeofday(&last, NULL);
do {
+ if (dumpseq.current->attr->action == HCISEQ_ACTION_SKIP) {
+ printf("[%4d/%4d] SKIPPING\n ", pos,
+ dumpseq.len);
+ dump_frame(dumpseq.current->frame);
+ dumpseq.current = dumpseq.current->next;
+ pos++;
+ continue;
+ }
+
/* delay */
if (timing == TIMING_DELTA) {
/* consider exec time of process_out()/process_in() */
@@ -485,6 +566,19 @@ static void delete_list()
}
}
+static void delete_type_cfg()
+{
+ int i;
+
+ for (i = 0; i < 9216; i++) {
+ free(type_cfg.cmd[i]);
+ }
+ for (i = 0; i < 256; i++) {
+ free(type_cfg.evt[i]);
+ }
+ free(type_cfg.acl);
+}
+
static void usage(void)
{
printf("hcireplay - Bluetooth replayer\n"
@@ -493,6 +587,7 @@ static void usage(void)
"\t-d, --delay-mode={none|delta} Specify delay mode (default is none)\n"
"\t-m, --delay-modifier=N Set delay modifier to N (default is 1)\n"
"\t-t, --timeout=N Set timeout to N milliseconds when receiving packets from host\n"
+ "\t-c, --config=<file> Use config file\n"
"\t-v, --verbose Enable verbose output\n"
"\t --version Give version information\n"
"\t --help Give a short usage message\n");
@@ -502,6 +597,7 @@ static const struct option main_options[] = {
{"delay-mode", required_argument, NULL, 'd'},
{"delay-modifier", required_argument, NULL, 'm'},
{"timeout", required_argument, NULL, 't'},
+ {"config", required_argument, NULL, 'c'},
{"verbose", no_argument, NULL, 'v'},
{"version", no_argument, NULL, 'V'},
{"help", no_argument, NULL, 'H'},
@@ -512,11 +608,12 @@ int main(int argc, char *argv[])
{
int dumpfd;
int i;
+ char *config = NULL;
while (1) {
int opt;
- opt = getopt_long(argc, argv, "d:m:t:v",
+ opt = getopt_long(argc, argv, "d:m:t:c:v",
main_options, NULL);
if (opt < 0)
break;
@@ -535,6 +632,9 @@ int main(int argc, char *argv[])
case 't':
timeout = atoi(optarg);
break;
+ case 'c':
+ config = optarg;
+ break;
case 'v':
verbose = true;
break;
@@ -572,6 +672,20 @@ int main(int argc, char *argv[])
dumpseq.current = dumpseq.frames;
calc_rel_ts(&dumpseq);
+ /* init type config */
+ for (i = 0; i < 9216; i++)
+ type_cfg.cmd[i] = NULL;
+ for (i = 0; i < 256; i++)
+ type_cfg.evt[i] = NULL;
+ type_cfg.acl = NULL;
+
+ if (config != NULL) {
+ if (parse_config(config, &dumpseq, &type_cfg, verbose)) {
+ vhci_close();
+ return 1;
+ }
+ }
+
/* init emulator */
btdev = btdev_create(0);
btdev_set_send_handler(btdev, btdev_send, NULL);
@@ -595,6 +709,7 @@ int main(int argc, char *argv[])
vhci_close();
btdev_destroy(btdev);
delete_list();
+ delete_type_cfg();
printf("Terminating\n");
return EXIT_SUCCESS;
diff --git a/tools/replay/main.h b/tools/replay/main.h
index 2223789..e8b7365 100644
--- a/tools/replay/main.h
+++ b/tools/replay/main.h
@@ -23,8 +23,6 @@
*
*/
-#include "hciseq.h"
-
struct btsnoop_hdr {
uint8_t id[8]; /* Identification Pattern */
uint32_t version; /* Version Number = 1 */
--
1.7.9.5
^ permalink raw reply related
* [PATCH BlueZ v3 3/6] replay: Add emulation support
From: Anton Weber @ 2012-09-05 14:14 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Anton Weber
In-Reply-To: <1346854462-12396-1-git-send-email-ant@antweb.me>
Integrate emulator so it can process selected packets instead of
replaying them from the sequence. The behaviour is controlled
through the action attribute in hciseq_attr.
If set to HCISEQ_ACTION_EMULATE, hcireplay will use the emulator
to process the packet automatically instead of replaying it.
HCISEQ_ACTION_REPLAY keeps the previous behaviour and replays the
packet using the dump file.
---
Makefile.tools | 1 +
tools/replay/hciseq.h | 1 +
tools/replay/main.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++---
3 files changed, 51 insertions(+), 3 deletions(-)
diff --git a/Makefile.tools b/Makefile.tools
index 6767300..8b3c8d8 100644
--- a/Makefile.tools
+++ b/Makefile.tools
@@ -76,6 +76,7 @@ tools_replay_btreplay_SOURCES = tools/replay/main.h tools/replay/main.c \
monitor/btsnoop.h monitor/btsnoop.c \
monitor/control.h monitor/control.c \
monitor/mainloop.h monitor/mainloop.c \
+ emulator/btdev.h emulator/btdev.c \
lib/hci.h
tools_replay_btreplay_LDADD = lib/libbluetooth-private.la
diff --git a/tools/replay/hciseq.h b/tools/replay/hciseq.h
index f9fe7c8..1454147 100644
--- a/tools/replay/hciseq.h
+++ b/tools/replay/hciseq.h
@@ -43,6 +43,7 @@ struct frame {
enum hciseq_action {
HCISEQ_ACTION_REPLAY = 0,
+ HCISEQ_ACTION_EMULATE = 1
};
struct hciseq_list {
diff --git a/tools/replay/main.c b/tools/replay/main.c
index e026d98..dc281b0 100644
--- a/tools/replay/main.c
+++ b/tools/replay/main.c
@@ -43,6 +43,7 @@
#include "time.h"
#include "lib/bluetooth.h"
#include "lib/hci.h"
+#include "emulator/btdev.h"
#include "monitor/bt.h"
#include "monitor/btsnoop.h"
#include "monitor/control.h"
@@ -69,6 +70,8 @@ static int timing = TIMING_NONE;
static double factor = 1;
static bool verbose = false;
+static struct btdev *btdev;
+
static inline int read_n(int fd, char *buf, int len)
{
int t = 0, w;
@@ -250,6 +253,34 @@ static int recv_frm(int fd, struct frame *frm)
return n;
}
+static void btdev_send(const void *data, uint16_t len, void *user_data)
+{
+ struct frame frm;
+ static void* tmpdata = NULL;
+
+ /* copy data so we respect 'const' qualifier */
+ if(tmpdata == NULL)
+ tmpdata = malloc(HCI_MAX_FRAME_SIZE);
+
+ memcpy(tmpdata, data, len);
+
+ frm.data = tmpdata;
+ frm.len = len;
+ frm.data_len = len;
+ frm.in = 1;
+ printf("[Emulator ] ");
+ dump_frame(&frm);
+ send_frm(&frm);
+}
+
+static void btdev_recv(struct frame *frm)
+{
+ frm->in = 0;
+ printf("[Emulator ] ");
+ dump_frame(frm);
+ btdev_receive_h4(btdev, frm->data, frm->data_len);
+}
+
static bool check_match(struct frame *l, struct frame *r, char *msg)
{
uint8_t type_l = ((const uint8_t *) l->data)[0];
@@ -332,11 +363,16 @@ static bool process_in()
match = check_match(dumpseq.current->frame, &frm, msg);
/* process packet if match */
- if (match)
+ if (match) {
printf("[%4d/%4d] ", pos, dumpseq.len);
- else
- printf("[ Unknown ] %s\n ", msg);
+ if (dumpseq.current->attr->action == HCISEQ_ACTION_EMULATE) {
+ btdev_recv(&frm);
+ return true;
+ }
+ } else {
+ printf("[ Unknown ] %s\n ", msg);
+ }
dump_frame(&frm);
return match;
@@ -346,6 +382,11 @@ static bool process_out()
{
uint8_t pkt_type;
+ /* emulator sends response automatically */
+ if (dumpseq.current->attr->action == HCISEQ_ACTION_EMULATE) {
+ return 1;
+ }
+
pkt_type = ((const uint8_t *) dumpseq.current->frame->data)[0];
switch (pkt_type) {
@@ -531,6 +572,10 @@ int main(int argc, char *argv[])
dumpseq.current = dumpseq.frames;
calc_rel_ts(&dumpseq);
+ /* init emulator */
+ btdev = btdev_create(0);
+ btdev_set_send_handler(btdev, btdev_send, NULL);
+
gettimeofday(&start, NULL);
/*
@@ -548,6 +593,7 @@ int main(int argc, char *argv[])
process();
vhci_close();
+ btdev_destroy(btdev);
delete_list();
printf("Terminating\n");
--
1.7.9.5
^ permalink raw reply related
* [PATCH BlueZ v3 2/6] replay: Add timing functionality
From: Anton Weber @ 2012-09-05 14:14 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Anton Weber
In-Reply-To: <1346854462-12396-1-git-send-email-ant@antweb.me>
Add -d parameter that lets user choose between two delay modes.
delta: use time difference between two packets for delay
none: no delay
Add -m parameter to specify a factor that multiplies delays in
delta delay mode.
Add -t parameter to set the epoll timeout when receiving packets.
---
v2 -> v3: Rename long parameters timing and factor
Makefile.tools | 3 +-
tools/replay/hciseq.c | 53 ++++++++++++++++++++++++++++
tools/replay/hciseq.h | 23 +++++++++++++
tools/replay/main.c | 62 ++++++++++++++++++++++++++++++---
tools/replay/main.h | 21 +-----------
tools/replay/time.c | 91 +++++++++++++++++++++++++++++++++++++++++++++++++
tools/replay/time.h | 31 +++++++++++++++++
7 files changed, 259 insertions(+), 25 deletions(-)
create mode 100644 tools/replay/hciseq.c
create mode 100644 tools/replay/time.c
create mode 100644 tools/replay/time.h
diff --git a/Makefile.tools b/Makefile.tools
index 4a3aca5..6767300 100644
--- a/Makefile.tools
+++ b/Makefile.tools
@@ -70,7 +70,8 @@ emulator_btvirt_SOURCES = emulator/main.c monitor/bt.h \
emulator/btdev.h emulator/btdev.c
tools_replay_btreplay_SOURCES = tools/replay/main.h tools/replay/main.c \
- tools/replay/hciseq.h \
+ tools/replay/hciseq.h tools/replay/hciseq.c \
+ tools/replay/time.h tools/replay/time.c \
monitor/packet.h monitor/packet.c \
monitor/btsnoop.h monitor/btsnoop.c \
monitor/control.h monitor/control.c \
diff --git a/tools/replay/hciseq.c b/tools/replay/hciseq.c
new file mode 100644
index 0000000..8b24264
--- /dev/null
+++ b/tools/replay/hciseq.c
@@ -0,0 +1,53 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ * Copyright (C) 2012 Anton Weber <ant@antweb.me>
+ * Copyright (C) 2011-2012 Intel Corporation
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <stdlib.h>
+#include <stdint.h>
+
+#include "hciseq.h"
+#include "time.h"
+#include "monitor/bt.h"
+
+void calc_rel_ts(struct hciseq_list *seq)
+{
+ struct timeval start;
+ struct hciseq_node *tmp;
+
+ start = seq->current->frame->ts;
+ tmp = seq->current;
+
+ /* first packet */
+ tmp->attr->ts_rel.tv_sec = 0;
+ tmp->attr->ts_rel.tv_usec = 0;
+ tmp->attr->ts_diff.tv_sec = 0;
+ tmp->attr->ts_diff.tv_usec = 0;
+
+ while (tmp->next != NULL) {
+ timeval_diff(&tmp->next->frame->ts, &start,
+ &tmp->next->attr->ts_rel);
+ timeval_diff(&tmp->next->frame->ts, &tmp->frame->ts,
+ &tmp->next->attr->ts_diff);
+ tmp = tmp->next;
+ }
+}
diff --git a/tools/replay/hciseq.h b/tools/replay/hciseq.h
index bf953cd..f9fe7c8 100644
--- a/tools/replay/hciseq.h
+++ b/tools/replay/hciseq.h
@@ -22,6 +22,25 @@
*
*/
+struct frame {
+ void *data;
+ uint32_t data_len;
+ void *ptr;
+ uint32_t len;
+ uint16_t dev_id;
+ uint8_t in;
+ uint8_t master;
+ uint16_t handle;
+ uint16_t cid;
+ uint16_t num;
+ uint8_t dlci;
+ uint8_t channel;
+ unsigned long flags;
+ struct timeval ts;
+ int pppdump_fd;
+ int audio_fd;
+};
+
enum hciseq_action {
HCISEQ_ACTION_REPLAY = 0,
};
@@ -33,6 +52,8 @@ struct hciseq_list {
};
struct hciseq_attr {
+ struct timeval ts_rel;
+ struct timeval ts_diff;
enum hciseq_action action;
};
@@ -41,3 +62,5 @@ struct hciseq_node {
struct hciseq_node *next;
struct hciseq_attr *attr;
};
+
+void calc_rel_ts(struct hciseq_list *seq);
diff --git a/tools/replay/main.c b/tools/replay/main.c
index 509d968..e026d98 100644
--- a/tools/replay/main.c
+++ b/tools/replay/main.c
@@ -37,8 +37,10 @@
#include <unistd.h>
#include <sys/epoll.h>
#include <sys/ioctl.h>
+#include <sys/time.h>
#include "main.h"
+#include "time.h"
#include "lib/bluetooth.h"
#include "lib/hci.h"
#include "monitor/bt.h"
@@ -49,16 +51,22 @@
#define MAX_EPOLL_EVENTS 1
#define MAX_MSG 128
+#define TIMING_NONE 0
+#define TIMING_DELTA 1
+
static struct hciseq_list dumpseq;
static int fd;
static int pos = 1;
static int skipped = 0;
+static struct timeval start;
static int epoll_fd;
static struct epoll_event epoll_event;
static int timeout = -1;
+static int timing = TIMING_NONE;
+static double factor = 1;
static bool verbose = false;
static inline int read_n(int fd, char *buf, int len)
@@ -313,6 +321,10 @@ static bool process_in()
if (n < 0) {
perror("Could not receive\n");
return false;
+ } else if (n == 0) {
+ printf("[%4d/%4d] Timeout\n", pos, dumpseq.len);
+ skipped++;
+ return true;
}
/* is this the packet in the sequence? */
@@ -353,9 +365,29 @@ static bool process_out()
static void process()
{
+ struct timeval last, last_diff;
+ __useconds_t delay;
bool processed;
+ gettimeofday(&last, NULL);
do {
+ /* delay */
+ if (timing == TIMING_DELTA) {
+ /* consider exec time of process_out()/process_in() */
+ get_timeval_passed(&last, &last_diff);
+ if (timeval_cmp(&dumpseq.current->attr->ts_diff, &last_diff) >= 0) {
+ delay = timeval_diff(&dumpseq.current->attr->ts_diff,
+ &last_diff, NULL);
+ delay *= factor;
+ if (usleep(delay) == -1)
+ printf("Delay failed\n");
+ } else {
+ /* exec time was longer than delay */
+ printf("Packet delay - processing previous packet took longer than recorded time difference\n");
+ }
+ gettimeofday(&last, NULL);
+ }
+
if (dumpseq.current->frame->in == 1)
processed = process_out();
else
@@ -417,12 +449,18 @@ static void usage(void)
printf("hcireplay - Bluetooth replayer\n"
"Usage:\thcireplay-client [options] file...\n"
"options:\n"
- "\t-v, --verbose Enable verbose output\n"
- "\t --version Give version information\n"
- "\t --help Give a short usage message\n");
+ "\t-d, --delay-mode={none|delta} Specify delay mode (default is none)\n"
+ "\t-m, --delay-modifier=N Set delay modifier to N (default is 1)\n"
+ "\t-t, --timeout=N Set timeout to N milliseconds when receiving packets from host\n"
+ "\t-v, --verbose Enable verbose output\n"
+ "\t --version Give version information\n"
+ "\t --help Give a short usage message\n");
}
static const struct option main_options[] = {
+ {"delay-mode", required_argument, NULL, 'd'},
+ {"delay-modifier", required_argument, NULL, 'm'},
+ {"timeout", required_argument, NULL, 't'},
{"verbose", no_argument, NULL, 'v'},
{"version", no_argument, NULL, 'V'},
{"help", no_argument, NULL, 'H'},
@@ -437,12 +475,25 @@ int main(int argc, char *argv[])
while (1) {
int opt;
- opt = getopt_long(argc, argv, "v",
+ opt = getopt_long(argc, argv, "d:m:t:v",
main_options, NULL);
if (opt < 0)
break;
switch (opt) {
+ case 'd':
+ if (!strcmp(optarg, "none"))
+ timing = TIMING_NONE;
+ else if (!strcmp(optarg, "delta"))
+ timing = TIMING_DELTA;
+
+ break;
+ case 'm':
+ factor = atof(optarg);
+ break;
+ case 't':
+ timeout = atoi(optarg);
+ break;
case 'v':
verbose = true;
break;
@@ -478,6 +529,9 @@ int main(int argc, char *argv[])
}
}
dumpseq.current = dumpseq.frames;
+ calc_rel_ts(&dumpseq);
+
+ gettimeofday(&start, NULL);
/*
* make sure we open the interface after parsing
diff --git a/tools/replay/main.h b/tools/replay/main.h
index d80deec..2223789 100644
--- a/tools/replay/main.h
+++ b/tools/replay/main.h
@@ -42,23 +42,4 @@ struct btsnoop_pkt {
} __attribute__ ((packed));
#define BTSNOOP_PKT_SIZE (sizeof(struct btsnoop_pkt))
-static uint8_t btsnoop_id[] = { 0x62, 0x74, 0x73, 0x6e, 0x6f, 0x6f, 0x70, 0x00 };
-
-struct frame {
- void *data;
- uint32_t data_len;
- void *ptr;
- uint32_t len;
- uint16_t dev_id;
- uint8_t in;
- uint8_t master;
- uint16_t handle;
- uint16_t cid;
- uint16_t num;
- uint8_t dlci;
- uint8_t channel;
- unsigned long flags;
- struct timeval ts;
- int pppdump_fd;
- int audio_fd;
-};
+uint8_t btsnoop_id[] = { 0x62, 0x74, 0x73, 0x6e, 0x6f, 0x6f, 0x70, 0x00 };
diff --git a/tools/replay/time.c b/tools/replay/time.c
new file mode 100644
index 0000000..029501a
--- /dev/null
+++ b/tools/replay/time.c
@@ -0,0 +1,91 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ * Copyright (C) 2012 Anton Weber <ant@antweb.me>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <stdlib.h>
+#include <sys/time.h>
+
+#include "time.h"
+
+/*
+ * Adjust timeval structs to make sure usec difference is not negative
+ * see http://www.gnu.org/software/libc/manual/html_node/Elapsed-Time.html
+ */
+void timeval_adjust_usec(struct timeval *l, struct timeval *r) {
+ int tmpsec;
+
+ if (r->tv_usec > l->tv_usec) {
+ tmpsec = (r->tv_usec - l->tv_usec) / 1000000 + 1;
+ r->tv_sec += tmpsec;
+ r->tv_usec -= 1000000 * tmpsec;
+ }
+
+ if ((l->tv_usec - r->tv_usec) > 1000000) {
+ tmpsec = (l->tv_usec - r->tv_usec) / 1000000;
+ r->tv_sec -= tmpsec;
+ r->tv_usec += 1000000 * tmpsec;
+ }
+}
+
+__useconds_t
+timeval_diff(struct timeval *l, struct timeval *r, struct timeval *diff)
+{
+ static struct timeval tmp;
+
+ timeval_adjust_usec(l, r);
+
+ /* use local variable if we only need return value */
+ if (diff == NULL)
+ diff = &tmp;
+
+ diff->tv_sec = l->tv_sec - r->tv_sec;
+ diff->tv_usec = l->tv_usec - r->tv_usec;
+
+ return (diff->tv_sec * 1000000) + diff->tv_usec;
+}
+
+int timeval_cmp(struct timeval *l, struct timeval *r)
+{
+ timeval_adjust_usec(l, r);
+
+ if (l->tv_sec > r->tv_sec) {
+ return 1;
+ } else if (l->tv_sec < r->tv_sec) {
+ return -1;
+ } else {
+ if (l->tv_usec > r->tv_usec)
+ return 1;
+ else if (l->tv_usec < r->tv_usec)
+ return -1;
+ else
+ return 0;
+ }
+}
+
+inline __useconds_t
+get_timeval_passed(struct timeval *since, struct timeval *diff)
+{
+ struct timeval now;
+
+ gettimeofday(&now, NULL);
+
+ return timeval_diff(&now, since, diff);
+}
diff --git a/tools/replay/time.h b/tools/replay/time.h
new file mode 100644
index 0000000..0c876a4
--- /dev/null
+++ b/tools/replay/time.h
@@ -0,0 +1,31 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ * Copyright (C) 2012 Anton Weber <ant@antweb.me>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+void timeval_adjust_usec(struct timeval *l, struct timeval *r);
+
+__useconds_t
+timeval_diff(struct timeval *l, struct timeval *r, struct timeval *diff);
+
+int timeval_cmp(struct timeval *l, struct timeval *r);
+
+inline __useconds_t
+ get_timeval_passed(struct timeval *since, struct timeval *diff);
--
1.7.9.5
^ permalink raw reply related
* [PATCH BlueZ v3 1/6] replay: Add initial version of replay tool
From: Anton Weber @ 2012-09-05 14:14 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Anton Weber
In-Reply-To: <1344533773-12914-1-git-send-email-ant@antweb.me>
This utility uses a VHCI interface to simulate HCI traffic from
a recorded scenario. It reads packets from BTSnoop dump files and
replays them on the virtual interface.
It is meant as a debugging tool that allows to investigate problems
with particular controllers and Bluetooth hardware on other system
configurations.
---
.gitignore | 1 +
Makefile.tools | 12 +-
tools/replay/hciseq.h | 43 +++++
tools/replay/main.c | 501 +++++++++++++++++++++++++++++++++++++++++++++++++
tools/replay/main.h | 64 +++++++
5 files changed, 620 insertions(+), 1 deletion(-)
create mode 100644 tools/replay/hciseq.h
create mode 100644 tools/replay/main.c
create mode 100644 tools/replay/main.h
diff --git a/.gitignore b/.gitignore
index 38318cd..d53e266 100644
--- a/.gitignore
+++ b/.gitignore
@@ -87,6 +87,7 @@ unit/test-eir
tools/btmgmt
monitor/btmon
emulator/btvirt
+tools/replay/btreplay
doc/*.bak
doc/*.stamp
diff --git a/Makefile.tools b/Makefile.tools
index 5579b86..4a3aca5 100644
--- a/Makefile.tools
+++ b/Makefile.tools
@@ -50,7 +50,7 @@ tools_ppporc_LDADD = lib/libbluetooth-private.la
tools_hcieventmask_LDADD = lib/libbluetooth-private.la
-noinst_PROGRAMS += tools/btmgmt monitor/btmon emulator/btvirt
+noinst_PROGRAMS += tools/btmgmt monitor/btmon emulator/btvirt tools/replay/btreplay
tools_btmgmt_SOURCES = tools/btmgmt.c src/glib-helper.c
tools_btmgmt_LDADD = lib/libbluetooth-private.la @GLIB_LIBS@
@@ -69,6 +69,16 @@ emulator_btvirt_SOURCES = emulator/main.c monitor/bt.h \
emulator/vhci.h emulator/vhci.c \
emulator/btdev.h emulator/btdev.c
+tools_replay_btreplay_SOURCES = tools/replay/main.h tools/replay/main.c \
+ tools/replay/hciseq.h \
+ monitor/packet.h monitor/packet.c \
+ monitor/btsnoop.h monitor/btsnoop.c \
+ monitor/control.h monitor/control.c \
+ monitor/mainloop.h monitor/mainloop.c \
+ lib/hci.h
+
+tools_replay_btreplay_LDADD = lib/libbluetooth-private.la
+
if READLINE
bin_PROGRAMS += attrib/gatttool
diff --git a/tools/replay/hciseq.h b/tools/replay/hciseq.h
new file mode 100644
index 0000000..bf953cd
--- /dev/null
+++ b/tools/replay/hciseq.h
@@ -0,0 +1,43 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ * Copyright (C) 2012 Anton Weber <ant@antweb.me>
+ * Copyright (C) 2011-2012 Intel Corporation
+ * Copyright (C) 2004-2010 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+enum hciseq_action {
+ HCISEQ_ACTION_REPLAY = 0,
+};
+
+struct hciseq_list {
+ struct hciseq_node *frames;
+ struct hciseq_node *current;
+ int len;
+};
+
+struct hciseq_attr {
+ enum hciseq_action action;
+};
+
+struct hciseq_node {
+ struct frame *frame;
+ struct hciseq_node *next;
+ struct hciseq_attr *attr;
+};
diff --git a/tools/replay/main.c b/tools/replay/main.c
new file mode 100644
index 0000000..509d968
--- /dev/null
+++ b/tools/replay/main.c
@@ -0,0 +1,501 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ * Copyright (C) 2012 Anton Weber <ant@antweb.me>
+ * Copyright (C) 2011-2012 Intel Corporation
+ * Copyright (C) 2000-2002 Maxim Krasnyansky <maxk@qualcomm.com>
+ * Copyright (C) 2003-2011 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/epoll.h>
+#include <sys/ioctl.h>
+
+#include "main.h"
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "monitor/bt.h"
+#include "monitor/btsnoop.h"
+#include "monitor/control.h"
+#include "monitor/packet.h"
+
+#define MAX_EPOLL_EVENTS 1
+#define MAX_MSG 128
+
+static struct hciseq_list dumpseq;
+
+static int fd;
+static int pos = 1;
+static int skipped = 0;
+
+static int epoll_fd;
+static struct epoll_event epoll_event;
+
+static int timeout = -1;
+static bool verbose = false;
+
+static inline int read_n(int fd, char *buf, int len)
+{
+ int t = 0, w;
+
+ while (len > 0) {
+ w = read(fd, buf, len);
+ if (w < 0) {
+ if (errno == EINTR || errno == EAGAIN)
+ continue;
+ return -1;
+ } else if (w == 0) {
+ return 0;
+ }
+
+ len -= w;
+ buf += w;
+ t += w;
+ }
+
+ return t;
+}
+
+static int
+parse_btsnoop(int fd, struct frame *frm, struct btsnoop_hdr *hdr)
+{
+ struct btsnoop_pkt pkt;
+ uint8_t pkt_type;
+ uint64_t ts;
+ int n;
+
+ n = read_n(fd, (void *) &pkt, BTSNOOP_PKT_SIZE);
+ if (n < 0)
+ return -1;
+ else if (n == 0)
+ return 0;
+
+ switch (ntohl(hdr->type)) {
+ case 1001:
+ if (ntohl(pkt.flags) & 0x02) {
+ if (ntohl(pkt.flags) & 0x01)
+ pkt_type = HCI_EVENT_PKT;
+ else
+ pkt_type = HCI_COMMAND_PKT;
+ } else
+ pkt_type = HCI_ACLDATA_PKT;
+
+ ((uint8_t *) frm->data)[0] = pkt_type;
+
+ frm->data_len = ntohl(pkt.len) + 1;
+ n = read_n(fd, frm->data + 1, frm->data_len - 1);
+ break;
+
+ case 1002:
+ frm->data_len = ntohl(pkt.len);
+ n = read_n(fd, frm->data, frm->data_len);
+ break;
+ }
+
+ frm->in = ntohl(pkt.flags) & 0x01;
+ ts = ntoh64(pkt.ts) - 0x00E03AB44A676000ll;
+ frm->ts.tv_sec = (ts / 1000000ll) + 946684800ll;
+ frm->ts.tv_usec = ts % 1000000ll;
+
+ return n;
+}
+
+static int parse_dump(int fd, struct hciseq_list *seq)
+{
+ struct frame *frm;
+ struct btsnoop_hdr bh;
+ int n, count;
+ struct hciseq_node *nodeptr, *last;
+
+ last = seq->current;
+
+ /* read BTSnoop header once */
+ if (read_n(fd, (void *) &bh, BTSNOOP_HDR_SIZE) != BTSNOOP_HDR_SIZE)
+ return -1;
+
+ /* check for "btsnoop" string in header */
+ if (memcmp(bh.id, btsnoop_id, sizeof(btsnoop_id)) != 0)
+ return -1;
+
+ count = seq->len;
+ while (1) {
+ frm = malloc(sizeof(*frm));
+ frm->data = malloc(HCI_MAX_FRAME_SIZE);
+
+ n = parse_btsnoop(fd, frm, &bh);
+ if (n <= 0) {
+ free(frm->data);
+ free(frm);
+ return n;
+ }
+
+ frm->ptr = frm->data;
+ frm->len = frm->data_len;
+
+ nodeptr = malloc(sizeof(*nodeptr));
+ nodeptr->frame = frm;
+ nodeptr->attr = malloc(sizeof(*nodeptr->attr));
+ nodeptr->attr->action = HCISEQ_ACTION_REPLAY;
+
+ if (last == NULL)
+ seq->frames = nodeptr;
+ else
+ last->next = nodeptr;
+
+ last = nodeptr;
+ nodeptr->next = NULL;
+ seq->len = ++count;
+ }
+
+ return 0;
+}
+
+static void dump_frame(struct frame *frm)
+{
+ struct timeval tv;
+ uint8_t pkt_type;
+
+ gettimeofday(&tv, NULL);
+
+ pkt_type = ((const uint8_t *) frm->data)[0];
+ switch (pkt_type) {
+ case BT_H4_CMD_PKT:
+ packet_hci_command(&tv, 0x00, frm->data + 1,
+ frm->data_len - 1);
+ break;
+ case BT_H4_EVT_PKT:
+ packet_hci_event(&tv, 0x00, frm->data + 1,
+ frm->data_len - 1);
+ break;
+ case BT_H4_ACL_PKT:
+ if (frm->in)
+ packet_hci_acldata(&tv, 0x00, 0x01,
+ frm->data + 1,
+ frm->data_len - 1);
+ else
+ packet_hci_acldata(&tv, 0x00, 0x00,
+ frm->data + 1,
+ frm->data_len - 1);
+ break;
+ default:
+ //TODO: raw dump
+ break;
+ }
+}
+
+static int send_frm(struct frame *frm)
+{
+ return write(fd, frm->data, frm->data_len);
+}
+
+static int recv_frm(int fd, struct frame *frm)
+{
+ int i, n;
+ int nevs;
+ uint8_t buf[HCI_MAX_FRAME_SIZE];
+ struct epoll_event ev[MAX_EPOLL_EVENTS];
+
+ nevs = epoll_wait(epoll_fd, ev, MAX_EPOLL_EVENTS, timeout);
+ if (nevs < 0)
+ return -1;
+ else if (nevs == 0)
+ return 0;
+
+ for (i = 0; i < nevs; i++) {
+ if (ev[i].events & (EPOLLERR | EPOLLHUP))
+ return -1;
+
+ n = read(fd, (void *) &buf, HCI_MAX_FRAME_SIZE);
+ if (n > 0) {
+ memcpy(frm->data, buf, n);
+ frm->data_len = n;
+ }
+ }
+
+ return n;
+}
+
+static bool check_match(struct frame *l, struct frame *r, char *msg)
+{
+ uint8_t type_l = ((const uint8_t *) l->data)[0];
+ uint8_t type_r = ((const uint8_t *) r->data)[0];
+ uint16_t opcode_l, opcode_r;
+ uint8_t evt_l, evt_r;
+
+ if (type_l != type_r) {
+ snprintf(msg, MAX_MSG,
+ "! Wrong packet type - expected (0x%2.2x), was (0x%2.2x)",
+ type_l, type_r);
+ return false;
+ }
+
+ switch (type_l) {
+ case BT_H4_CMD_PKT:
+ opcode_l = *((uint16_t *) (l->data + 1));
+ opcode_r = *((uint16_t *) (r->data + 1));
+ if (opcode_l != opcode_r) {
+ snprintf(msg, MAX_MSG,
+ "! Wrong opcode - expected (0x%2.2x|0x%4.4x), was (0x%2.2x|0x%4.4x)",
+ cmd_opcode_ogf(opcode_l),
+ cmd_opcode_ocf(opcode_l),
+ cmd_opcode_ogf(opcode_r),
+ cmd_opcode_ocf(opcode_r));
+ return false;
+ } else {
+ return true;
+ }
+ case BT_H4_EVT_PKT:
+ evt_l = *((uint8_t *) (l->data + 1));
+ evt_r = *((uint8_t *) (r->data + 1));
+ if (evt_l != evt_r) {
+ snprintf(msg, MAX_MSG,
+ "! Wrong event type - expected (0x%2.2x), was (0x%2.2x)",
+ evt_l, evt_r);
+ return false;
+ } else {
+ return true;
+ }
+ case BT_H4_ACL_PKT:
+ if (l->data_len != r->data_len)
+ return false;
+
+ return memcmp(l->data, r->data, l->data_len) == 0;
+ default:
+ snprintf(msg, MAX_MSG, "! Unknown packet type (0x%2.2x)",
+ type_l);
+
+ if (l->data_len != r->data_len)
+ return false;
+
+ return memcmp(l->data, r->data, l->data_len) == 0;
+ }
+}
+
+static bool process_in()
+{
+ static struct frame frm;
+ static uint8_t data[HCI_MAX_FRAME_SIZE];
+ int n;
+ bool match;
+ char msg[MAX_MSG];
+
+ frm.data = &data;
+ frm.ptr = frm.data;
+
+ n = recv_frm(fd, &frm);
+ if (n < 0) {
+ perror("Could not receive\n");
+ return false;
+ }
+
+ /* is this the packet in the sequence? */
+ msg[0] = '\0';
+ match = check_match(dumpseq.current->frame, &frm, msg);
+
+ /* process packet if match */
+ if (match)
+ printf("[%4d/%4d] ", pos, dumpseq.len);
+ else
+ printf("[ Unknown ] %s\n ", msg);
+
+ dump_frame(&frm);
+
+ return match;
+}
+
+static bool process_out()
+{
+ uint8_t pkt_type;
+
+ pkt_type = ((const uint8_t *) dumpseq.current->frame->data)[0];
+
+ switch (pkt_type) {
+ case BT_H4_EVT_PKT:
+ case BT_H4_ACL_PKT:
+ printf("[%4d/%4d] ", pos, dumpseq.len);
+ dump_frame(dumpseq.current->frame);
+ send_frm(dumpseq.current->frame);
+ break;
+ default:
+ printf("Unsupported packet 0x%2.2x\n", pkt_type);
+ break;
+ }
+
+ return true;
+}
+
+static void process()
+{
+ bool processed;
+
+ do {
+ if (dumpseq.current->frame->in == 1)
+ processed = process_out();
+ else
+ processed = process_in();
+
+ if (processed) {
+ dumpseq.current = dumpseq.current->next;
+ pos++;
+ }
+ } while (dumpseq.current != NULL);
+
+ printf("Done\n");
+ printf("Processed %d out of %d\n", dumpseq.len - skipped,
+ dumpseq.len);
+}
+
+static int vhci_open()
+{
+ fd = open("/dev/vhci", O_RDWR | O_NONBLOCK);
+ epoll_fd = epoll_create1(EPOLL_CLOEXEC);
+ if (epoll_fd < 0)
+ return -1;
+
+ epoll_event.events = EPOLLIN;
+ epoll_event.data.fd = fd;
+
+ if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD,
+ epoll_event.data.fd, &epoll_event) < 0) {
+ return -1;
+ }
+
+ return fd;
+}
+
+static int vhci_close()
+{
+ epoll_ctl(epoll_fd, EPOLL_CTL_DEL, epoll_event.data.fd, NULL);
+ return close(fd);
+}
+
+static void delete_list()
+{
+ struct hciseq_node *node, *tmp;
+
+ node = dumpseq.frames;
+ while (node != NULL) {
+ tmp = node;
+ node = node->next;
+
+ free(tmp->frame->data);
+ free(tmp->frame);
+ free(tmp->attr);
+ free(tmp);
+ }
+}
+
+static void usage(void)
+{
+ printf("hcireplay - Bluetooth replayer\n"
+ "Usage:\thcireplay-client [options] file...\n"
+ "options:\n"
+ "\t-v, --verbose Enable verbose output\n"
+ "\t --version Give version information\n"
+ "\t --help Give a short usage message\n");
+}
+
+static const struct option main_options[] = {
+ {"verbose", no_argument, NULL, 'v'},
+ {"version", no_argument, NULL, 'V'},
+ {"help", no_argument, NULL, 'H'},
+ {}
+};
+
+int main(int argc, char *argv[])
+{
+ int dumpfd;
+ int i;
+
+ while (1) {
+ int opt;
+
+ opt = getopt_long(argc, argv, "v",
+ main_options, NULL);
+ if (opt < 0)
+ break;
+
+ switch (opt) {
+ case 'v':
+ verbose = true;
+ break;
+ case 'V':
+ printf("%s\n", VERSION);
+ return EXIT_SUCCESS;
+ case 'H':
+ usage();
+ return EXIT_SUCCESS;
+ default:
+ return EXIT_FAILURE;
+ }
+ }
+
+ if (optind >= argc) {
+ usage();
+ return EXIT_FAILURE;
+ }
+
+ dumpseq.current = NULL;
+ dumpseq.frames = NULL;
+ for (i = optind; i < argc; i++) {
+ dumpfd = open(argv[i], O_RDONLY);
+ if (dumpfd < 0) {
+ perror("Failed to open dump file");
+ return EXIT_FAILURE;
+ }
+
+ if (parse_dump(dumpfd, &dumpseq) < 0) {
+ fprintf(stderr, "Error parsing dump file\n");
+ vhci_close();
+ return EXIT_FAILURE;
+ }
+ }
+ dumpseq.current = dumpseq.frames;
+
+ /*
+ * make sure we open the interface after parsing
+ * through all files so we can start without delay
+ */
+ fd = vhci_open();
+ if (fd < 0) {
+ perror("Failed to open VHCI interface");
+ return EXIT_FAILURE;
+ }
+
+ printf("Running\n");
+
+ process();
+
+ vhci_close();
+ delete_list();
+ printf("Terminating\n");
+
+ return EXIT_SUCCESS;
+}
diff --git a/tools/replay/main.h b/tools/replay/main.h
new file mode 100644
index 0000000..d80deec
--- /dev/null
+++ b/tools/replay/main.h
@@ -0,0 +1,64 @@
+/*
+ *
+ * BlueZ - Bluetooth protocol stack for Linux
+ * Copyright (C) 2012 Anton Weber <ant@antweb.me>
+ * Copyright (C) 2011-2012 Intel Corporation
+ * Copyright (C) 2000-2002 Maxim Krasnyansky <maxk@qualcomm.com>
+ * Copyright (C) 2003-2011 Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include "hciseq.h"
+
+struct btsnoop_hdr {
+ uint8_t id[8]; /* Identification Pattern */
+ uint32_t version; /* Version Number = 1 */
+ uint32_t type; /* Datalink Type */
+} __attribute__ ((packed));
+#define BTSNOOP_HDR_SIZE (sizeof(struct btsnoop_hdr))
+
+struct btsnoop_pkt {
+ uint32_t size; /* Original Length */
+ uint32_t len; /* Included Length */
+ uint32_t flags; /* Packet Flags */
+ uint32_t drops; /* Cumulative Drops */
+ uint64_t ts; /* Timestamp microseconds */
+ uint8_t data[0]; /* Packet Data */
+} __attribute__ ((packed));
+#define BTSNOOP_PKT_SIZE (sizeof(struct btsnoop_pkt))
+
+static uint8_t btsnoop_id[] = { 0x62, 0x74, 0x73, 0x6e, 0x6f, 0x6f, 0x70, 0x00 };
+
+struct frame {
+ void *data;
+ uint32_t data_len;
+ void *ptr;
+ uint32_t len;
+ uint16_t dev_id;
+ uint8_t in;
+ uint8_t master;
+ uint16_t handle;
+ uint16_t cid;
+ uint16_t num;
+ uint8_t dlci;
+ uint8_t channel;
+ unsigned long flags;
+ struct timeval ts;
+ int pppdump_fd;
+ int audio_fd;
+};
--
1.7.9.5
^ permalink raw reply related
* Re: [PATCH v2 09/17] heartrate: Enable measurement when watchers are registered
From: Vinicius Costa Gomes @ 2012-09-05 13:49 UTC (permalink / raw)
To: Andrzej Kaczmarek; +Cc: linux-bluetooth
In-Reply-To: <1346850348-21176-10-git-send-email-andrzej.kaczmarek@tieto.com>
Hi,
On 15:05 Wed 05 Sep, Andrzej Kaczmarek wrote:
> 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..5464a9f 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)
Nitpick: I think it is possible to break the line after the first parameter.
> +{
> + GSList *l;
> +
> + l = g_slist_find_custom(hr->chars, uuid, cmp_char_uuid);
> + if (l == NULL)
> + return NULL;
> +
> + return l->data;
> +}
> +
Cheers,
--
Vinicius
^ permalink raw reply
* Re: [PATCH v2 01/17] Heart Rate Profile API
From: Vinicius Costa Gomes @ 2012-09-05 13:47 UTC (permalink / raw)
To: Andrzej Kaczmarek; +Cc: linux-bluetooth, Santiago Carot-Nemesio
In-Reply-To: <1346850348-21176-2-git-send-email-andrzej.kaczmarek@tieto.com>
Hi,
On 15:05 Wed 05 Sep, Andrzej Kaczmarek wrote:
> From: Santiago Carot-Nemesio <sancane@gmail.com>
>
> ---
> doc/heartrate-api.txt | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 83 insertions(+)
> create mode 100644 doc/heartrate-api.txt
>
> diff --git a/doc/heartrate-api.txt b/doc/heartrate-api.txt
> new file mode 100644
> index 0000000..3afea78
> --- /dev/null
> +++ b/doc/heartrate-api.txt
> @@ -0,0 +1,83 @@
> + Heart Rate API description
> +****************************************
> +
> +Copyright (C) 2012 Santiago Carot-Nemesio <sancane@gmail.com>
> +Copyright (C) 2012 Tieto Poland
> +
> +Heart Rate Manager hierarchy
> +============================
> +
> +Service org.bluez
> +Interface org.bluez.HeartRateManager
> +Object path [variable prefix]/{hci0,hci1,...}
> +
> +Methods RegisterWatcher(object agent)
> +
> + Registers a watcher to monitor heart rate measurements.
> +
> + Possible Errors: org.bluez.Error.InvalidArguments
> +
> + UnregisterWatcher(object agent)
> +
> + Unregisters a watcher.
> +
> +Heart Rate Profile hierarchy
> +============================
> +
> +Service org.bluez
> +Interface org.bluez.HeartRate
> +Object path [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX
> +
> +Methods dict GetProperties()
> +
> + Returns all properties for the interface. See the
> + Properties section for the available properties.
> +
> + Reset()
> +
> + Restart the accumulation of energy expended from zero.
> +
> + Possible Errors: org.bluez.Error.NotSupported
> +
> +Properties String Location (optional) [readonly]
> +
> + Possible values: "Other", "Chest", "Wrist","Finger",
> + "Hand", "Earlobe", "Foot"
> +
> + boolean ResetSupported [readonly]
> +
> + True if energy expended is supported.
> +
> +Heart Rate Watcher hierarchy
> +
> +============================
> +Service unique name
> +Interface org.bluez.HeartRateWatcher
> +Object path freely definable
> +
> +Methods void MeasurementReceived(object device, dict measure)
> +
> + This callback is called whenever a heart rate
> + measurement is received from the heart rate device.
> + The unit for the Value is expressed in beats per
> + minute (bpm). The energy field is optional and
> + represents the accumulated energy expended in
> + kilo Joules since last time it was reset. Furthermore,
> + the device will be automatically reset when it
> + is needed.
> + The Contact field, if present, indicates
> + that the device supports contact sensor, besides it
> + will be true if skin contact is detected. The optional
> + interval field is an array containing RR-Interval
> + values which represent the time between two R-Wave
> + detections, where the RR-Interval value 0 is older
> + than the value 1 and so on.
The description of the possible fields could be similar to what's done
above and what media-api.txt is doing.
> +
> + Dict is defined as below:
> + {
> + "Value" : uint16,
> + "Energy" : uint16,
> + "Contact" : boolean,
> + "Interval" : array{uint16}
> + }
> +
> --
> 1.7.11.3
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
Cheers,
--
Vinicius
^ permalink raw reply
* [PATCH v2 17/17] heartrate: Add test script
From: Andrzej Kaczmarek @ 2012-09-05 13:05 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Rafal Garbat
In-Reply-To: <1346850348-21176-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 v2 16/17] heartrate: Add HeartRateWatcher interface to default policy
From: Andrzej Kaczmarek @ 2012-09-05 13:05 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Rafal Garbat
In-Reply-To: <1346850348-21176-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 v2 15/17] heartrate: Add GetProperties method
From: Andrzej Kaczmarek @ 2012-09-05 13:05 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Rafal Garbat
In-Reply-To: <1346850348-21176-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 f2ae2a4..5605fdd 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 v2 14/17] heartrate: Add Reset method
From: Andrzej Kaczmarek @ 2012-09-05 13:05 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Andrzej Kaczmarek
In-Reply-To: <1346850348-21176-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 8a84e89..f2ae2a4 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 v2 13/17] heartrate: Process Heart Rate Measurement characteristics
From: Andrzej Kaczmarek @ 2012-09-05 13:05 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Andrzej Kaczmarek
In-Reply-To: <1346850348-21176-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 cf5514f..8a84e89 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 v2 12/17] heartrate: Handle characteristics value changed notification
From: Andrzej Kaczmarek @ 2012-09-05 13:05 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Andrzej Kaczmarek
In-Reply-To: <1346850348-21176-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 03f0383..cf5514f 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 v2 11/17] heartrate: Read Heart Rate Control Point characteristics
From: Andrzej Kaczmarek @ 2012-09-05 13:05 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Andrzej Kaczmarek
In-Reply-To: <1346850348-21176-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 b73b357..03f0383 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 v2 10/17] heartrate: Read Body Sensor Location characteristics
From: Andrzej Kaczmarek @ 2012-09-05 13:05 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Rafal Garbat
In-Reply-To: <1346850348-21176-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 5464a9f..b73b357 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
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