Linux bluetooth development
 help / color / mirror / Atom feed
* [PATCH BlueZ 3/4] replay: Add emulation support
From: Anton Weber @ 2012-08-09 17:36 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Anton Weber
In-Reply-To: <1344533773-12914-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 49ea21d..f108b25 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 2/4] replay: Add timing functionality
From: Anton Weber @ 2012-08-09 17:36 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Anton Weber
In-Reply-To: <1344533773-12914-1-git-send-email-ant@antweb.me>

Add -d parameter that lets user choose between two timing 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 timing mode.

Add -t parameter to set the epoll timeout when receiving packets.
---
 Makefile.tools        |    3 +-
 tools/replay/hciseq.c |   53 ++++++++++++++++++++++++++++
 tools/replay/hciseq.h |   23 +++++++++++++
 tools/replay/main.c   |   56 +++++++++++++++++++++++++++++-
 tools/replay/main.h   |   21 +-----------
 tools/replay/time.c   |   91 +++++++++++++++++++++++++++++++++++++++++++++++++
 tools/replay/time.h   |   31 +++++++++++++++++
 7 files changed, 256 insertions(+), 22 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 8019151..49ea21d 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-d, --timing={none|delta}    Specify timing mode\n"
+	       "\t-m, --factor=<value>         Use timing modifier\n"
+	       "\t-t, --timeout=<value>        Use timeout when receiving\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[] = {
+	{"timing", required_argument, NULL, 'd'},
+	{"factor", 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 1/4] replay: Add initial version of replay tool
From: Anton Weber @ 2012-08-09 17:36 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Anton Weber

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..8019151
--- /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)))
+		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

* [PATCH BlueZ 0/4] replay: Add initial version of replay tool
From: Anton Weber @ 2012-08-09 17:35 UTC (permalink / raw)
  To: linux-bluetooth

The Bluetooth Replayer is a debugging tool that I created for my
Google Summer of Code project.
It reads dump files in BTSnoop format and replays them on a VHCI interface.

The idea is to emulate scenarios to track down bugs, especially if
they only occur with a specific system setup.
That way the problem can be recorded by the user and debugged by a
developer on his machine.

It supports several ways to configure the replay process, such as
timing controls, emulator integration and different actions.
More detailed documentation will follow shortly.

One of the current limitations is that the replay can hang for several
reasons (packets coming in in the wrong order or with wrong timing).
At the moment the only workaround is to create a config file and tweak
the sequence by hand.

I couldn't implement all of my ideas within the GSoC time frame, such
as a flexible processing order of packets in the sequence or a more
powerful config parser.
For now I will focus on documentation and bug fixes / improvements
based on feedback.

The tool is broken down into several patches, each adding more
features and complexity.
Feedback, comments or any other remarks are very welcome!

Regards,
Anton

^ permalink raw reply

* [PATCH obexd] client: Fix pbap_select using absolute path with known locations
From: Ludek Finstrle @ 2012-08-09 16:07 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Ludek Finstrle

pbap_select has to use absolute path with known location to support
repeatable pbap_select calls. In other way the second call fails.
---
 client/pbap.c |    4 ++--
 1 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/client/pbap.c b/client/pbap.c
index 48dbac1..d8c39e5 100644
--- a/client/pbap.c
+++ b/client/pbap.c
@@ -232,14 +232,14 @@ static gchar *build_phonebook_path(const char *location, const char *item)
 
 	if (!g_ascii_strcasecmp(location, "INT") ||
 			!g_ascii_strcasecmp(location, "INTERNAL"))
-		path = g_strdup("telecom");
+		path = g_strdup("/telecom");
 	else if (!g_ascii_strncasecmp(location, "SIM", 3)) {
 		if (strlen(location) == 3)
 			tmp = g_strdup("SIM1");
 		else
 			tmp = g_ascii_strup(location, 4);
 
-		path = g_build_filename(tmp, "telecom", NULL);
+		path = g_build_filename("/", tmp, "telecom", NULL);
 		g_free(tmp);
 	} else
 		return NULL;
-- 
1.7.1


^ permalink raw reply related

* Re: [RFC v4 3/3] Bluetooth: mgmt: Add device disconnect reason
From: Marcel Holtmann @ 2012-08-09 15:54 UTC (permalink / raw)
  To: Mikel Astiz; +Cc: linux-bluetooth, Mikel Astiz
In-Reply-To: <1344498750-2698-4-git-send-email-mikel.astiz.oss@gmail.com>

Hi Mikel,

> MGMT_EV_DEVICE_DISCONNECTED will now expose the disconnection reason to
> userland, distinguishing four possible values:
> 
> 	0x00	Reason not known or unspecified
> 	0x01	Connection timeout
> 	0x02	Connection terminated by local host
> 	0x03	Connection terminated by remote host
> 
> Note that the local/remote distinction just determines which side
> terminated the low-level connection, regardless of the disconnection of
> the higher-level profiles.
> 
> This can sometimes be misleading and thus must be used with care. For
> example, some hardware combinations would report a locally initiated
> disconnection even if the user turned Bluetooth off in the remote side.
> 
> Signed-off-by: Mikel Astiz <mikel.astiz@bmw-carit.de>
> ---
>  include/net/bluetooth/hci_core.h |    2 +-
>  include/net/bluetooth/mgmt.h     |    9 +++++++++
>  net/bluetooth/hci_event.c        |   26 +++++++++++++++++++++++---
>  net/bluetooth/mgmt.c             |    9 +++++----
>  4 files changed, 38 insertions(+), 8 deletions(-)

Acked-by: Marcel Holtmann <marcel@holtmann.org>

Regards

Marcel



^ permalink raw reply

* Re: [RFC v4 2/3] Bluetooth: Fix minor coding style in hci_event.c
From: Marcel Holtmann @ 2012-08-09 15:50 UTC (permalink / raw)
  To: Mikel Astiz; +Cc: linux-bluetooth, Mikel Astiz
In-Reply-To: <1344498750-2698-3-git-send-email-mikel.astiz.oss@gmail.com>

Hi Mikel,

> Replace the status checks with the short form of the boolean expression.
> 
> Signed-off-by: Mikel Astiz <mikel.astiz@bmw-carit.de>
> ---
>  net/bluetooth/hci_event.c |    8 ++++----
>  1 files changed, 4 insertions(+), 4 deletions(-)

Acked-by: Marcel Holtmann <marcel@holtmann.org>

Regards

Marcel



^ permalink raw reply

* [RFC] Bluetooth: btusb: Set reset quirk for A-Link and Medialink devices
From: Andrei Emeltchenko @ 2012-08-09 15:03 UTC (permalink / raw)
  To: linux-bluetooth

From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>

Broadcom devices A-LINK (0a5c:2148) and Medialink (0a5c:2198) works more stable
when setting HCI_QUIRK_RESET_ON_CLOSE. Without this patch they do not always
come up after reset and down.
---
 drivers/bluetooth/btusb.c |    8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index f637c25..57ca6fd 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -47,6 +47,7 @@ static struct usb_driver btusb_driver;
 #define BTUSB_BROKEN_ISOC	0x20
 #define BTUSB_WRONG_SCO_MTU	0x40
 #define BTUSB_ATH3012		0x80
+#define BTUSB_BCM_RESET_QUIRK	0x100
 
 static struct usb_device_id btusb_table[] = {
 	/* Generic Bluetooth USB device */
@@ -149,6 +150,10 @@ static struct usb_device_id blacklist_table[] = {
 	{ USB_DEVICE(0x0a5c, 0x2039), .driver_info = BTUSB_WRONG_SCO_MTU },
 	{ USB_DEVICE(0x0a5c, 0x2101), .driver_info = BTUSB_WRONG_SCO_MTU },
 
+	/* Broadcom chips works better with reset quirk */
+	{ USB_DEVICE(0x0a5c, 0x2148), .driver_info = BTUSB_BCM_RESET_QUIRK },
+	{ USB_DEVICE(0x0a5c, 0x2198), .driver_info = BTUSB_BCM_RESET_QUIRK },
+
 	/* IBM/Lenovo ThinkPad with Broadcom chip */
 	{ USB_DEVICE(0x0a5c, 0x201e), .driver_info = BTUSB_WRONG_SCO_MTU },
 	{ USB_DEVICE(0x0a5c, 0x2110), .driver_info = BTUSB_WRONG_SCO_MTU },
@@ -1023,6 +1028,9 @@ static int btusb_probe(struct usb_interface *intf,
 			set_bit(HCI_QUIRK_FIXUP_BUFFER_SIZE, &hdev->quirks);
 	}
 
+	if (id->driver_info & BTUSB_BCM_RESET_QUIRK)
+		set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks);
+
 	if (id->driver_info & BTUSB_BROKEN_ISOC)
 		data->isoc = NULL;
 
-- 
1.7.9.5


^ permalink raw reply related

* Re: RFCOMM disconnection problem
From: Andrei Emeltchenko @ 2012-08-09 14:46 UTC (permalink / raw)
  To: Dean Jenkins; +Cc: Frederic Danis, linux-bluetooth@vger.kernel.org
In-Reply-To: <CAJ2qBzaLyPiwEcd2n5Kdu_Y4KMpYjvjGo+Ddk3RC1Cf6_k=K9A@mail.gmail.com>

Hi Dean,

On Thu, Aug 09, 2012 at 03:29:18PM +0100, Dean Jenkins wrote:
> One obvious failure of the rfcomm session refcnt is that the refcnt
> counter either starts with a value of 0 or 1 depending on which peer
> initiated the connection request, that is wrong. The initiator
> direction is not relevant for the session as connect and disconnect
> are independent events. The refcnt should start with a value of 1 in
> all cases.
> 
> I am using a 2-core ARM environment that is under high processor
> loading. The rfcomm session refcnt caused kernel crashes. I used a
> 2.6.34 kernel but the latest 3.5-RC1 still has the poor rfcomm code.
> My solution was to remove the rfcomm session refcnt and to ensure that
> the freeing of the rfcomm session pointer was propagated through-out
> the rfcomm core code. Some kernel crashes were due to reuse of the
> freed rfcomm session pointer.

Maybe it does make sense to fix refcounting instead of removing?

Best regards 
Andrei Emeltchenko 

> 
> I intend to release a patchset of rfcomm fixes.
> 
> Therefore, IMHO the fix "Bluetooth: Fix RFCOMM session reference
> counting issue" (commit cf33e7 in linux-stable.git) from Octavian
> Purdila in kernel 3.4.6 is in fact not fixing the root cause and
> introduces a misbehaviour of the refcnt. In our project, we rejected
> this commit because disconnections failed.
> 


^ permalink raw reply

* Re: [PATCH v17 01/15] doc: Add telephony interface documents
From: Luiz Augusto von Dentz @ 2012-08-09 14:42 UTC (permalink / raw)
  To: Frederic Danis; +Cc: Marcel Holtmann, linux-bluetooth
In-Reply-To: <50238B05.4030203@linux.intel.com>

Hi Frederic,

On Thu, Aug 9, 2012 at 1:03 PM, Frederic Danis
<frederic.danis@linux.intel.com> wrote:
>> They are mostly independent, oFono will never really acquire or
>> anything like that, but there are some AT commands (+VGS,+VGM) that
>> does notify PA about volume gain changes and as I said above it could
>> be useful to notify about wideband speech in the same way.
>>
>
> It is also possible that telephony agent implements a TelephonyClient
> interface for each connection, object which should be returned by
> NewConnection method.

You should return the properties as well to avoid another round trip
to get the properties of the client. Btw this requires yet another
object and interface that increases the complexity of the solution.

> In this case BlueZ will listen to properties changes on this interface (like
> for remote volume change) or call SetProperty (when receiving volume change
> from PulseAudio).
>
> As MediaTransport may change during wideband speech HFP session, due to
> codec re-negotiation, this architecture may simplify media transport code.

I don't think we need to do the codec negotiation on acquire, it
actually doesn't work since the transport cannot be reconfigured with
another codec as by design the endpoints can only have 1 codec, so I
suggest having the list of available codecs be given upfront in
NewConnection then you actually negotiate the codec before responding.
If the remote device attempts to change the codec oFono then can check
if the codec is available in the list of available codecs given on
NewConnection, if it find a match then it accepts and emit a signal of
codec changes that triggers a new transport to be configured.

Btw, Im not sure if this is really productive to discuss before we
even have this working with 1.5, IMO is easier to do things step by
step and the first step should be to get HFP 1.5 working as the
current upstream does then we think about 1.6 and other profiles such
as DUN and SAP.

-- 
Luiz Augusto von Dentz

^ permalink raw reply

* Re: RFCOMM disconnection problem
From: Dean Jenkins @ 2012-08-09 14:29 UTC (permalink / raw)
  To: Frederic Danis; +Cc: linux-bluetooth@vger.kernel.org
In-Reply-To: <501BC282.9070509@linux.intel.com>

On 3 August 2012 13:22, Frederic Danis <frederic.danis@linux.intel.com> wrote:
> On 03/08/2012 14:15, Frederic Danis wrote:
>>
>> Hello,
>>
>> When I try to disconnect Blue Stereo 200 headset (from mrhandsfree) from
>> my PC, if headset was the initiator of the connection, the low level
>> (ACL) is not disconnected.
>> The device is still visible whith "hcitool con".
>>
>> This happens with BlueZ 4.98 or from git upstream, and kernel 3.4.6.
>> There is no disconnection problem with kernel 3.2.
>>
>> I also try to revert change "Bluetooth: Fix RFCOMM session reference
>> counting issue" (commit cf33e7 in linux-stable.git) from Octavian
>> Purdila in kernel 3.4.6.
>> With this kernel I do not get disconnection problem.
>>
>> You can find attached hcidump traces.
>
>
> Make a mistake, this was kernel log for l2cap and rfcomm.
>
> Find attached hcidump traces.
>
> Fred
>
>
> --
> Frederic Danis                            Open Source Technology Center
> frederic.danis@intel.com                              Intel Corporation
>

Hi Fred,

IMHO, kernel.org's rfcomm session refcnt is fundamentally broken and
is in fact redundant. Search back in the mailing list for my previous
proposed fixes.

One obvious failure of the rfcomm session refcnt is that the refcnt
counter either starts with a value of 0 or 1 depending on which peer
initiated the connection request, that is wrong. The initiator
direction is not relevant for the session as connect and disconnect
are independent events. The refcnt should start with a value of 1 in
all cases.

I am using a 2-core ARM environment that is under high processor
loading. The rfcomm session refcnt caused kernel crashes. I used a
2.6.34 kernel but the latest 3.5-RC1 still has the poor rfcomm code.
My solution was to remove the rfcomm session refcnt and to ensure that
the freeing of the rfcomm session pointer was propagated through-out
the rfcomm core code. Some kernel crashes were due to reuse of the
freed rfcomm session pointer.

I intend to release a patchset of rfcomm fixes.

Therefore, IMHO the fix "Bluetooth: Fix RFCOMM session reference
counting issue" (commit cf33e7 in linux-stable.git) from Octavian
Purdila in kernel 3.4.6 is in fact not fixing the root cause and
introduces a misbehaviour of the refcnt. In our project, we rejected
this commit because disconnections failed.

Regards,
Dean

-- 
Dean Jenkins
Embedded Software Engineer
Professional Services UK/EMEA
MontaVista Software, LLC

^ permalink raw reply

* Re: [PATCH] irmc: Fix possible memory leak in handling of location
From: Luiz Augusto von Dentz @ 2012-08-09 10:53 UTC (permalink / raw)
  To: Ludek Finstrle; +Cc: linux-bluetooth
In-Reply-To: <1344502915-487-1-git-send-email-luf@pzkagis.cz>

Hi Ludek,

On Thu, Aug 9, 2012 at 12:01 PM, Ludek Finstrle <luf@pzkagis.cz> wrote:
> ---
>  plugins/irmc.c |   19 ++++++++++++-------
>  1 files changed, 12 insertions(+), 7 deletions(-)
>
> diff --git a/plugins/irmc.c b/plugins/irmc.c
> index 2a8c543..0a0dc93 100644
> --- a/plugins/irmc.c
> +++ b/plugins/irmc.c
> @@ -401,6 +401,7 @@ static void *irmc_open(const char *name, int oflag, mode_t mode, void *context,
>  {
>         struct irmc_session *irmc = context;
>         int ret = 0;
> +       void *retp = NULL
>         char *path;
>
>         DBG("name %s context %p", name, context);
> @@ -422,22 +423,26 @@ static void *irmc_open(const char *name, int oflag, mode_t mode, void *context,
>                 path = g_build_filename("/", name, NULL);
>
>         if (g_str_equal(path, PB_DEVINFO))
> -               return irmc_open_devinfo(irmc, err);
> +               retp = irmc_open_devinfo(irmc, err);
>         else if (g_str_equal(path, PB_CONTACTS))
> -               return irmc_open_pb(irmc, err);
> +               retp = irmc_open_pb(irmc, err);
>         else if (g_str_equal(path, PB_INFO_LOG))
> -               return irmc_open_info(irmc, err);
> +               retp = irmc_open_info(irmc, err);
>         else if (g_str_equal(path, PB_CC_LOG))
> -               return irmc_open_cc(irmc, err);
> +               retp = irmc_open_cc(irmc, err);
>         else if (g_str_has_prefix(path, PB_CALENDAR_FOLDER))
> -               return irmc_open_cal(irmc, err);
> +               retp = irmc_open_cal(irmc, err);
>         else if (g_str_has_prefix(path, PB_NOTES_FOLDER))
> -               return irmc_open_nt(irmc, err);
> +               retp = irmc_open_nt(irmc, err);
>         else if (g_str_has_prefix(path, PB_LUID_FOLDER))
> -               return irmc_open_luid(irmc, err);
> +               retp = irmc_open_luid(irmc, err);
>         else
>                 ret = -EBADR;
>
> +       g_free(path);
> +       if (retp)
> +               return retp;
> +
>  fail:
>         if (err)
>                 *err = ret;
> --
> 1.7.1

Doesnt compile:

plugins/irmc.c: In function ‘irmc_open’:
plugins/irmc.c:405:2: error: expected ‘,’ or ‘;’ before ‘char’
plugins/irmc.c:421:3: error: ‘path’ undeclared (first use in this function)
plugins/irmc.c:421:3: note: each undeclared identifier is reported
only once for each function it appears in
make[1]: *** [plugins/irmc.o] Error 1
make: *** [all] Error 2

Anyway Ive done a little bit different fix:

diff --git a/plugins/irmc.c b/plugins/irmc.c
index 2a8c543..c9c3521 100644
--- a/plugins/irmc.c
+++ b/plugins/irmc.c
@@ -281,7 +281,7 @@ static int irmc_chkput(struct obex_session *os,
void *user_data)
 	return -EBADR;
 }

-static void *irmc_open_devinfo(struct irmc_session *irmc, int *err)
+static int irmc_open_devinfo(struct irmc_session *irmc)
 {
 	if (!irmc->buffer)
 		irmc->buffer = g_string_new("");
@@ -301,10 +301,10 @@ static void *irmc_open_devinfo(struct
irmc_session *irmc, int *err)
 				"NOTE-TYPE-RX:NONE\r\n",
 				irmc->manu, irmc->model, irmc->sn);

-	return irmc;
+	return 0;
 }

-static void *irmc_open_pb(struct irmc_session *irmc, int *err)
+static int irmc_open_pb(struct irmc_session *irmc)
 {
 	int ret;

@@ -313,25 +313,19 @@ static void *irmc_open_pb(struct irmc_session
*irmc, int *err)
 						query_result, irmc, &ret);
 	if (ret < 0) {
 		DBG("phonebook_pull failed...");
-		goto fail;
+		return ret;
 	}

 	ret = phonebook_pull_read(irmc->request);
 	if (ret < 0) {
 		DBG("phonebook_pull_read failed...");
-		goto fail;
+		return ret;
 	}

-	return irmc;
-
-fail:
-	if (err)
-		*err = ret;
-
-	return NULL;
+	return 0;
 }

-static void *irmc_open_info(struct irmc_session *irmc, int *err)
+static int irmc_open_info(struct irmc_session *irmc)
 {
 	if (irmc->buffer == NULL)
 		irmc->buffer = g_string_new("");
@@ -343,20 +337,20 @@ static void *irmc_open_info(struct irmc_session
*irmc, int *err)
 				irmc->params->maxlistcount,
 				irmc->params->maxlistcount, irmc->did);

-	return irmc;
+	return 0;
 }

-static void *irmc_open_cc(struct irmc_session *irmc, int *err)
+static int irmc_open_cc(struct irmc_session *irmc)
 {
 	if (irmc->buffer == NULL)
 		irmc->buffer = g_string_new("");

 	g_string_printf(irmc->buffer, "%d\r\n", irmc->params->maxlistcount);

-	return irmc;
+	return 0;
 }

-static void *irmc_open_cal(struct irmc_session *irmc, int *err)
+static int irmc_open_cal(struct irmc_session *irmc)
 {
 	/* no suport yet. Just return an empty buffer. cal.vcs */
 	DBG("unsupported, returning empty buffer");
@@ -364,10 +358,10 @@ static void *irmc_open_cal(struct irmc_session
*irmc, int *err)
 	if (!irmc->buffer)
 		irmc->buffer = g_string_new("");

-	return irmc;
+	return 0;
 }

-static void *irmc_open_nt(struct irmc_session *irmc, int *err)
+static int irmc_open_nt(struct irmc_session *irmc)
 {
 	/* no suport yet. Just return an empty buffer. nt.vnt */
 	DBG("unsupported, returning empty buffer");
@@ -375,10 +369,10 @@ static void *irmc_open_nt(struct irmc_session
*irmc, int *err)
 	if (!irmc->buffer)
 		irmc->buffer = g_string_new("");

-	return irmc;
+	return 0;
 }

-static void *irmc_open_luid(struct irmc_session *irmc, int *err)
+static int irmc_open_luid(struct irmc_session *irmc)
 {
 	if (irmc->buffer == NULL)
 		irmc->buffer = g_string_new("");
@@ -393,7 +387,7 @@ static void *irmc_open_luid(struct irmc_session
*irmc, int *err)
 					irmc->params->maxlistcount,
 					irmc->params->maxlistcount);

-	return irmc;
+	return 0;
 }

 static void *irmc_open(const char *name, int oflag, mode_t mode, void *context,
@@ -422,22 +416,27 @@ static void *irmc_open(const char *name, int
oflag, mode_t mode, void *context,
 		path = g_build_filename("/", name, NULL);

 	if (g_str_equal(path, PB_DEVINFO))
-		return irmc_open_devinfo(irmc, err);
+		ret = irmc_open_devinfo(irmc);
 	else if (g_str_equal(path, PB_CONTACTS))
-		return irmc_open_pb(irmc, err);
+		ret = irmc_open_pb(irmc);
 	else if (g_str_equal(path, PB_INFO_LOG))
-		return irmc_open_info(irmc, err);
+		ret = irmc_open_info(irmc);
 	else if (g_str_equal(path, PB_CC_LOG))
-		return irmc_open_cc(irmc, err);
+		ret = irmc_open_cc(irmc);
 	else if (g_str_has_prefix(path, PB_CALENDAR_FOLDER))
-		return irmc_open_cal(irmc, err);
+		ret = irmc_open_cal(irmc);
 	else if (g_str_has_prefix(path, PB_NOTES_FOLDER))
-		return irmc_open_nt(irmc, err);
+		ret = irmc_open_nt(irmc);
 	else if (g_str_has_prefix(path, PB_LUID_FOLDER))
-		return irmc_open_luid(irmc, err);
+		ret = irmc_open_luid(irmc);
 	else
 		ret = -EBADR;

+	g_free(path);
+
+	if (ret == 0)
+		return irmc;
+
 fail:
 	if (err)
 		*err = ret;
-- 
1.7.11.2


-- 
Luiz Augusto von Dentz

^ permalink raw reply related

* [PATCH obexd 9/9] core: Remove map_ap.c
From: Luiz Augusto von Dentz @ 2012-08-09 10:32 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1344508353-24647-1-git-send-email-luiz.dentz@gmail.com>

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

It is no longer needed as MAP plugin is now using GObexApparam API
---
 Makefile.am  |   4 +-
 src/map_ap.c | 466 -----------------------------------------------------------
 src/map_ap.h |  63 --------
 3 files changed, 2 insertions(+), 531 deletions(-)
 delete mode 100644 src/map_ap.c

diff --git a/Makefile.am b/Makefile.am
index 4757f60..724dd5d 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -63,7 +63,7 @@ builtin_sources += plugins/pbap.c plugins/phonebook.h \
 
 builtin_modules += mas
 builtin_sources += plugins/mas.c plugins/messages.h \
-			src/map_ap.c src/map_ap.h
+			src/map_ap.h
 
 builtin_modules += irmc
 builtin_sources += plugins/irmc.c
@@ -127,7 +127,7 @@ client_obex_client_SOURCES = $(gdbus_sources) $(gobex_sources) \
 				client/transport.h client/transport.c \
 				client/dbus.h client/dbus.c \
 				client/driver.h client/driver.c \
-				src/map_ap.h src/map_ap.c
+				src/map_ap.h
 
 client_obex_client_LDADD = @GLIB_LIBS@ @DBUS_LIBS@ @BLUEZ_LIBS@
 endif
diff --git a/src/map_ap.c b/src/map_ap.c
deleted file mode 100644
index 6efc484..0000000
--- a/src/map_ap.c
+++ /dev/null
@@ -1,466 +0,0 @@
-/*
- *
- *  OBEX Server
- *
- *  Copyright (C) 2010-2011  Nokia Corporation
- *
- *
- *  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 <string.h>
-
-#include "log.h"
-
-#include "map_ap.h"
-
-enum ap_type {
-	APT_UINT8,
-	APT_UINT16,
-	APT_UINT32,
-	APT_STR
-};
-
-/* NOTE: ap_defs array has to be kept in sync with map_ap_tag. */
-static const struct ap_def {
-	const char *name;
-	enum ap_type type;
-} ap_defs[] = {
-	{ "MAXLISTCOUNT",		APT_UINT16 },
-	{ "STARTOFFSET",		APT_UINT16 },
-	{ "FILTERMESSAGETYPE",		APT_UINT8  },
-	{ "FILTERPERIODBEGIN",		APT_STR    },
-	{ "FILTERPERIODEND",		APT_STR    },
-	{ "FILTERREADSTATUS",		APT_UINT8  },
-	{ "FILTERRECIPIENT",		APT_STR    },
-	{ "FILTERORIGINATOR",		APT_STR    },
-	{ "FILTERPRIORITY",		APT_UINT8  },
-	{ "ATTACHMENT",			APT_UINT8  },
-	{ "TRANSPARENT",		APT_UINT8  },
-	{ "RETRY",			APT_UINT8  },
-	{ "NEWMESSAGE",			APT_UINT8  },
-	{ "NOTIFICATIONSTATUS",		APT_UINT8  },
-	{ "MASINSTANCEID",		APT_UINT8  },
-	{ "PARAMETERMASK",		APT_UINT32 },
-	{ "FOLDERLISTINGSIZE",		APT_UINT16 },
-	{ "MESSAGESLISTINGSIZE",	APT_UINT16 },
-	{ "SUBJECTLENGTH",		APT_UINT8  },
-	{ "CHARSET",			APT_UINT8  },
-	{ "FRACTIONREQUEST",		APT_UINT8  },
-	{ "FRACTIONDELIVER",		APT_UINT8  },
-	{ "STATUSINDICATOR",		APT_UINT8  },
-	{ "STATUSVALUE",		APT_UINT8  },
-	{ "MSETIME",			APT_STR    },
-};
-
-struct ap_entry {
-	enum map_ap_tag tag;
-	union {
-		uint32_t u32;
-		uint16_t u16;
-		uint8_t u8;
-		char *str;
-	} val;
-};
-
-/* This comes from OBEX specs */
-struct obex_ap_header {
-	uint8_t tag;
-	uint8_t len;
-	uint8_t val[0];
-} __attribute__ ((packed));
-
-static int find_ap_def_offset(uint8_t tag)
-{
-	if (tag == 0 || tag > G_N_ELEMENTS(ap_defs))
-		return -1;
-
-	return tag - 1;
-}
-
-static void ap_entry_dump(gpointer tag, gpointer val, gpointer user_data)
-{
-	struct ap_entry *entry = val;
-	int offset;
-
-	offset = find_ap_def_offset(GPOINTER_TO_INT(tag));
-
-	switch (ap_defs[offset].type) {
-	case APT_UINT8:
-		DBG("%-30s %08x", ap_defs[offset].name, entry->val.u8);
-		break;
-	case APT_UINT16:
-		DBG("%-30s %08x", ap_defs[offset].name, entry->val.u16);
-		break;
-	case APT_UINT32:
-		DBG("%-30s %08x", ap_defs[offset].name, entry->val.u32);
-		break;
-	case APT_STR:
-		DBG("%-30s %s", ap_defs[offset].name, entry->val.str);
-		break;
-	}
-}
-
-static void ap_entry_free(gpointer val)
-{
-	struct ap_entry *entry = val;
-	int offset;
-
-	offset = find_ap_def_offset(entry->tag);
-
-	if (offset >= 0 && ap_defs[offset].type == APT_STR)
-		g_free(entry->val.str);
-
-	g_free(entry);
-}
-
-map_ap_t *map_ap_new(void)
-{
-	return g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL,
-								ap_entry_free);
-}
-
-void map_ap_free(map_ap_t *ap)
-{
-	if (!ap)
-		return;
-
-	g_hash_table_destroy(ap);
-}
-
-static void ap_decode_u8(map_ap_t *ap, const struct obex_ap_header *hdr)
-{
-	if (hdr->len != 1) {
-		DBG("Value of tag %u is %u byte(s) long instead of expected "
-				"1 byte - skipped!", hdr->tag, hdr->len);
-		return;
-	}
-
-	map_ap_set_u8(ap, hdr->tag, hdr->val[0]);
-}
-
-static void ap_decode_u16(map_ap_t *ap, const struct obex_ap_header *hdr)
-{
-	uint16_t val;
-
-	if (hdr->len != 2) {
-		DBG("Value of tag %u is %u byte(s) long instead of expected "
-				"2 bytes - skipped!", hdr->tag, hdr->len);
-		return;
-	}
-
-	memcpy(&val, hdr->val, sizeof(val));
-	map_ap_set_u16(ap, hdr->tag, GUINT16_FROM_BE(val));
-}
-
-static void ap_decode_u32(map_ap_t *ap, const struct obex_ap_header *hdr)
-{
-	uint32_t val;
-
-	if (hdr->len != 4) {
-		DBG("Value of tag %u is %u byte(s) long instead of expected "
-				"4 bytes - skipped!", hdr->tag, hdr->len);
-		return;
-	}
-
-	memcpy(&val, hdr->val, sizeof(val));
-	map_ap_set_u32(ap, hdr->tag, GUINT32_FROM_BE(val));
-}
-
-static void ap_decode_str(map_ap_t *ap, const struct obex_ap_header *hdr)
-{
-	char *val = g_malloc0(hdr->len + 1);
-
-	memcpy(val, hdr->val, hdr->len);
-	map_ap_set_string(ap, hdr->tag, val);
-
-	g_free(val);
-}
-
-map_ap_t *map_ap_decode(const uint8_t *buffer, size_t length)
-{
-	map_ap_t *ap;
-	struct obex_ap_header *hdr;
-	uint32_t done;
-	int offset;
-
-	ap = map_ap_new();
-	if (!ap)
-		return NULL;
-
-	for (done = 0;  done < length; done += hdr->len + sizeof(*hdr)) {
-		hdr = (struct obex_ap_header *)(buffer + done);
-
-		offset = find_ap_def_offset(hdr->tag);
-
-		if (offset < 0) {
-			DBG("Unknown tag %u (length %u) - skipped.",
-							hdr->tag, hdr->len);
-			continue;
-		}
-
-		switch (ap_defs[offset].type) {
-		case APT_UINT8:
-			ap_decode_u8(ap, hdr);
-			break;
-		case APT_UINT16:
-			ap_decode_u16(ap, hdr);
-			break;
-		case APT_UINT32:
-			ap_decode_u32(ap, hdr);
-			break;
-		case APT_STR:
-			ap_decode_str(ap, hdr);
-			break;
-		}
-	}
-
-	g_hash_table_foreach(ap, ap_entry_dump, NULL);
-
-	return ap;
-}
-
-static void ap_encode_u8(GByteArray *buf, struct ap_entry *entry)
-{
-	struct obex_ap_header *hdr;
-
-	hdr = (struct obex_ap_header *) buf->data + buf->len;
-	g_byte_array_set_size(buf, buf->len + sizeof(*hdr) + 1);
-
-	hdr->tag = entry->tag;
-	hdr->len = 1;
-	hdr->val[0] = entry->val.u8;
-}
-
-static void ap_encode_u16(GByteArray *buf, struct ap_entry *entry)
-{
-	struct obex_ap_header *hdr;
-	uint16_t val;
-
-	hdr = (struct obex_ap_header *) buf->data + buf->len;
-
-	g_byte_array_set_size(buf, buf->len + sizeof(*hdr) + 2);
-
-	hdr->tag = entry->tag;
-	hdr->len = 2;
-
-	val = GUINT16_TO_BE(entry->val.u16);
-	memcpy(hdr->val, &val, sizeof(val));
-}
-
-static void ap_encode_u32(GByteArray *buf, struct ap_entry *entry)
-{
-	uint32_t val;
-	struct obex_ap_header *hdr;
-
-	hdr = (struct obex_ap_header *) buf->data + buf->len;
-	g_byte_array_set_size(buf, buf->len + sizeof(*hdr) + 4);
-
-	hdr->tag = entry->tag;
-	hdr->len = 4;
-
-	val = GUINT32_TO_BE(entry->val.u16);
-	memcpy(hdr->val, &val, sizeof(val));
-}
-
-static void ap_encode_str(GByteArray *buf, struct ap_entry *entry)
-{
-	size_t len;
-	struct obex_ap_header *hdr;
-
-	hdr = (struct obex_ap_header *) buf->data + buf->len;
-	len = strlen(entry->val.str);
-	g_byte_array_set_size(buf, buf->len + sizeof(*hdr) + len);
-
-	hdr->tag = entry->tag;
-	hdr->len = len;
-
-	memcpy(hdr->val, entry->val.str, len);
-}
-
-uint8_t *map_ap_encode(map_ap_t *ap, size_t *length)
-{
-	GByteArray *buf;
-	GHashTableIter iter;
-	gpointer key, value;
-	struct ap_entry *entry;
-	int offset;
-
-	buf = g_byte_array_new();
-	g_hash_table_iter_init(&iter, ap);
-
-	while (g_hash_table_iter_next(&iter, &key, &value)) {
-		entry = (struct ap_entry *) value;
-		offset = find_ap_def_offset(entry->tag);
-
-		switch (ap_defs[offset].type) {
-		case APT_UINT8:
-			ap_encode_u8(buf, entry);
-			break;
-		case APT_UINT16:
-			ap_encode_u16(buf, entry);
-			break;
-		case APT_UINT32:
-			ap_encode_u32(buf, entry);
-			break;
-		case APT_STR:
-			ap_encode_str(buf, entry);
-			break;
-		}
-	}
-
-	*length = buf->len;
-
-	return g_byte_array_free(buf, FALSE);
-}
-
-gboolean map_ap_get_u8(map_ap_t *ap, enum map_ap_tag tag, uint8_t *val)
-{
-	struct ap_entry *entry;
-	int offset = find_ap_def_offset(tag);
-
-	if (offset < 0 || ap_defs[offset].type != APT_UINT8)
-		return FALSE;
-
-	entry = g_hash_table_lookup(ap, GINT_TO_POINTER(tag));
-	if (entry == NULL)
-		return FALSE;
-
-	*val = entry->val.u8;
-
-	return TRUE;
-}
-
-gboolean map_ap_get_u16(map_ap_t *ap, enum map_ap_tag tag, uint16_t *val)
-{
-	struct ap_entry *entry;
-	int offset = find_ap_def_offset(tag);
-
-	if (offset < 0 || ap_defs[offset].type != APT_UINT16)
-		return FALSE;
-
-	entry = g_hash_table_lookup(ap, GINT_TO_POINTER(tag));
-	if (entry == NULL)
-		return FALSE;
-
-	*val = entry->val.u16;
-
-	return TRUE;
-}
-
-gboolean map_ap_get_u32(map_ap_t *ap, enum map_ap_tag tag, uint32_t *val)
-{
-	struct ap_entry *entry;
-	int offset = find_ap_def_offset(tag);
-
-	if (offset < 0 || ap_defs[offset].type != APT_UINT32)
-		return FALSE;
-
-	entry = g_hash_table_lookup(ap, GINT_TO_POINTER(tag));
-	if (entry == NULL)
-		return FALSE;
-
-	*val = entry->val.u32;
-
-	return TRUE;
-}
-
-const char *map_ap_get_string(map_ap_t *ap, enum map_ap_tag tag)
-{
-	struct ap_entry *entry;
-	int offset = find_ap_def_offset(tag);
-
-	if (offset < 0 || ap_defs[offset].type != APT_STR)
-		return NULL;
-
-	entry = g_hash_table_lookup(ap, GINT_TO_POINTER(tag));
-	if (entry == NULL)
-		return NULL;
-
-	return entry->val.str;
-}
-
-gboolean map_ap_set_u8(map_ap_t *ap, enum map_ap_tag tag, uint8_t val)
-{
-	struct ap_entry *entry;
-	int offset = find_ap_def_offset(tag);
-
-	if (offset < 0 || ap_defs[offset].type != APT_UINT8)
-		return FALSE;
-
-	entry = g_new0(struct ap_entry, 1);
-	entry->tag = tag;
-	entry->val.u8 = val;
-
-	g_hash_table_insert(ap, GINT_TO_POINTER(tag), entry);
-
-	return TRUE;
-}
-
-gboolean map_ap_set_u16(map_ap_t *ap, enum map_ap_tag tag, uint16_t val)
-{
-	struct ap_entry *entry;
-	int offset = find_ap_def_offset(tag);
-
-	if (offset < 0 || ap_defs[offset].type != APT_UINT16)
-		return FALSE;
-
-	entry = g_new0(struct ap_entry, 1);
-	entry->tag = tag;
-	entry->val.u16 = val;
-
-	g_hash_table_insert(ap, GINT_TO_POINTER(tag), entry);
-
-	return TRUE;
-}
-
-gboolean map_ap_set_u32(map_ap_t *ap, enum map_ap_tag tag, uint32_t val)
-{
-	struct ap_entry *entry;
-	int offset = find_ap_def_offset(tag);
-
-	if (offset < 0 || ap_defs[offset].type != APT_UINT32)
-		return FALSE;
-
-	entry = g_new0(struct ap_entry, 1);
-	entry->tag = tag;
-	entry->val.u32 = val;
-
-	g_hash_table_insert(ap, GINT_TO_POINTER(tag), entry);
-
-	return TRUE;
-}
-
-gboolean map_ap_set_string(map_ap_t *ap, enum map_ap_tag tag, const char *val)
-{
-	struct ap_entry *entry;
-	int offset = find_ap_def_offset(tag);
-
-	if (offset < 0 || ap_defs[offset].type != APT_STR)
-		return FALSE;
-
-	entry = g_new0(struct ap_entry, 1);
-	entry->tag = tag;
-	entry->val.str = g_strdup(val);
-
-	g_hash_table_insert(ap, GINT_TO_POINTER(tag), entry);
-
-	return TRUE;
-}
diff --git a/src/map_ap.h b/src/map_ap.h
index 24254af..da108fe 100644
--- a/src/map_ap.h
+++ b/src/map_ap.h
@@ -21,9 +21,6 @@
  *
  */
 
-#include <glib.h>
-#include <inttypes.h>
-
 /* List of OBEX application parameters tags as per MAP specification. */
 enum map_ap_tag {
 	MAP_AP_MAXLISTCOUNT		= 0x01,		/* uint16_t	*/
@@ -52,63 +49,3 @@ enum map_ap_tag {
 	MAP_AP_STATUSVALUE		= 0x18,		/* uint8_t	*/
 	MAP_AP_MSETIME			= 0x19,		/* char *	*/
 };
-
-/* Data type representing MAP application parameters. Consider opaque. */
-typedef GHashTable map_ap_t;
-
-/* Creates a new empty MAP application parameters object. */
-map_ap_t *map_ap_new(void);
-
-/* Frees all the memory used by MAP application parameters object. */
-void map_ap_free(map_ap_t *ap);
-
-/* Parses given buffer that is a payload of OBEX application parameter header
- * with a given length. Returned value can be used in calls to map_ap_get_*()
- * and map_ap_set_*(). It has to be freed using map_ap_free(). It also takes
- * care of converting all the data to host byte order, so this is the byte
- * order used in map_ap_get_*()/map_ap_set_*().
- *
- * Returns NULL in case of failure.
- */
-map_ap_t *map_ap_decode(const uint8_t *buffer, size_t length);
-
-/* Takes all parameters currently set and packs them into a buffer with OBEX
- * application parameters header payload format.
- *
- * Returns newly allocated buffer of size 'length'. Free with g_free().
- */
-uint8_t *map_ap_encode(map_ap_t *ap, size_t *length);
-
-/* Following family of functions reads value of MAP parameter with given tag.
- * Use the one with appropriate type for a given tag, as noted above in
- * map_ap_tag declaration comments.
- *
- * Returns TRUE when value is present. FALSE if it is not or the function is
- * used get a parameter of a different type. When FALSE is returned, variable
- * pointed by 'val' is left intact.
- */
-gboolean map_ap_get_u8(map_ap_t *ap, enum map_ap_tag tag, uint8_t *val);
-gboolean map_ap_get_u16(map_ap_t *ap, enum map_ap_tag tag, uint16_t *val);
-gboolean map_ap_get_u32(map_ap_t *ap, enum map_ap_tag tag, uint32_t *val);
-
-/* Reads value of MAP parameter with given tag that is of a string type.
- *
- * Returns NULL if parameter is not present in ap or given tag is not of a
- * string type.
- */
-const char *map_ap_get_string(map_ap_t *ap, enum map_ap_tag tag);
-
-/* Following family of functions sets the value of MAP parameter with given
- * tag. Use the one with appropriate type for a given tag, as noted above in
- * map_ap_tag declaration comments.
- *
- * If there is already a parameter with given tag present, it will be
- * replaced. map_ap_set_string() makes its own copy of given string.
- *
- * Returns TRUE on success (the tag is known and the function chosen matches
- * the type of tag).
- */
-gboolean map_ap_set_u8(map_ap_t *ap, enum map_ap_tag tag, uint8_t val);
-gboolean map_ap_set_u16(map_ap_t *ap, enum map_ap_tag tag, uint16_t val);
-gboolean map_ap_set_u32(map_ap_t *ap, enum map_ap_tag tag, uint32_t val);
-gboolean map_ap_set_string(map_ap_t *ap, enum map_ap_tag tag, const char *val);
-- 
1.7.11.2


^ permalink raw reply related

* [PATCH obexd 8/9] MAP: Make use of GObexApparam API
From: Luiz Augusto von Dentz @ 2012-08-09 10:32 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1344508353-24647-1-git-send-email-luiz.dentz@gmail.com>

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

---
 plugins/mas.c | 81 ++++++++++++++++++++++++++++-------------------------------
 1 file changed, 38 insertions(+), 43 deletions(-)

diff --git a/plugins/mas.c b/plugins/mas.c
index 576c206..30e529f 100644
--- a/plugins/mas.c
+++ b/plugins/mas.c
@@ -32,6 +32,7 @@
 #include <inttypes.h>
 
 #include <gobex/gobex.h>
+#include <gobex/gobex-apparam.h>
 
 #include "obexd.h"
 #include "plugin.h"
@@ -112,8 +113,8 @@ struct mas_session {
 	gboolean finished;
 	gboolean nth_call;
 	GString *buffer;
-	map_ap_t *inparams;
-	map_ap_t *outparams;
+	GObexApparam *inparams;
+	GObexApparam *outparams;
 	gboolean ap_sent;
 };
 
@@ -130,14 +131,12 @@ static int get_params(struct obex_session *os, struct mas_session *mas)
 	if (size < 0)
 		size = 0;
 
-	mas->inparams = map_ap_decode(buffer, size);
+	mas->inparams = g_obex_apparam_decode(buffer, size);
 	if (mas->inparams == NULL) {
 		DBG("Error when parsing parameters!");
 		return -EBADR;
 	}
 
-	mas->outparams = map_ap_new();
-
 	return 0;
 }
 
@@ -148,10 +147,15 @@ static void reset_request(struct mas_session *mas)
 		mas->buffer = NULL;
 	}
 
-	map_ap_free(mas->inparams);
-	mas->inparams = NULL;
-	map_ap_free(mas->outparams);
-	mas->outparams = NULL;
+	if (mas->inparams) {
+		g_obex_apparam_free(mas->inparams);
+		mas->inparams = NULL;
+	}
+
+	if (mas->outparams) {
+		g_obex_apparam_free(mas->outparams);
+		mas->outparams = NULL;
+	}
 
 	mas->nth_call = FALSE;
 	mas->finished = FALSE;
@@ -289,7 +293,7 @@ static void get_messages_listing_cb(void *session, int err, uint16_t size,
 		return;
 	}
 
-	map_ap_get_u16(mas->inparams, MAP_AP_MAXLISTCOUNT, &max);
+	g_obex_apparam_get_uint16(mas->inparams, MAP_AP_MAXLISTCOUNT, &max);
 
 	if (max == 0) {
 		if (!entry)
@@ -390,10 +394,12 @@ static void get_messages_listing_cb(void *session, int err, uint16_t size,
 
 proceed:
 	if (!entry) {
-		map_ap_set_u16(mas->outparams, MAP_AP_MESSAGESLISTINGSIZE,
-							size);
-		map_ap_set_u8(mas->outparams, MAP_AP_NEWMESSAGE,
-							newmsg ? 1 : 0);
+		mas->outparams = g_obex_apparam_set_uint16(mas->outparams,
+						MAP_AP_MESSAGESLISTINGSIZE,
+						size);
+		mas->outparams = g_obex_apparam_set_uint8(mas->outparams,
+						MAP_AP_NEWMESSAGE,
+						newmsg ? 1 : 0);
 	}
 
 	if (err != -EAGAIN)
@@ -435,12 +441,14 @@ static void get_folder_listing_cb(void *session, int err, uint16_t size,
 		return;
 	}
 
-	map_ap_get_u16(mas->inparams, MAP_AP_MAXLISTCOUNT, &max);
+	g_obex_apparam_get_uint16(mas->inparams, MAP_AP_MAXLISTCOUNT, &max);
 
 	if (max == 0) {
 		if (err != -EAGAIN)
-			map_ap_set_u16(mas->outparams,
-					MAP_AP_FOLDERLISTINGSIZE, size);
+			mas->outparams = g_obex_apparam_set_uint16(
+						mas->outparams,
+						MAP_AP_FOLDERLISTINGSIZE,
+						size);
 
 		if (!name)
 			mas->finished = TRUE;
@@ -529,8 +537,8 @@ static void *folder_listing_open(const char *name, int oflag, mode_t mode,
 
 	DBG("name = %s", name);
 
-	map_ap_get_u16(mas->inparams, MAP_AP_MAXLISTCOUNT, &max);
-	map_ap_get_u16(mas->inparams, MAP_AP_STARTOFFSET, &offset);
+	g_obex_apparam_get_uint16(mas->inparams, MAP_AP_MAXLISTCOUNT, &max);
+	g_obex_apparam_get_uint16(mas->inparams, MAP_AP_STARTOFFSET, &offset);
 
 	*err = messages_get_folder_listing(mas->backend_data, name, max,
 					offset, get_folder_listing_cb, mas);
@@ -559,24 +567,24 @@ static void *msg_listing_open(const char *name, int oflag, mode_t mode,
 		return NULL;
 	}
 
-	map_ap_get_u16(mas->inparams, MAP_AP_MAXLISTCOUNT, &max);
-	map_ap_get_u16(mas->inparams, MAP_AP_STARTOFFSET, &offset);
+	g_obex_apparam_get_uint16(mas->inparams, MAP_AP_MAXLISTCOUNT, &max);
+	g_obex_apparam_get_uint16(mas->inparams, MAP_AP_STARTOFFSET, &offset);
 
-	map_ap_get_u32(mas->inparams, MAP_AP_PARAMETERMASK,
+	g_obex_apparam_get_uint32(mas->inparams, MAP_AP_PARAMETERMASK,
 						&filter.parameter_mask);
-	map_ap_get_u8(mas->inparams, MAP_AP_FILTERMESSAGETYPE,
+	g_obex_apparam_get_uint8(mas->inparams, MAP_AP_FILTERMESSAGETYPE,
 						&filter.type);
-	filter.period_begin = map_ap_get_string(mas->inparams,
+	filter.period_begin = g_obex_apparam_get_string(mas->inparams,
 						MAP_AP_FILTERPERIODBEGIN);
-	filter.period_end = map_ap_get_string(mas->inparams,
+	filter.period_end = g_obex_apparam_get_string(mas->inparams,
 						MAP_AP_FILTERPERIODEND);
-	map_ap_get_u8(mas->inparams, MAP_AP_FILTERREADSTATUS,
+	g_obex_apparam_get_uint8(mas->inparams, MAP_AP_FILTERREADSTATUS,
 						&filter.read_status);
-	filter.recipient = map_ap_get_string(mas->inparams,
+	filter.recipient = g_obex_apparam_get_string(mas->inparams,
 						MAP_AP_FILTERRECIPIENT);
-	filter.originator = map_ap_get_string(mas->inparams,
+	filter.originator = g_obex_apparam_get_string(mas->inparams,
 						MAP_AP_FILTERORIGINATOR);
-	map_ap_get_u8(mas->inparams, MAP_AP_FILTERPRIORITY,
+	g_obex_apparam_get_uint8(mas->inparams, MAP_AP_FILTERPRIORITY,
 						&filter.priority);
 
 	*err = messages_get_messages_listing(mas->backend_data, name, max,
@@ -640,8 +648,6 @@ static ssize_t any_get_next_header(void *object, void *buf, size_t mtu,
 								uint8_t *hi)
 {
 	struct mas_session *mas = object;
-	size_t len;
-	uint8_t *apbuf;
 
 	DBG("");
 
@@ -654,18 +660,7 @@ static ssize_t any_get_next_header(void *object, void *buf, size_t mtu,
 		return 0;
 
 	mas->ap_sent = TRUE;
-	apbuf = map_ap_encode(mas->outparams, &len);
-
-	if (len > mtu) {
-		DBG("MTU is to small to fit application parameters header!");
-		g_free(apbuf);
-
-		return -EIO;
-	}
-
-	memcpy(buf, apbuf, len);
-
-	return len;
+	return g_obex_apparam_encode(mas->outparams, buf, mtu);
 }
 
 static void *any_open(const char *name, int oflag, mode_t mode,
-- 
1.7.11.2


^ permalink raw reply related

* [PATCH obexd 7/9] PBAP: Make use of GObexApparam API
From: Luiz Augusto von Dentz @ 2012-08-09 10:32 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1344508353-24647-1-git-send-email-luiz.dentz@gmail.com>

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

---
 plugins/pbap.c      | 180 +++++++++++-----------------------------------------
 plugins/phonebook.h |   2 +-
 2 files changed, 39 insertions(+), 143 deletions(-)

diff --git a/plugins/pbap.c b/plugins/pbap.c
index c7e792a..c36fab2 100644
--- a/plugins/pbap.c
+++ b/plugins/pbap.c
@@ -39,6 +39,7 @@
 #include <inttypes.h>
 
 #include <gobex.h>
+#include <gobex-apparam.h>
 
 #include "obexd.h"
 #include "plugin.h"
@@ -64,16 +65,6 @@
 #define PHONEBOOKSIZE_TAG	0X08
 #define NEWMISSEDCALLS_TAG	0X09
 
-/* The following length is in the unit of byte */
-#define ORDER_LEN		1
-#define SEARCHATTRIB_LEN	1
-#define MAXLISTCOUNT_LEN	2
-#define LISTSTARTOFFSET_LEN	2
-#define FILTER_LEN		8
-#define FORMAT_LEN		1
-#define PHONEBOOKSIZE_LEN	2
-#define NEWMISSEDCALLS_LEN	1
-
 #define PBAP_CHANNEL	15
 
 #define PBAP_RECORD "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>	\
@@ -117,12 +108,6 @@
   </attribute>								\
 </record>"
 
-struct aparam_header {
-	uint8_t tag;
-	uint8_t len;
-	uint8_t val[0];
-} __attribute__ ((packed));
-
 struct cache {
 	gboolean valid;
 	uint32_t index;
@@ -147,7 +132,7 @@ struct pbap_session {
 
 struct pbap_object {
 	GString *buffer;
-	GByteArray *aparams;
+	GObexApparam *apparam;
 	gboolean firstpacket;
 	gboolean lastpart;
 	struct pbap_session *session;
@@ -229,33 +214,6 @@ static void cache_clear(struct cache *cache)
 	cache->entries = NULL;
 }
 
-static GByteArray *append_aparam_header(GByteArray *buf, uint8_t tag,
-							const void *val)
-{
-	/* largest aparam is for phonebooksize (4 bytes) */
-	uint8_t aparam[sizeof(struct aparam_header) + PHONEBOOKSIZE_LEN];
-	struct aparam_header *hdr = (struct aparam_header *) aparam;
-
-	switch (tag) {
-	case PHONEBOOKSIZE_TAG:
-		hdr->tag = PHONEBOOKSIZE_TAG;
-		hdr->len = PHONEBOOKSIZE_LEN;
-		memcpy(hdr->val, val, PHONEBOOKSIZE_LEN);
-
-		return g_byte_array_append(buf,	aparam,
-			sizeof(struct aparam_header) + PHONEBOOKSIZE_LEN);
-	case NEWMISSEDCALLS_TAG:
-		hdr->tag = NEWMISSEDCALLS_TAG;
-		hdr->len = NEWMISSEDCALLS_LEN;
-		memcpy(hdr->val, val, NEWMISSEDCALLS_LEN);
-
-		return g_byte_array_append(buf,	aparam,
-			sizeof(struct aparam_header) + NEWMISSEDCALLS_LEN);
-	default:
-		return buf;
-	}
-}
-
 static void phonebook_size_result(const char *buffer, size_t bufsize,
 					int vcards, int missed,
 					gboolean lastpart, void *user_data)
@@ -275,15 +233,16 @@ static void phonebook_size_result(const char *buffer, size_t bufsize,
 
 	phonebooksize = htons(vcards);
 
-	pbap->obj->aparams = g_byte_array_new();
-	pbap->obj->aparams = append_aparam_header(pbap->obj->aparams,
-					PHONEBOOKSIZE_TAG, &phonebooksize);
+	pbap->obj->apparam = g_obex_apparam_set_uint16(NULL, PHONEBOOKSIZE_TAG,
+								phonebooksize);
 
 	if (missed > 0)	{
 		DBG("missed %d", missed);
 
-		pbap->obj->aparams = append_aparam_header(pbap->obj->aparams,
-						NEWMISSEDCALLS_TAG, &missed);
+		pbap->obj->apparam = g_obex_apparam_set_uint16(
+							pbap->obj->apparam,
+							NEWMISSEDCALLS_TAG,
+							missed);
 	}
 
 	obex_object_set_io_flags(pbap->obj, G_IO_IN, 0);
@@ -319,9 +278,10 @@ static void query_result(const char *buffer, size_t bufsize, int vcards,
 
 		pbap->obj->firstpacket = TRUE;
 
-		pbap->obj->aparams = g_byte_array_new();
-		pbap->obj->aparams = append_aparam_header(pbap->obj->aparams,
-						NEWMISSEDCALLS_TAG, &missed);
+		pbap->obj->apparam = g_obex_apparam_set_uint16(
+							pbap->obj->apparam,
+							NEWMISSEDCALLS_TAG,
+							missed);
 	}
 
 	obex_object_set_io_flags(pbap->obj, G_IO_IN, 0);
@@ -450,9 +410,10 @@ static int generate_response(void *user_data)
 		/* Ignore all other parameter and return PhoneBookSize */
 		uint16_t size = htons(g_slist_length(pbap->cache.entries));
 
-		pbap->obj->aparams = g_byte_array_new();
-		pbap->obj->aparams = append_aparam_header(pbap->obj->aparams,
-						PHONEBOOKSIZE_TAG, &size);
+		pbap->obj->apparam = g_obex_apparam_set_uint16(
+							pbap->obj->apparam,
+							PHONEBOOKSIZE_TAG,
+							size);
 
 		return 0;
 	}
@@ -527,85 +488,34 @@ static void cache_entry_done(void *user_data)
 
 static struct apparam_field *parse_aparam(const uint8_t *buffer, uint32_t hlen)
 {
+	GObexApparam *apparam;
 	struct apparam_field *param;
-	struct aparam_header *hdr;
-	uint64_t val64;
-	uint32_t len = 0;
-	uint16_t val16;
-
-	param = g_new0(struct apparam_field, 1);
-
-	while (len < hlen) {
-		hdr = (void *) buffer + len;
-
-		switch (hdr->tag) {
-		case ORDER_TAG:
-			if (hdr->len != ORDER_LEN)
-				goto failed;
-
-			param->order = hdr->val[0];
-			break;
-
-		case SEARCHATTRIB_TAG:
-			if (hdr->len != SEARCHATTRIB_LEN)
-				goto failed;
-
-			param->searchattrib = hdr->val[0];
-			break;
-		case SEARCHVALUE_TAG:
-			if (hdr->len == 0)
-				goto failed;
-
-			param->searchval = g_try_malloc0(hdr->len + 1);
-			if (param->searchval)
-				memcpy(param->searchval, hdr->val, hdr->len);
-			break;
-		case FILTER_TAG:
-			if (hdr->len != FILTER_LEN)
-				goto failed;
-
-			memcpy(&val64, hdr->val, sizeof(val64));
-			param->filter = GUINT64_FROM_BE(val64);
-
-			break;
-		case FORMAT_TAG:
-			if (hdr->len != FORMAT_LEN)
-				goto failed;
 
-			param->format = hdr->val[0];
-			break;
-		case MAXLISTCOUNT_TAG:
-			if (hdr->len != MAXLISTCOUNT_LEN)
-				goto failed;
+	apparam = g_obex_apparam_decode(buffer, hlen);
+	if (apparam == NULL)
+		return NULL;
 
-			memcpy(&val16, hdr->val, sizeof(val16));
-			param->maxlistcount = GUINT16_FROM_BE(val16);
-			break;
-		case LISTSTARTOFFSET_TAG:
-			if (hdr->len != LISTSTARTOFFSET_LEN)
-				goto failed;
-
-			memcpy(&val16, hdr->val, sizeof(val16));
-			param->liststartoffset = GUINT16_FROM_BE(val16);
-			break;
-		default:
-			goto failed;
-		}
+	param = g_new0(struct apparam_field, 1);
 
-		len += hdr->len + sizeof(struct aparam_header);
-	}
+	g_obex_apparam_get_uint8(apparam, ORDER_TAG, &param->order);
+	g_obex_apparam_get_uint8(apparam, SEARCHATTRIB_TAG,
+						&param->searchattrib);
+	g_obex_apparam_get_uint8(apparam, FORMAT_TAG, &param->format);
+	g_obex_apparam_get_uint16(apparam, MAXLISTCOUNT_TAG,
+						&param->maxlistcount);
+	g_obex_apparam_get_uint16(apparam, LISTSTARTOFFSET_TAG,
+						&param->liststartoffset);
+	g_obex_apparam_get_uint64(apparam, FILTER_TAG, &param->filter);
+	param->searchval = g_obex_apparam_get_string(apparam, SEARCHVALUE_TAG);
 
 	DBG("o %x sa %x sv %s fil %" G_GINT64_MODIFIER "x for %x max %x off %x",
 			param->order, param->searchattrib, param->searchval,
 			param->filter, param->format, param->maxlistcount,
 			param->liststartoffset);
 
-	return param;
-
-failed:
-	g_free(param);
+	g_obex_apparam_free(apparam);
 
-	return NULL;
+	return param;
 }
 
 static void *pbap_connect(struct obex_session *os, int *err)
@@ -839,8 +749,8 @@ static int vobject_close(void *object)
 	if (obj->buffer)
 		g_string_free(obj->buffer, TRUE);
 
-	if (obj->aparams)
-		g_byte_array_free(obj->aparams, TRUE);
+	if (obj->apparam)
+		g_obex_apparam_free(obj->apparam);
 
 	if (obj->request)
 		phonebook_req_finalize(obj->request);
@@ -952,27 +862,13 @@ fail:
 	return NULL;
 }
 
-static ssize_t array_read(GByteArray *array, void *buf, size_t count)
-{
-	ssize_t len;
-
-	if (array->len == 0)
-		return 0;
-
-	len = MIN(array->len, count);
-	memcpy(buf, array->data, len);
-	g_byte_array_remove_range(array, 0, len);
-
-	return len;
-}
-
 static ssize_t vobject_pull_get_next_header(void *object, void *buf, size_t mtu,
 								uint8_t *hi)
 {
 	struct pbap_object *obj = object;
 	struct pbap_session *pbap = obj->session;
 
-	if (!obj->buffer && !obj->aparams)
+	if (!obj->buffer && !obj->apparam)
 		return -EAGAIN;
 
 	*hi = G_OBEX_HDR_APPARAM;
@@ -980,7 +876,7 @@ static ssize_t vobject_pull_get_next_header(void *object, void *buf, size_t mtu,
 	if (pbap->params->maxlistcount == 0 || obj->firstpacket) {
 		obj->firstpacket = FALSE;
 
-		return array_read(obj->aparams, buf, mtu);
+		return g_obex_apparam_encode(obj->apparam, buf, mtu);
 	}
 
 	return 0;
@@ -1031,7 +927,7 @@ static ssize_t vobject_list_get_next_header(void *object, void *buf, size_t mtu,
 	*hi = G_OBEX_HDR_APPARAM;
 
 	if (pbap->params->maxlistcount == 0)
-		return array_read(obj->aparams, buf, mtu);
+		return g_obex_apparam_encode(obj->apparam, buf, mtu);
 
 	return 0;
 }
diff --git a/plugins/phonebook.h b/plugins/phonebook.h
index 6e51c73..441cff2 100644
--- a/plugins/phonebook.h
+++ b/plugins/phonebook.h
@@ -61,7 +61,7 @@ struct apparam_field {
 	/* list attributes only */
 	uint8_t order;
 	uint8_t searchattrib;
-	uint8_t *searchval;
+	char *searchval;
 };
 
 /*
-- 
1.7.11.2


^ permalink raw reply related

* [PATCH obexd 6/9] client: Port PBAP module to use GObexApparam
From: Luiz Augusto von Dentz @ 2012-08-09 10:32 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1344508353-24647-1-git-send-email-luiz.dentz@gmail.com>

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

---
 client/pbap.c | 181 ++++++++++++++++------------------------------------------
 1 file changed, 49 insertions(+), 132 deletions(-)

diff --git a/client/pbap.c b/client/pbap.c
index 48dbac1..9a1da8d 100644
--- a/client/pbap.c
+++ b/client/pbap.c
@@ -33,6 +33,7 @@
 #include <gdbus.h>
 
 #include <bluetooth/bluetooth.h>
+#include <gobex-apparam.h>
 
 #include "log.h"
 
@@ -72,18 +73,6 @@
 #define PHONEBOOKSIZE_TAG	0X08
 #define NEWMISSEDCALLS_TAG	0X09
 
-/* The following length is in the unit of byte */
-#define ORDER_LEN		1
-#define SEARCHATTRIB_LEN	1
-#define MAXLISTCOUNT_LEN	2
-#define LISTSTARTOFFSET_LEN	2
-#define FILTER_LEN		8
-#define FORMAT_LEN		1
-#define PHONEBOOKSIZE_LEN	2
-#define NEWMISSEDCALLS_LEN	1
-
-#define get_be16(val)	GUINT16_FROM_BE(bt_get_unaligned((guint16 *) val))
-
 static const char *filter_list[] = {
 	"VERSION",
 	"FN",
@@ -137,38 +126,6 @@ struct pending_request {
 	DBusMessage *msg;
 };
 
-struct pullphonebook_apparam {
-	uint8_t     filter_tag;
-	uint8_t     filter_len;
-	uint64_t    filter;
-	uint8_t     format_tag;
-	uint8_t     format_len;
-	uint8_t     format;
-	uint8_t     maxlistcount_tag;
-	uint8_t     maxlistcount_len;
-	uint16_t    maxlistcount;
-	uint8_t     liststartoffset_tag;
-	uint8_t     liststartoffset_len;
-	uint16_t    liststartoffset;
-} __attribute__ ((packed));
-
-struct pullvcardentry_apparam {
-        uint8_t     filter_tag;
-        uint8_t     filter_len;
-        uint64_t    filter;
-        uint8_t     format_tag;
-        uint8_t     format_len;
-        uint8_t     format;
-} __attribute__ ((packed));
-
-struct apparam_hdr {
-	uint8_t		tag;
-	uint8_t		len;
-	uint8_t		val[0];
-} __attribute__ ((packed));
-
-#define APPARAM_HDR_SIZE 2
-
 static DBusConnection *conn = NULL;
 
 static struct pending_request *pending_request_new(struct pbap_data *pbap,
@@ -295,48 +252,28 @@ static void pbap_setpath_cb(struct obc_session *session,
 static void read_return_apparam(struct obc_transfer *transfer,
 				guint16 *phone_book_size, guint8 *new_missed_calls)
 {
-	const struct apparam_hdr *hdr;
+	GObexApparam *apparam;
+	const guint8 *data;
 	size_t size;
 
 	*phone_book_size = 0;
 	*new_missed_calls = 0;
 
-	hdr = obc_transfer_get_params(transfer, &size);
-	if (hdr == NULL)
+	data = obc_transfer_get_params(transfer, &size);
+	if (data == NULL)
 		return;
 
-	if (size < APPARAM_HDR_SIZE)
+	apparam = g_obex_apparam_decode(data, size);
+	if (apparam == NULL)
 		return;
 
-	while (size > APPARAM_HDR_SIZE) {
-		if (hdr->len > size - APPARAM_HDR_SIZE) {
-			error("Unexpected PBAP pullphonebook app"
-					" length, tag %d, len %d",
-					hdr->tag, hdr->len);
-			return;
-		}
+	g_obex_apparam_get_uint16(apparam, PHONEBOOKSIZE_TAG,
+							phone_book_size);
+	g_obex_apparam_get_uint8(apparam, NEWMISSEDCALLS_TAG,
+							new_missed_calls);
 
-		switch (hdr->tag) {
-		case PHONEBOOKSIZE_TAG:
-			if (hdr->len == PHONEBOOKSIZE_LEN) {
-				guint16 val;
-				memcpy(&val, hdr->val, sizeof(val));
-				*phone_book_size = get_be16(&val);
-			}
-			break;
-		case NEWMISSEDCALLS_TAG:
-			if (hdr->len == NEWMISSEDCALLS_LEN)
-				*new_missed_calls = hdr->val[0];
-			break;
-		default:
-			error("Unexpected PBAP pullphonebook app"
-					" parameter, tag %d, len %d",
-					hdr->tag, hdr->len);
-		}
 
-		size -= APPARAM_HDR_SIZE + hdr->len;
-		hdr += APPARAM_HDR_SIZE + hdr->len;
-	}
+	g_obex_apparam_free(apparam);
 }
 
 static void phonebook_size_callback(struct obc_session *session,
@@ -425,25 +362,21 @@ static struct obc_transfer *pull_phonebook(struct pbap_data *pbap,
 {
 	struct pending_request *request;
 	struct obc_transfer *transfer;
-	struct pullphonebook_apparam apparam;
+	GObexApparam *apparam;
+	guint8 buf[32];
+	gsize len;
 	session_callback_t func;
 
 	transfer = obc_transfer_get("x-bt/phonebook", name, targetfile, err);
 	if (transfer == NULL)
 		return NULL;
 
-	apparam.filter_tag = FILTER_TAG;
-	apparam.filter_len = FILTER_LEN;
-	apparam.filter = GUINT64_TO_BE(filter);
-	apparam.format_tag = FORMAT_TAG;
-	apparam.format_len = FORMAT_LEN;
-	apparam.format = format;
-	apparam.maxlistcount_tag = MAXLISTCOUNT_TAG;
-	apparam.maxlistcount_len = MAXLISTCOUNT_LEN;
-	apparam.maxlistcount = GUINT16_TO_BE(maxlistcount);
-	apparam.liststartoffset_tag = LISTSTARTOFFSET_TAG;
-	apparam.liststartoffset_len = LISTSTARTOFFSET_LEN;
-	apparam.liststartoffset = GUINT16_TO_BE(liststartoffset);
+	apparam = g_obex_apparam_set_uint64(NULL, FILTER_TAG, filter);
+	apparam = g_obex_apparam_set_uint8(apparam, FORMAT_TAG, format);
+	apparam = g_obex_apparam_set_uint16(apparam, MAXLISTCOUNT_TAG,
+							maxlistcount);
+	apparam = g_obex_apparam_set_uint16(apparam, LISTSTARTOFFSET_TAG,
+							liststartoffset);
 
 	switch (type) {
 	case PULLPHONEBOOK:
@@ -459,7 +392,11 @@ static struct obc_transfer *pull_phonebook(struct pbap_data *pbap,
 		return NULL;
 	}
 
-	obc_transfer_set_params(transfer, &apparam, sizeof(apparam));
+	len = g_obex_apparam_encode(apparam, buf, sizeof(buf));
+
+	obc_transfer_set_params(transfer, buf, len);
+
+	g_obex_apparam_free(apparam);
 
 	if (!obc_session_queue(pbap->session, transfer, func, request, err)) {
 		if (request != NULL)
@@ -472,18 +409,6 @@ static struct obc_transfer *pull_phonebook(struct pbap_data *pbap,
 	return transfer;
 }
 
-static guint8 *fill_apparam(guint8 *dest, void *buf, guint8 tag, guint8 len)
-{
-	if (dest && buf) {
-		*dest++ = tag;
-		*dest++ = len;
-		memcpy(dest, buf, len);
-		dest += len;
-	}
-
-	return dest;
-}
-
 static DBusMessage *pull_vcard_listing(struct pbap_data *pbap,
 					DBusMessage *message, const char *name,
 					guint8 order, char *searchval, guint8 attrib,
@@ -491,41 +416,31 @@ static DBusMessage *pull_vcard_listing(struct pbap_data *pbap,
 {
 	struct pending_request *request;
 	struct obc_transfer *transfer;
-	guint8 *p, apparam[272];
-	gint apparam_size;
+	guint8 buf[272];
+	gsize len;
 	GError *err = NULL;
+	GObexApparam *apparam;
 	DBusMessage *reply;
 
 	transfer = obc_transfer_get("x-bt/vcard-listing", name, NULL, &err);
 	if (transfer == NULL)
 		goto fail;
 
-	/* trunc the searchval string if it's length exceed the max value of guint8 */
-	if (strlen(searchval) > 254)
-		searchval[255] = '\0';
-
-	apparam_size = APPARAM_HDR_SIZE + ORDER_LEN +
-			(APPARAM_HDR_SIZE + strlen(searchval) + 1) +
-			(APPARAM_HDR_SIZE + SEARCHATTRIB_LEN) +
-			(APPARAM_HDR_SIZE + MAXLISTCOUNT_LEN) +
-			(APPARAM_HDR_SIZE + LISTSTARTOFFSET_LEN);
-
-	p = apparam;
+	apparam = g_obex_apparam_set_uint8(NULL, ORDER_TAG, order);
+	apparam = g_obex_apparam_set_uint8(apparam, SEARCHATTRIB_TAG, attrib);
+	apparam = g_obex_apparam_set_string(apparam, SEARCHVALUE_TAG,
+								searchval);
+	apparam = g_obex_apparam_set_uint16(apparam, MAXLISTCOUNT_TAG, count);
+	apparam = g_obex_apparam_set_uint16(apparam, LISTSTARTOFFSET_TAG,
+								offset);
 
-	p = fill_apparam(p, &order, ORDER_TAG, ORDER_LEN);
-	p = fill_apparam(p, searchval, SEARCHVALUE_TAG, strlen(searchval) + 1);
-	p = fill_apparam(p, &attrib, SEARCHATTRIB_TAG, SEARCHATTRIB_LEN);
+	len = g_obex_apparam_encode(apparam, buf, sizeof(buf));
 
-	count = GUINT16_TO_BE(count);
-	p = fill_apparam(p, &count, MAXLISTCOUNT_TAG, MAXLISTCOUNT_LEN);
+	obc_transfer_set_params(transfer, buf, len);
 
-	offset = GUINT16_TO_BE(offset);
-	fill_apparam(p, &offset, LISTSTARTOFFSET_TAG, LISTSTARTOFFSET_LEN);
+	g_obex_apparam_free(apparam);
 
 	request = pending_request_new(pbap, message);
-
-	obc_transfer_set_params(transfer, apparam, apparam_size);
-
 	if (obc_session_queue(pbap->session, transfer,
 				pull_vcard_listing_callback, request, &err))
 		return NULL;
@@ -739,7 +654,9 @@ static DBusMessage *pbap_pull_vcard(DBusConnection *connection,
 {
 	struct pbap_data *pbap = user_data;
 	struct obc_transfer *transfer;
-	struct pullvcardentry_apparam apparam;
+	GObexApparam *apparam;
+	guint8 buf[32];
+	gsize len;
 	const char *name, *targetfile;
 	DBusMessage *reply;
 	GError *err = NULL;
@@ -760,14 +677,14 @@ static DBusMessage *pbap_pull_vcard(DBusConnection *connection,
 	if (transfer == NULL)
 		goto fail;
 
-	apparam.filter_tag = FILTER_TAG;
-	apparam.filter_len = FILTER_LEN;
-	apparam.filter = GUINT64_TO_BE(pbap->filter);
-	apparam.format_tag = FORMAT_TAG;
-	apparam.format_len = FORMAT_LEN;
-	apparam.format = pbap->format;
+	apparam = g_obex_apparam_set_uint64(NULL, FILTER_TAG, pbap->filter);
+	apparam = g_obex_apparam_set_uint8(apparam, FORMAT_TAG, pbap->format);
+
+	len = g_obex_apparam_encode(apparam, buf, sizeof(buf));
+
+	obc_transfer_set_params(transfer, buf, len);
 
-	obc_transfer_set_params(transfer, &apparam, sizeof(apparam));
+	g_obex_apparam_free(apparam);
 
 	if (!obc_session_queue(pbap->session, transfer, NULL, NULL, &err))
 		goto fail;
-- 
1.7.11.2


^ permalink raw reply related

* [PATCH obexd 5/9] gobex: Add debug option to apparam
From: Luiz Augusto von Dentz @ 2012-08-09 10:32 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1344508353-24647-1-git-send-email-luiz.dentz@gmail.com>

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

This adds "apparam" to the debug options of GOBEX_DEBUG
---
 gobex/gobex-apparam.c | 43 ++++++++++++++++++++++++++++++++++++++++++-
 gobex/gobex-debug.h   |  7 ++++---
 gobex/gobex.c         | 11 ++++++-----
 3 files changed, 52 insertions(+), 9 deletions(-)

diff --git a/gobex/gobex-apparam.c b/gobex/gobex-apparam.c
index 09bf034..8f72aa7 100644
--- a/gobex/gobex-apparam.c
+++ b/gobex/gobex-apparam.c
@@ -28,6 +28,7 @@
 #include <errno.h>
 
 #include "gobex-apparam.h"
+#include "gobex-debug.h"
 
 struct _GObexApparam {
 	GHashTable *tags;
@@ -179,6 +180,8 @@ GObexApparam *g_obex_apparam_set_bytes(GObexApparam *apparam, guint8 id,
 GObexApparam *g_obex_apparam_set_uint8(GObexApparam *apparam, guint8 id,
 							guint8 value)
 {
+	g_obex_debug(G_OBEX_DEBUG_APPARAM, "tag 0x%02x value %u", id, value);
+
 	return g_obex_apparam_set_bytes(apparam, id, &value, 1);
 }
 
@@ -187,6 +190,8 @@ GObexApparam *g_obex_apparam_set_uint16(GObexApparam *apparam, guint8 id,
 {
 	guint16 num = g_htons(value);
 
+	g_obex_debug(G_OBEX_DEBUG_APPARAM, "tag 0x%02x value %u", id, value);
+
 	return g_obex_apparam_set_bytes(apparam, id, &num, 2);
 }
 
@@ -195,6 +200,8 @@ GObexApparam *g_obex_apparam_set_uint32(GObexApparam *apparam, guint8 id,
 {
 	guint32 num = g_htonl(value);
 
+	g_obex_debug(G_OBEX_DEBUG_APPARAM, "tag 0x%02x value %u", id, value);
+
 	return g_obex_apparam_set_bytes(apparam, id, &num, 4);
 }
 
@@ -203,6 +210,9 @@ GObexApparam *g_obex_apparam_set_uint64(GObexApparam *apparam, guint8 id,
 {
 	guint64 num = GUINT64_TO_BE(value);
 
+	g_obex_debug(G_OBEX_DEBUG_APPARAM, "tag 0x%02x value %"
+						G_GUINT64_FORMAT, id, value);
+
 	return g_obex_apparam_set_bytes(apparam, id, &num, 8);
 }
 
@@ -211,6 +221,8 @@ GObexApparam *g_obex_apparam_set_string(GObexApparam *apparam, guint8 id,
 {
 	gsize len;
 
+	g_obex_debug(G_OBEX_DEBUG_APPARAM, "tag 0x%02x value %s", id, value);
+
 	len = strlen(value) + 1;
 	if (len > G_MAXUINT8) {
 		((char *) value)[G_MAXUINT8 - 1] = '\0';
@@ -225,11 +237,16 @@ gboolean g_obex_apparam_get_uint8(GObexApparam *apparam, guint8 id,
 {
 	struct apparam_tag *tag;
 
+	g_obex_debug(G_OBEX_DEBUG_APPARAM, "tag 0x%02x", id);
+
 	tag = g_hash_table_lookup(apparam->tags, GUINT_TO_POINTER(id));
 	if (tag == NULL)
 		return FALSE;
 
 	*dest = tag->value.u8;
+
+	g_obex_debug(G_OBEX_DEBUG_APPARAM, "%u", *dest);
+
 	return TRUE;
 }
 
@@ -238,6 +255,8 @@ gboolean g_obex_apparam_get_uint16(GObexApparam *apparam, guint8 id,
 {
 	struct apparam_tag *tag;
 
+	g_obex_debug(G_OBEX_DEBUG_APPARAM, "tag 0x%02x", id);
+
 	tag = g_hash_table_lookup(apparam->tags, GUINT_TO_POINTER(id));
 	if (tag == NULL)
 		return FALSE;
@@ -246,6 +265,9 @@ gboolean g_obex_apparam_get_uint16(GObexApparam *apparam, guint8 id,
 		return FALSE;
 
 	*dest = g_ntohs(tag->value.u16);
+
+	g_obex_debug(G_OBEX_DEBUG_APPARAM, "%u", *dest);
+
 	return TRUE;
 }
 
@@ -254,6 +276,8 @@ gboolean g_obex_apparam_get_uint32(GObexApparam *apparam, guint8 id,
 {
 	struct apparam_tag *tag;
 
+	g_obex_debug(G_OBEX_DEBUG_APPARAM, "tag 0x%02x", id);
+
 	tag = g_hash_table_lookup(apparam->tags, GUINT_TO_POINTER(id));
 	if (tag == NULL)
 		return FALSE;
@@ -262,6 +286,9 @@ gboolean g_obex_apparam_get_uint32(GObexApparam *apparam, guint8 id,
 		return FALSE;
 
 	*dest = g_ntohl(tag->value.u32);
+
+	g_obex_debug(G_OBEX_DEBUG_APPARAM, "%u", *dest);
+
 	return TRUE;
 }
 
@@ -270,6 +297,8 @@ gboolean g_obex_apparam_get_uint64(GObexApparam *apparam, guint8 id,
 {
 	struct apparam_tag *tag;
 
+	g_obex_debug(G_OBEX_DEBUG_APPARAM, "tag 0x%02x", id);
+
 	tag = g_hash_table_lookup(apparam->tags, GUINT_TO_POINTER(id));
 	if (tag == NULL)
 		return FALSE;
@@ -278,18 +307,28 @@ gboolean g_obex_apparam_get_uint64(GObexApparam *apparam, guint8 id,
 		return FALSE;
 
 	*dest = GUINT64_FROM_BE(tag->value.u64);
+
+	g_obex_debug(G_OBEX_DEBUG_APPARAM, "%" G_GUINT64_FORMAT, *dest);
+
 	return TRUE;
 }
 
 char *g_obex_apparam_get_string(GObexApparam *apparam, guint8 id)
 {
 	struct apparam_tag *tag;
+	char *string;
+
+	g_obex_debug(G_OBEX_DEBUG_APPARAM, "tag 0x%02x", id);
 
 	tag = g_hash_table_lookup(apparam->tags, GUINT_TO_POINTER(id));
 	if (tag == NULL)
 		return NULL;
 
-	return g_strndup(tag->value.string, tag->len);
+	string = g_strndup(tag->value.string, tag->len);
+
+	g_obex_debug(G_OBEX_DEBUG_APPARAM, "%s", string);
+
+	return string;
 }
 
 gboolean g_obex_apparam_get_bytes(GObexApparam *apparam, guint8 id,
@@ -297,6 +336,8 @@ gboolean g_obex_apparam_get_bytes(GObexApparam *apparam, guint8 id,
 {
 	struct apparam_tag *tag;
 
+	g_obex_debug(G_OBEX_DEBUG_APPARAM, "tag 0x%02x", id);
+
 	tag = g_hash_table_lookup(apparam->tags, GUINT_TO_POINTER(id));
 	if (tag == NULL)
 		return FALSE;
diff --git a/gobex/gobex-debug.h b/gobex/gobex-debug.h
index 14faa10..14e2bcd 100644
--- a/gobex/gobex-debug.h
+++ b/gobex/gobex-debug.h
@@ -32,6 +32,7 @@
 #define G_OBEX_DEBUG_HEADER	(1 << 4)
 #define G_OBEX_DEBUG_PACKET	(1 << 5)
 #define G_OBEX_DEBUG_DATA	(1 << 6)
+#define G_OBEX_DEBUG_APPARAM	(1 << 7)
 
 extern guint gobex_debug;
 
@@ -40,13 +41,13 @@ extern guint gobex_debug;
 		g_log("gobex", G_LOG_LEVEL_DEBUG, "%s:%s() " format, __FILE__, \
 						__FUNCTION__, ## __VA_ARGS__)
 
-static inline void g_obex_dump(const char *prefix, const void *buf,
-								gsize len)
+static inline void g_obex_dump(guint level, const char *prefix,
+					const void *buf, gsize len)
 {
 	const guint8 *data = buf;
 	int n = 0;
 
-	if (!(gobex_debug & G_OBEX_DEBUG_DATA))
+	if (!(gobex_debug & level))
 		return;
 
 	while (len > 0) {
diff --git a/gobex/gobex.c b/gobex/gobex.c
index b6126b8..7c136af 100644
--- a/gobex/gobex.c
+++ b/gobex/gobex.c
@@ -267,7 +267,7 @@ static gboolean write_stream(GObex *obex, GError **err)
 	if (status != G_IO_STATUS_NORMAL)
 		return FALSE;
 
-	g_obex_dump("<", buf, bytes_written);
+	g_obex_dump(G_OBEX_DEBUG_DATA, "<", buf, bytes_written);
 
 	obex->tx_sent += bytes_written;
 	obex->tx_data -= bytes_written;
@@ -290,7 +290,7 @@ static gboolean write_packet(GObex *obex, GError **err)
 	if (bytes_written != obex->tx_data)
 		return FALSE;
 
-	g_obex_dump("<", buf, bytes_written);
+	g_obex_dump(G_OBEX_DEBUG_DATA, "<", buf, bytes_written);
 
 	obex->tx_sent += bytes_written;
 	obex->tx_data -= bytes_written;
@@ -1078,7 +1078,7 @@ read_body:
 	} while (rbytes > 0 && obex->rx_data < obex->rx_pkt_len);
 
 done:
-	g_obex_dump(">", obex->rx_buf, obex->rx_data);
+	g_obex_dump(G_OBEX_DEBUG_DATA, ">", obex->rx_buf, obex->rx_data);
 
 	return TRUE;
 }
@@ -1124,7 +1124,7 @@ static gboolean read_packet(GObex *obex, GError **err)
 		return FALSE;
 	}
 
-	g_obex_dump(">", obex->rx_buf, obex->rx_data);
+	g_obex_dump(G_OBEX_DEBUG_DATA, ">", obex->rx_buf, obex->rx_data);
 
 	return TRUE;
 fail:
@@ -1236,6 +1236,7 @@ static GDebugKey keys[] = {
 	{ "header",	G_OBEX_DEBUG_HEADER },
 	{ "packet",	G_OBEX_DEBUG_PACKET },
 	{ "data",	G_OBEX_DEBUG_DATA },
+	{ "apparam",	G_OBEX_DEBUG_APPARAM },
 };
 
 GObex *g_obex_new(GIOChannel *io, GObexTransportType transport_type,
@@ -1248,7 +1249,7 @@ GObex *g_obex_new(GIOChannel *io, GObexTransportType transport_type,
 		const char *env = g_getenv("GOBEX_DEBUG");
 
 		if (env) {
-			gobex_debug = g_parse_debug_string(env, keys, 6);
+			gobex_debug = g_parse_debug_string(env, keys, 7);
 			g_setenv("G_MESSAGES_DEBUG", "gobex", FALSE);
 		} else
 			gobex_debug = G_OBEX_DEBUG_NONE;
-- 
1.7.11.2


^ permalink raw reply related

* [PATCH obexd 4/9] gobex: Add unit test for encoding/decoding apparam headers
From: Luiz Augusto von Dentz @ 2012-08-09 10:32 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1344508353-24647-1-git-send-email-luiz.dentz@gmail.com>

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

---
 unit/test-gobex-header.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 46 insertions(+)

diff --git a/unit/test-gobex-header.c b/unit/test-gobex-header.c
index 86e69f3..feb7d17 100644
--- a/unit/test-gobex-header.c
+++ b/unit/test-gobex-header.c
@@ -47,6 +47,8 @@ static uint8_t hdr_bytes_nval_short[] = { G_OBEX_HDR_BODY, 0xab, 0xcd,
 						0x01, 0x02, 0x03 };
 static uint8_t hdr_bytes_nval_data[] = { G_OBEX_HDR_BODY, 0xab };
 static uint8_t hdr_bytes_nval_len[] = { G_OBEX_HDR_BODY, 0x00, 0x00 };
+static uint8_t hdr_apparam[] = { G_OBEX_HDR_APPARAM, 0x00, 0x09, 0x00, 0x04,
+						0x01, 0x02, 0x03, 0x04 };
 
 static void test_header_name_empty(void)
 {
@@ -115,6 +117,27 @@ static void test_header_bytes(void)
 	g_obex_header_free(header);
 }
 
+static void test_header_apparam(void)
+{
+	GObexHeader *header;
+	GObexApparam *apparam;
+	uint8_t buf[1024];
+	size_t len;
+
+	apparam = g_obex_apparam_set_uint32(NULL, 0, 0x01020304);
+	g_assert(apparam != NULL);
+
+	header = g_obex_header_new_apparam(apparam);
+	g_assert(header != NULL);
+
+	len = g_obex_header_encode(header, buf, sizeof(buf));
+
+	assert_memequal(hdr_apparam, sizeof(hdr_apparam), buf, len);
+
+	g_obex_apparam_free(apparam);
+	g_obex_header_free(header);
+}
+
 static void test_header_uint8(void)
 {
 	GObexHeader *header;
@@ -247,6 +270,26 @@ static void test_header_encode_body(void)
 	g_obex_header_free(header);
 }
 
+static void test_header_encode_apparam(void)
+{
+	GObexHeader *header;
+	GObexApparam *apparam;
+	gboolean ret;
+	guint32 data;
+
+	header = parse_and_encode(hdr_apparam, sizeof(hdr_apparam));
+
+	apparam = g_obex_header_get_apparam(header);
+	g_assert(apparam != NULL);
+
+	ret = g_obex_apparam_get_uint32(apparam, 0x00, &data);
+	g_assert(ret == TRUE);
+	g_assert(data == 0x01020304);
+
+	g_obex_apparam_free(apparam);
+	g_obex_header_free(header);
+}
+
 static void test_header_encode_actionid(void)
 {
 	GObexHeader *header;
@@ -507,6 +550,8 @@ int main(int argc, char *argv[])
 						test_header_encode_body);
 	g_test_add_func("/gobex/test_header_encode_connid",
 						test_header_encode_actionid);
+	g_test_add_func("/gobex/test_header_encode_apparam",
+						test_header_encode_apparam);
 
 	g_test_add_func("/gobex/test_header_name_empty",
 						test_header_name_empty);
@@ -517,6 +562,7 @@ int main(int argc, char *argv[])
 	g_test_add_func("/gobex/test_header_bytes", test_header_bytes);
 	g_test_add_func("/gobex/test_header_uint8", test_header_uint8);
 	g_test_add_func("/gobex/test_header_uint32", test_header_uint32);
+	g_test_add_func("/gobex/test_header_apparam", test_header_apparam);
 
 	g_test_run();
 
-- 
1.7.11.2


^ permalink raw reply related

* [PATCH obexd 3/9] gobex: Integrate GObexApparam with GObexHeader
From: Luiz Augusto von Dentz @ 2012-08-09 10:32 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1344508353-24647-1-git-send-email-luiz.dentz@gmail.com>

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

This introduce 2 new convenient functions: g_obex_header_get_apparam
which parses and decode an header into GObexApparam and
gobex_header_new_apparam that encode GObexApparam into GObexHeader.
---
 gobex/gobex-header.c | 25 +++++++++++++++++++++++++
 gobex/gobex-header.h |  3 +++
 2 files changed, 28 insertions(+)

diff --git a/gobex/gobex-header.c b/gobex/gobex-header.c
index 56dd9b2..80e8e4e 100644
--- a/gobex/gobex-header.c
+++ b/gobex/gobex-header.c
@@ -337,6 +337,19 @@ gboolean g_obex_header_get_bytes(GObexHeader *header, const guint8 **val,
 	return TRUE;
 }
 
+GObexApparam *g_obex_header_get_apparam(GObexHeader *header)
+{
+	gboolean ret;
+	const guint8 *val;
+	gsize len;
+
+	ret = g_obex_header_get_bytes(header, &val, &len);
+	if (!ret)
+		return NULL;
+
+	return g_obex_apparam_decode(val, len);
+}
+
 gboolean g_obex_header_get_uint8(GObexHeader *header, guint8 *val)
 {
 	g_obex_debug(G_OBEX_DEBUG_HEADER, "header 0x%02x",
@@ -411,6 +424,18 @@ GObexHeader *g_obex_header_new_bytes(guint8 id, const void *data, gsize len)
 	return header;
 }
 
+GObexHeader *g_obex_header_new_apparam(GObexApparam *apparam)
+{
+	guint8 buf[1024];
+	gssize len;
+
+	len = g_obex_apparam_encode(apparam, buf, sizeof(buf));
+	if (len < 0)
+		return NULL;
+
+	return g_obex_header_new_bytes(G_OBEX_HDR_APPARAM, buf, len);
+}
+
 GObexHeader *g_obex_header_new_uint8(guint8 id, guint8 val)
 {
 	GObexHeader *header;
diff --git a/gobex/gobex-header.h b/gobex/gobex-header.h
index 2ee8364..196cb20 100644
--- a/gobex/gobex-header.h
+++ b/gobex/gobex-header.h
@@ -25,6 +25,7 @@
 #include <glib.h>
 
 #include <gobex/gobex-defs.h>
+#include <gobex/gobex-apparam.h>
 
 /* Header ID's */
 #define G_OBEX_HDR_INVALID	0x00
@@ -77,11 +78,13 @@ gboolean g_obex_header_get_bytes(GObexHeader *header, const guint8 **val,
 								gsize *len);
 gboolean g_obex_header_get_uint8(GObexHeader *header, guint8 *val);
 gboolean g_obex_header_get_uint32(GObexHeader *header, guint32 *val);
+GObexApparam *g_obex_header_get_apparam(GObexHeader *header);
 
 GObexHeader *g_obex_header_new_unicode(guint8 id, const char *str);
 GObexHeader *g_obex_header_new_bytes(guint8 id, const void *data, gsize len);
 GObexHeader *g_obex_header_new_uint8(guint8 id, guint8 val);
 GObexHeader *g_obex_header_new_uint32(guint8 id, guint32 val);
+GObexHeader *g_obex_header_new_apparam(GObexApparam *apparam);
 
 GSList *g_obex_header_create_list(guint8 first_hdr_id, va_list args,
 							gsize *total_len);
-- 
1.7.11.2


^ permalink raw reply related

* [PATCH obexd 2/9] gobex: Add unit tests for GObexApparam API
From: Luiz Augusto von Dentz @ 2012-08-09 10:32 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1344508353-24647-1-git-send-email-luiz.dentz@gmail.com>

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

---
 Makefile.am               |  11 +-
 unit/test-gobex-apparam.c | 422 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 430 insertions(+), 3 deletions(-)
 create mode 100644 unit/test-gobex-apparam.c

diff --git a/Makefile.am b/Makefile.am
index a1b4da0..4757f60 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -166,11 +166,12 @@ plugins/phonebook.c: plugins/@PHONEBOOK_DRIVER@
 plugins/messages.c: plugins/@MESSAGES_DRIVER@
 	$(AM_V_GEN)$(LN_S) @abs_top_srcdir@/$< $@
 
-TESTS = unit/test-gobex-header unit/test-gobex-packet unit/test-gobex \
-						unit/test-gobex-transfer
+TESTS = unit/test-gobex-apparam unit/test-gobex-header unit/test-gobex-packet \
+				unit/test-gobex unit/test-gobex-transfer
 
 noinst_PROGRAMS += unit/test-gobex-header unit/test-gobex-packet \
-				unit/test-gobex unit/test-gobex-transfer
+			unit/test-gobex unit/test-gobex-transfer \
+			unit/test-gobex-apparam
 
 unit_test_gobex_SOURCES = $(gobex_sources) unit/test-gobex.c \
 							unit/util.c unit/util.h
@@ -188,6 +189,10 @@ unit_test_gobex_transfer_SOURCES = $(gobex_sources) unit/util.c unit/util.h \
 						unit/test-gobex-transfer.c
 unit_test_gobex_transfer_LDADD = @GLIB_LIBS@
 
+unit_test_gobex_apparam_SOURCES = $(gobex_sources) unit/util.c unit/util.h \
+						unit/test-gobex-apparam.c
+unit_test_gobex_apparam_LDADD = @GLIB_LIBS@
+
 if READLINE
 noinst_PROGRAMS += tools/test-client
 tools_test_client_SOURCES = $(gobex_sources) $(btio_sources) \
diff --git a/unit/test-gobex-apparam.c b/unit/test-gobex-apparam.c
new file mode 100644
index 0000000..573de99
--- /dev/null
+++ b/unit/test-gobex-apparam.c
@@ -0,0 +1,422 @@
+/*
+ *
+ *  OBEX library with GLib integration
+ *
+ *  Copyright (C) 2012  Intel Corporation.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  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 <stdint.h>
+#include <string.h>
+
+#include <gobex/gobex-apparam.h>
+
+#include "util.h"
+
+#define TAG_U8 0x00
+#define TAG_U16 0x01
+#define TAG_U32 0x02
+#define TAG_U64 0x03
+#define TAG_STRING 0x04
+#define TAG_BYTES 0x05
+
+static uint8_t tag_nval_short[] = { TAG_U8 };
+static uint8_t tag_nval_data[] = { TAG_U8, 0x01 };
+static uint8_t tag_nval2_short[] = { TAG_U8, 0x01, 0x1, TAG_U16 };
+static uint8_t tag_nval2_data[] = { TAG_U8, 0x01, 0x1, TAG_U16, 0x02 };
+static uint8_t tag_uint8[] = { TAG_U8, 0x01, 0x01 };
+static uint8_t tag_uint16[] = { TAG_U16, 0x02, 0x01, 0x02 };
+static uint8_t tag_uint32[] = { TAG_U32, 0x04, 0x01, 0x02, 0x03, 0x04 };
+static uint8_t tag_uint64[] = { TAG_U64, 0x08, 0x01, 0x02, 0x03, 0x04,
+						0x05, 0x06, 0x07, 0x08 };
+static uint8_t tag_string[] = { TAG_STRING, 0x04, 'A', 'B', 'C', '\0' };
+static uint8_t tag_bytes[257] = { TAG_BYTES, 0xFF };
+static uint8_t tag_multi[] = { TAG_U8, 0x01, 0x01,
+				TAG_U16, 0x02, 0x01, 0x02,
+				TAG_U32, 0x04, 0x01, 0x02, 0x03, 0x04,
+				TAG_U64, 0x08, 0x01, 0x02, 0x03, 0x04,
+						0x05, 0x06, 0x07, 0x08,
+				TAG_STRING, 0x04, 'A', 'B', 'C', '\0' };
+
+
+static GObexApparam *parse_and_decode(const void *data, gsize size)
+{
+	GObexApparam *apparam;
+	guint8 encoded[1024];
+	gsize len;
+
+	apparam = g_obex_apparam_decode(data, size);
+
+	g_assert(apparam != NULL);
+
+	len = g_obex_apparam_encode(apparam, encoded, sizeof(encoded));
+
+	assert_memequal(data, size, encoded, len);
+
+	return apparam;
+}
+
+static void test_apparam_nval_short(void)
+{
+	GObexApparam *apparam;
+
+	apparam = g_obex_apparam_decode(tag_nval_short,
+						sizeof(tag_nval_short));
+
+	g_assert(apparam == NULL);
+}
+
+static void test_apparam_nval_data(void)
+{
+	GObexApparam *apparam;
+
+	apparam = g_obex_apparam_decode(tag_nval_data,
+						sizeof(tag_nval_data));
+
+	g_assert(apparam == NULL);
+}
+
+static void test_apparam_nval2_short(void)
+{
+	GObexApparam *apparam;
+
+	apparam = g_obex_apparam_decode(tag_nval2_short,
+						sizeof(tag_nval2_short));
+
+	g_assert(apparam == NULL);
+}
+
+static void test_apparam_nval2_data(void)
+{
+	GObexApparam *apparam;
+
+	apparam = g_obex_apparam_decode(tag_nval2_data,
+						sizeof(tag_nval2_data));
+
+	g_assert(apparam == NULL);
+}
+
+static void test_apparam_get_uint8(void)
+{
+	GObexApparam *apparam;
+	guint8 data;
+	gboolean ret;
+
+	apparam = parse_and_decode(tag_uint8, sizeof(tag_uint8));
+
+	ret = g_obex_apparam_get_uint8(apparam, TAG_U8, &data);
+
+	g_assert(ret == TRUE);
+	g_assert(data == 0x01);
+
+	g_obex_apparam_free(apparam);
+}
+
+static void test_apparam_get_uint16(void)
+{
+	GObexApparam *apparam;
+	uint16_t data;
+	gboolean ret;
+
+	apparam = parse_and_decode(tag_uint16, sizeof(tag_uint16));
+
+	ret = g_obex_apparam_get_uint16(apparam, TAG_U16, &data);
+
+	g_assert(ret == TRUE);
+	g_assert(data == 0x0102);
+
+	g_obex_apparam_free(apparam);
+}
+
+static void test_apparam_get_uint32(void)
+{
+	GObexApparam *apparam;
+	uint32_t data;
+	gboolean ret;
+
+	apparam = parse_and_decode(tag_uint32, sizeof(tag_uint32));
+
+	ret = g_obex_apparam_get_uint32(apparam, TAG_U32, &data);
+
+	g_assert(ret == TRUE);
+	g_assert(data == 0x01020304);
+
+	g_obex_apparam_free(apparam);
+}
+
+static void test_apparam_get_uint64(void)
+{
+	GObexApparam *apparam;
+	uint64_t data;
+	gboolean ret;
+
+	apparam = parse_and_decode(tag_uint64, sizeof(tag_uint64));
+
+	ret = g_obex_apparam_get_uint64(apparam, TAG_U64, &data);
+
+	g_assert(ret == TRUE);
+	g_assert(data == 0x0102030405060708);
+
+	g_obex_apparam_free(apparam);
+}
+
+static void test_apparam_get_string(void)
+{
+	GObexApparam *apparam;
+	char *string;
+
+	apparam = parse_and_decode(tag_string, sizeof(tag_string));
+
+	string = g_obex_apparam_get_string(apparam, TAG_STRING);
+
+	g_assert(string != NULL);
+	g_assert_cmpstr(string, ==, "ABC");
+
+	g_free(string);
+	g_obex_apparam_free(apparam);
+}
+
+static void test_apparam_get_bytes(void)
+{
+	GObexApparam *apparam;
+	const uint8_t *data;
+	gsize len;
+	gboolean ret;
+
+	apparam = parse_and_decode(tag_bytes, sizeof(tag_bytes));
+
+	ret = g_obex_apparam_get_bytes(apparam, TAG_BYTES, &data, &len);
+
+	g_assert(ret == TRUE);
+	assert_memequal(tag_bytes + 2, sizeof(tag_bytes) - 2, data, len);
+
+	g_obex_apparam_free(apparam);
+}
+
+static void test_apparam_get_multi(void)
+{
+	GObexApparam *apparam;
+	char *string;
+	uint8_t data8;
+	uint16_t data16;
+	uint32_t data32;
+	uint64_t data64;
+	gboolean ret;
+
+	apparam = g_obex_apparam_decode(tag_multi, sizeof(tag_multi));
+
+	g_assert(apparam != NULL);
+
+	ret = g_obex_apparam_get_uint8(apparam, TAG_U8, &data8);
+
+	g_assert(ret == TRUE);
+	g_assert(data8 == 0x01);
+
+	ret = g_obex_apparam_get_uint16(apparam, TAG_U16, &data16);
+
+	g_assert(ret == TRUE);
+	g_assert(data16 == 0x0102);
+
+	ret = g_obex_apparam_get_uint32(apparam, TAG_U32, &data32);
+
+	g_assert(ret == TRUE);
+	g_assert(data32 == 0x01020304);
+
+	ret = g_obex_apparam_get_uint64(apparam, TAG_U64, &data64);
+
+	g_assert(ret == TRUE);
+	g_assert(data64 == 0x0102030405060708);
+
+	string = g_obex_apparam_get_string(apparam, TAG_STRING);
+
+	g_assert(string != NULL);
+	g_assert_cmpstr(string, ==, "ABC");
+
+	g_obex_apparam_free(apparam);
+}
+
+static void test_apparam_set_uint8(void)
+{
+	GObexApparam *apparam;
+	guint8 buf[1024];
+	gsize len;
+
+	apparam = g_obex_apparam_set_uint8(NULL, TAG_U8, 0x01);
+	g_assert(apparam != NULL);
+
+	len = g_obex_apparam_encode(apparam, buf, sizeof(buf));
+	assert_memequal(tag_uint8, sizeof(tag_uint8), buf, len);
+
+	g_obex_apparam_free(apparam);
+}
+
+static void test_apparam_set_uint16(void)
+{
+	GObexApparam *apparam;
+	guint8 buf[1024];
+	gsize len;
+
+	apparam = g_obex_apparam_set_uint16(NULL, TAG_U16, 0x0102);
+	g_assert(apparam != NULL);
+
+	len = g_obex_apparam_encode(apparam, buf, sizeof(buf));
+	assert_memequal(tag_uint16, sizeof(tag_uint16), buf, len);
+
+	g_obex_apparam_free(apparam);
+}
+
+static void test_apparam_set_uint32(void)
+{
+	GObexApparam *apparam;
+	guint8 buf[1024];
+	gsize len;
+
+	apparam = g_obex_apparam_set_uint32(NULL, TAG_U32, 0x01020304);
+	g_assert(apparam != NULL);
+
+	len = g_obex_apparam_encode(apparam, buf, sizeof(buf));
+	assert_memequal(tag_uint32, sizeof(tag_uint32), buf, len);
+
+	g_obex_apparam_free(apparam);
+}
+
+static void test_apparam_set_uint64(void)
+{
+	GObexApparam *apparam;
+	guint8 buf[1024];
+	gsize len;
+
+	apparam = g_obex_apparam_set_uint64(NULL, TAG_U64, 0x0102030405060708);
+	g_assert(apparam != NULL);
+
+	len = g_obex_apparam_encode(apparam, buf, sizeof(buf));
+	assert_memequal(tag_uint64, sizeof(tag_uint64), buf, len);
+
+	g_obex_apparam_free(apparam);
+}
+
+static void test_apparam_set_string(void)
+{
+	GObexApparam *apparam;
+	guint8 buf[1024];
+	gsize len;
+
+	apparam = g_obex_apparam_set_string(NULL, TAG_STRING, "ABC");
+	g_assert(apparam != NULL);
+
+	len = g_obex_apparam_encode(apparam, buf, sizeof(buf));
+	assert_memequal(tag_string, sizeof(tag_string), buf, len);
+
+	g_obex_apparam_free(apparam);
+}
+
+static void test_apparam_set_bytes(void)
+{
+	GObexApparam *apparam;
+	guint8 buf[1024];
+	gsize len;
+
+	apparam = g_obex_apparam_set_bytes(NULL, TAG_BYTES, tag_bytes + 2, 255);
+	g_assert(apparam != NULL);
+
+	len = g_obex_apparam_encode(apparam, buf, sizeof(buf));
+	assert_memequal(tag_bytes, sizeof(tag_bytes), buf, len);
+
+	g_obex_apparam_free(apparam);
+}
+
+static void test_apparam_set_multi(void)
+{
+	GObexApparam *apparam;
+	guint8 buf[1024];
+	gsize len;
+
+	apparam = g_obex_apparam_set_uint8(NULL, TAG_U8, 0x01);
+
+	g_assert(apparam != NULL);
+
+	apparam = g_obex_apparam_set_uint16(apparam, TAG_U16, 0x0102);
+
+	g_assert(apparam != NULL);
+
+	apparam = g_obex_apparam_set_uint32(apparam, TAG_U32, 0x01020304);
+
+	g_assert(apparam != NULL);
+
+	apparam = g_obex_apparam_set_uint64(apparam, TAG_U64,
+							0x0102030405060708);
+
+	g_assert(apparam != NULL);
+
+	apparam = g_obex_apparam_set_string(apparam, TAG_STRING, "ABC");
+
+	g_assert(apparam != NULL);
+
+	len = g_obex_apparam_encode(apparam, buf, sizeof(buf));
+
+	g_assert_cmpuint(len, ==, sizeof(tag_multi));
+
+	g_obex_apparam_free(apparam);
+}
+
+int main(int argc, char *argv[])
+{
+	g_test_init(&argc, &argv, NULL);
+
+	g_test_add_func("/gobex/test_apparam_nval_short",
+						test_apparam_nval_short);
+	g_test_add_func("/gobex/test_apparam_nval_data",
+						test_apparam_nval_data);
+
+	g_test_add_func("/gobex/test_apparam_nval2_short",
+						test_apparam_nval2_short);
+	g_test_add_func("/gobex/test_apparam_nval2_data",
+						test_apparam_nval2_data);
+
+	g_test_add_func("/gobex/test_apparam_get_uint8",
+						test_apparam_get_uint8);
+	g_test_add_func("/gobex/test_apparam_get_uint16",
+						test_apparam_get_uint16);
+	g_test_add_func("/gobex/test_apparam_get_uint32",
+						test_apparam_get_uint32);
+	g_test_add_func("/gobex/test_apparam_get_uint64",
+						test_apparam_get_uint64);
+	g_test_add_func("/gobex/test_apparam_get_string",
+						test_apparam_get_string);
+	g_test_add_func("/gobex/test_apparam_get_bytes",
+						test_apparam_get_bytes);
+	g_test_add_func("/gobex/test_apparam_get_multi",
+						test_apparam_get_multi);
+
+	g_test_add_func("/gobex/test_apparam_set_uint8",
+						test_apparam_set_uint8);
+	g_test_add_func("/gobex/test_apparam_set_uint16",
+						test_apparam_set_uint16);
+	g_test_add_func("/gobex/test_apparam_set_uint32",
+						test_apparam_set_uint32);
+	g_test_add_func("/gobex/test_apparam_set_uint64",
+						test_apparam_set_uint64);
+	g_test_add_func("/gobex/test_apparam_set_string",
+						test_apparam_set_string);
+	g_test_add_func("/gobex/test_apparam_set_bytes",
+						test_apparam_set_bytes);
+	g_test_add_func("/gobex/test_apparam_set_multi",
+						test_apparam_set_multi);
+
+	g_test_run();
+
+	return 0;
+}
-- 
1.7.11.2


^ permalink raw reply related

* [PATCH obexd 1/9] gobex: Introduce GObexApparam API
From: Luiz Augusto von Dentz @ 2012-08-09 10:32 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1344508353-24647-1-git-send-email-luiz.dentz@gmail.com>

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

GObexApparam abstract the handling of application parameter tags, it
can be used to read/parse application parameter header data using
g_obex_apparam_get_* functions or to generate the data using
g_obex_apparam_set_*.
---
 Makefile.am           |   3 +-
 gobex/gobex-apparam.c | 314 ++++++++++++++++++++++++++++++++++++++++++++++++++
 gobex/gobex-apparam.h |  59 ++++++++++
 3 files changed, 375 insertions(+), 1 deletion(-)
 create mode 100644 gobex/gobex-apparam.c
 create mode 100644 gobex/gobex-apparam.h

diff --git a/Makefile.am b/Makefile.am
index 97a1553..a1b4da0 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -20,7 +20,8 @@ gobex_sources = gobex/gobex.h gobex/gobex.c \
 			gobex/gobex-defs.h gobex/gobex-defs.c \
 			gobex/gobex-packet.c gobex/gobex-packet.h \
 			gobex/gobex-header.c gobex/gobex-header.h \
-			gobex/gobex-transfer.c gobex/gobex-debug.h
+			gobex/gobex-transfer.c gobex/gobex-debug.h \
+			gobex/gobex-apparam.h gobex/gobex-apparam.c
 
 noinst_PROGRAMS =
 libexec_PROGRAMS =
diff --git a/gobex/gobex-apparam.c b/gobex/gobex-apparam.c
new file mode 100644
index 0000000..09bf034
--- /dev/null
+++ b/gobex/gobex-apparam.c
@@ -0,0 +1,314 @@
+/*
+ *
+ *  OBEX library with GLib integration
+ *
+ *  Copyright (C) 2012  Intel Corporation.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  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 <string.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "gobex-apparam.h"
+
+struct _GObexApparam {
+	GHashTable *tags;
+};
+
+struct apparam_tag {
+	guint8 id;
+	guint8 len;
+	union {
+		/* Data is stored in network order */
+		char string[0];
+		guint8 data[0];
+		guint8 u8;
+		guint16 u16;
+		guint32 u32;
+		guint64 u64;
+	} value;
+} __attribute__ ((packed));
+
+static struct apparam_tag *tag_new(guint8 id, guint8 len, const void *data)
+{
+	struct apparam_tag *tag;
+
+	tag = g_malloc0(2 + len);
+	tag->id = id;
+	tag->len = len;
+	memcpy(tag->value.data, data, len);
+
+	return tag;
+}
+
+static GObexApparam *g_obex_apparam_new(void)
+{
+	GObexApparam *apparam;
+
+	apparam = g_new0(GObexApparam, 1);
+	apparam->tags = g_hash_table_new_full(g_direct_hash, g_direct_equal,
+							NULL, g_free);
+
+	return apparam;
+}
+
+static struct apparam_tag *apparam_tag_decode(const void *data, gsize size,
+							gsize *parsed)
+{
+	struct apparam_tag *tag;
+	const guint8 *ptr = data;
+	guint8 id;
+	guint8 len;
+
+	if (size < 2)
+		return NULL;
+
+	id = ptr[0];
+	len = ptr[1];
+
+	if (len > size - 2)
+		return NULL;
+
+	tag = tag_new(id, len, ptr + 2);
+	if (tag == NULL)
+		return NULL;
+
+	*parsed = 2 + tag->len;
+
+	return tag;
+}
+
+GObexApparam *g_obex_apparam_decode(const void *data, gsize size)
+{
+	GObexApparam *apparam;
+	GHashTable *tags;
+	gsize count = 0;
+
+	if (size < 2)
+		return NULL;
+
+	apparam = g_obex_apparam_new();
+
+	tags = apparam->tags;
+	while (count < size) {
+		struct apparam_tag *tag;
+		gsize parsed;
+
+		tag = apparam_tag_decode(data + count, size - count, &parsed);
+		if (tag == NULL)
+			break;
+
+		g_hash_table_insert(tags, GUINT_TO_POINTER(tag->id), tag);
+
+		count += parsed;
+	}
+
+	if (count != size) {
+		g_obex_apparam_free(apparam);
+		return NULL;
+	}
+
+	return apparam;
+}
+
+static gssize tag_encode(struct apparam_tag *tag, void *buf, gsize len)
+{
+	gsize count = 2 + tag->len;
+
+	if (len < count)
+		return -ENOBUFS;
+
+	memcpy(buf, tag, count);
+
+	return count;
+}
+
+gssize g_obex_apparam_encode(GObexApparam *apparam, void *buf, gsize len)
+{
+	gsize count = 0;
+	gssize ret;
+	GHashTableIter iter;
+	gpointer key, value;
+
+	g_hash_table_iter_init(&iter, apparam->tags);
+	while (g_hash_table_iter_next(&iter, &key, &value)) {
+		struct apparam_tag *tag = value;
+
+		ret = tag_encode(tag, buf + count, len - count);
+		if (ret < 0)
+			return ret;
+
+		count += ret;
+	}
+
+	return count;
+}
+
+GObexApparam *g_obex_apparam_set_bytes(GObexApparam *apparam, guint8 id,
+						const void *value, gsize len)
+{
+	struct apparam_tag *tag;
+
+	if (apparam == NULL)
+		apparam = g_obex_apparam_new();
+
+	tag = tag_new(id, len, value);
+	g_hash_table_replace(apparam->tags, GUINT_TO_POINTER(id), tag);
+
+	return apparam;
+}
+
+GObexApparam *g_obex_apparam_set_uint8(GObexApparam *apparam, guint8 id,
+							guint8 value)
+{
+	return g_obex_apparam_set_bytes(apparam, id, &value, 1);
+}
+
+GObexApparam *g_obex_apparam_set_uint16(GObexApparam *apparam, guint8 id,
+							guint16 value)
+{
+	guint16 num = g_htons(value);
+
+	return g_obex_apparam_set_bytes(apparam, id, &num, 2);
+}
+
+GObexApparam *g_obex_apparam_set_uint32(GObexApparam *apparam, guint8 id,
+							guint32 value)
+{
+	guint32 num = g_htonl(value);
+
+	return g_obex_apparam_set_bytes(apparam, id, &num, 4);
+}
+
+GObexApparam *g_obex_apparam_set_uint64(GObexApparam *apparam, guint8 id,
+							guint64 value)
+{
+	guint64 num = GUINT64_TO_BE(value);
+
+	return g_obex_apparam_set_bytes(apparam, id, &num, 8);
+}
+
+GObexApparam *g_obex_apparam_set_string(GObexApparam *apparam, guint8 id,
+							const char *value)
+{
+	gsize len;
+
+	len = strlen(value) + 1;
+	if (len > G_MAXUINT8) {
+		((char *) value)[G_MAXUINT8 - 1] = '\0';
+		len = G_MAXUINT8;
+	}
+
+	return g_obex_apparam_set_bytes(apparam, id, value, len);
+}
+
+gboolean g_obex_apparam_get_uint8(GObexApparam *apparam, guint8 id,
+							guint8 *dest)
+{
+	struct apparam_tag *tag;
+
+	tag = g_hash_table_lookup(apparam->tags, GUINT_TO_POINTER(id));
+	if (tag == NULL)
+		return FALSE;
+
+	*dest = tag->value.u8;
+	return TRUE;
+}
+
+gboolean g_obex_apparam_get_uint16(GObexApparam *apparam, guint8 id,
+							guint16 *dest)
+{
+	struct apparam_tag *tag;
+
+	tag = g_hash_table_lookup(apparam->tags, GUINT_TO_POINTER(id));
+	if (tag == NULL)
+		return FALSE;
+
+	if (tag->len < sizeof(*dest))
+		return FALSE;
+
+	*dest = g_ntohs(tag->value.u16);
+	return TRUE;
+}
+
+gboolean g_obex_apparam_get_uint32(GObexApparam *apparam, guint8 id,
+							guint32 *dest)
+{
+	struct apparam_tag *tag;
+
+	tag = g_hash_table_lookup(apparam->tags, GUINT_TO_POINTER(id));
+	if (tag == NULL)
+		return FALSE;
+
+	if (tag->len < sizeof(*dest))
+		return FALSE;
+
+	*dest = g_ntohl(tag->value.u32);
+	return TRUE;
+}
+
+gboolean g_obex_apparam_get_uint64(GObexApparam *apparam, guint8 id,
+							guint64 *dest)
+{
+	struct apparam_tag *tag;
+
+	tag = g_hash_table_lookup(apparam->tags, GUINT_TO_POINTER(id));
+	if (tag == NULL)
+		return FALSE;
+
+	if (tag->len < sizeof(*dest))
+		return FALSE;
+
+	*dest = GUINT64_FROM_BE(tag->value.u64);
+	return TRUE;
+}
+
+char *g_obex_apparam_get_string(GObexApparam *apparam, guint8 id)
+{
+	struct apparam_tag *tag;
+
+	tag = g_hash_table_lookup(apparam->tags, GUINT_TO_POINTER(id));
+	if (tag == NULL)
+		return NULL;
+
+	return g_strndup(tag->value.string, tag->len);
+}
+
+gboolean g_obex_apparam_get_bytes(GObexApparam *apparam, guint8 id,
+					const guint8 **val, gsize *len)
+{
+	struct apparam_tag *tag;
+
+	tag = g_hash_table_lookup(apparam->tags, GUINT_TO_POINTER(id));
+	if (tag == NULL)
+		return FALSE;
+
+	*len = tag->len;
+	*val = tag->value.data;
+
+	return TRUE;
+}
+
+void g_obex_apparam_free(GObexApparam *apparam)
+{
+	g_hash_table_unref(apparam->tags);
+	g_free(apparam);
+}
diff --git a/gobex/gobex-apparam.h b/gobex/gobex-apparam.h
new file mode 100644
index 0000000..46e20d2
--- /dev/null
+++ b/gobex/gobex-apparam.h
@@ -0,0 +1,59 @@
+/*
+ *
+ *  OBEX library with GLib integration
+ *
+ *  Copyright (C) 2012  Intel Corporation.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  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
+ *
+ */
+
+#ifndef __GOBEX_APPARAM_H
+#define __GOBEX_APPARAM_H
+
+#include <glib.h>
+
+typedef struct _GObexApparam GObexApparam;
+
+GObexApparam *g_obex_apparam_decode(const void *data, gsize size);
+gssize g_obex_apparam_encode(GObexApparam *apparam, void *buf, gsize size);
+
+GObexApparam *g_obex_apparam_set_bytes(GObexApparam *apparam, guint8 id,
+						const void *value, gsize size);
+GObexApparam *g_obex_apparam_set_uint8(GObexApparam *apparam, guint8 id,
+							guint8 value);
+GObexApparam *g_obex_apparam_set_uint16(GObexApparam *apparam, guint8 id,
+							guint16 value);
+GObexApparam *g_obex_apparam_set_uint32(GObexApparam *apparam, guint8 id,
+							guint32 value);
+GObexApparam *g_obex_apparam_set_uint64(GObexApparam *apparam, guint8 id,
+							guint64 value);
+GObexApparam *g_obex_apparam_set_string(GObexApparam *apparam, guint8 id,
+							const char *value);
+
+gboolean g_obex_apparam_get_bytes(GObexApparam *apparam, guint8 id,
+					const guint8 **val, gsize *len);
+gboolean g_obex_apparam_get_uint8(GObexApparam *apparam, guint8 id,
+							guint8 *value);
+gboolean g_obex_apparam_get_uint16(GObexApparam *apparam, guint8 id,
+							guint16 *value);
+gboolean g_obex_apparam_get_uint32(GObexApparam *apparam, guint8 id,
+							guint32 *value);
+gboolean g_obex_apparam_get_uint64(GObexApparam *apparam, guint8 id,
+							guint64 *value);
+char *g_obex_apparam_get_string(GObexApparam *apparam, guint8 id);
+
+void g_obex_apparam_free(GObexApparam *apparam);
+
+#endif /* __GOBEX_APPARAM_H */
-- 
1.7.11.2


^ permalink raw reply related

* [PATCH obexd 0/9] GObexApparam API
From: Luiz Augusto von Dentz @ 2012-08-09 10:32 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

GObexApparam can encode/decode OBEX application parameter in a generic
way, only the tags are expecific to each profile.

Some remarks:

  - Tag data is stored in network order/big endian because its type is
    not known.
  - Internally it uses a GHashTable to store the values which doesn't
    guarantee the order of the tag will be exact the same as inserted.

Luiz Augusto von Dentz (9):
  gobex: Introduce GObexApparam API
  gobex: Add unit tests for GObexApparam API
  gobex: Integrate GObexApparam with GObexHeader
  gobex: Add unit test for encoding/decoding apparam headers
  gobex: Add debug option to apparam
  client: Port PBAP module to use GObexApparam
  PBAP: Make use of GObexApparam API
  MAP: Make use of GObexApparam API
  core: Remove map_ap.c

 Makefile.am               |  18 +-
 client/pbap.c             | 181 +++++-------------
 gobex/gobex-apparam.c     | 355 +++++++++++++++++++++++++++++++++++
 gobex/gobex-apparam.h     |  59 ++++++
 gobex/gobex-debug.h       |   7 +-
 gobex/gobex-header.c      |  25 +++
 gobex/gobex-header.h      |   3 +
 gobex/gobex.c             |  11 +-
 plugins/mas.c             |  81 ++++----
 plugins/pbap.c            | 180 ++++--------------
 plugins/phonebook.h       |   2 +-
 src/map_ap.c              | 466 ----------------------------------------------
 src/map_ap.h              |  63 -------
 unit/test-gobex-apparam.c | 422 +++++++++++++++++++++++++++++++++++++++++
 unit/test-gobex-header.c  |  46 +++++
 15 files changed, 1058 insertions(+), 861 deletions(-)
 create mode 100644 gobex/gobex-apparam.c
 create mode 100644 gobex/gobex-apparam.h
 delete mode 100644 src/map_ap.c
 create mode 100644 unit/test-gobex-apparam.c

-- 
1.7.11.2


^ permalink raw reply

* Re: [PATCH 13/13] heartrate: Add Heart Rate test script
From: Santiago Carot @ 2012-08-09 10:18 UTC (permalink / raw)
  To: Rafal Garbat; +Cc: linux-bluetooth
In-Reply-To: <1344496816-4641-14-git-send-email-rafal.garbat@tieto.com>

Hi Rafa

2012/8/9 Rafal Garbat <rafal.garbat@tieto.com>:
> ---
>  Makefile.tools      |    4 +--
>  test/test-heartrate |   78 +++++++++++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 80 insertions(+), 2 deletions(-)
>  create mode 100755 test/test-heartrate
>
> diff --git a/Makefile.tools b/Makefile.tools
> index 5579b86..77b0a3f 100644
> --- a/Makefile.tools
> +++ b/Makefile.tools
> @@ -222,7 +222,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..35c97a8
> --- /dev/null
> +++ b/test/test-heartrate
> @@ -0,0 +1,78 @@
> +#!/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="a{sv}", out_signature="")
> +       def MeasurementReceived(self, measure):
> +               print("Measurement received")
> +               print("Value", measure["Value"])
> +               print("Energy", measure["Energy"])
> +               print("Contact", measure["Contact"])
> +               print("Location", measure["Location"])
> +
> +               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()
> +

This is just an idea, but it would be great to have an option here
which enables you to reset the device from command line, just for
testing. This option could be similar to EnableIntermediateMeasurement
in thermometer test script.

> +       if not options.address:
> +               print("Usage: %s [-i <adapter>] -b <bdaddr>" % (sys.argv[0]))
> +               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")
> +
> +       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")
> +
> +       path = "/test/watcher"
> +       watcher = Watcher(bus, path)
> +
> +       heartrate.RegisterWatcher(path)
> +
> +       properties = heartrate.GetProperties()
> +       print("Reset Supported:", properties["ResetSupported"])
> +
> +       mainloop = gobject.MainLoop()
> +       mainloop.run()
> \ No newline at end of file
> --
> 1.7.9.5
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply

* Re: [PATCH v17 01/15] doc: Add telephony interface documents
From: Frederic Danis @ 2012-08-09 10:03 UTC (permalink / raw)
  To: Luiz Augusto von Dentz, Marcel Holtmann; +Cc: linux-bluetooth
In-Reply-To: <CABBYNZ+95Zx32T_Soz8Nms3reNcGpa3FsiyZpxS5zNzdsXhVvA@mail.gmail.com>

[-- Attachment #1: Type: text/plain, Size: 2468 bytes --]

Hello Marcel and Luiz,

On 06/08/2012 22:30, Luiz Augusto von Dentz wrote:
> Hi Marcel,
>
> On Sun, Aug 5, 2012 at 7:37 AM, Marcel Holtmann <marcel@holtmann.org> wrote:
>>> +org.bluez.TelephonyAgent using this new interface. This will setup a SDP record
>>> +for the profile and a RFCOMM server listening for incoming connection.
>>> +
>>> +When a new device is connected, NewConnection method of TelephonyAgent is
>>> +called. The telephony agent should reply to it after proper communication
>>> +establishment (directly for HSP or after SLC setup completes for HFP).
>>
>> We need to describe on how HFP 1.6 with wideband speech is handled as
>> well.
>
> I need to look in detail when the audio configuration is done in HFP
> 1.6, in any case a the transport object can be used to signal wideband
> speech which PulseAudio should be able to catch and setup sbc
> encoder/decoder, iirc the parameters are fixed so there is no need to
> negotiate parameters with the endpoint as in A2DP so oFono only need
> to know if the transport is capable of wideband speech or not.
>
>>> +Interaction with the audio component (i.e. PulseAudio) will be done through the
>>> +MediaTransport object (passed to telephony agent during NewConnection call).
>>
>> This is the one thing that is really unclear to me. How does this
>> actually help. The MediaTransport and TelephonyAgent should be
>> independent.
>
> They are mostly independent, oFono will never really acquire or
> anything like that, but there are some AT commands (+VGS,+VGM) that
> does notify PA about volume gain changes and as I said above it could
> be useful to notify about wideband speech in the same way.
>

It is also possible that telephony agent implements a TelephonyClient 
interface for each connection, object which should be returned by 
NewConnection method.
In this case BlueZ will listen to properties changes on this interface 
(like for remote volume change) or call SetProperty (when receiving 
volume change from PulseAudio).

As MediaTransport may change during wideband speech HFP session, due to 
codec re-negotiation, this architecture may simplify media transport code.

You can find attached design documentation and telephony interfaces APIs 
proposal for this new architecture.

What are your advices regarding this ?

Regards

Fred

-- 
Frederic Danis                            Open Source Technology Center
frederic.danis@intel.com                              Intel Corporation


[-- Attachment #2: audio-telephony-design-new.txt --]
[-- Type: text/plain, Size: 14532 bytes --]

Telephony Interface Design
**************************

Introduction
============

The aim of this document is to briefly describe the telephony interface which
will allow external application to implement telephony related profiles
(headset, handsfree, dial-up networking and sim access).


The goal
========

Previous version of headset code in BlueZ needs the implementation of an AT
parser for each modem target or external telephony application (Maemo, oFono)
which is not the aim of Bluez.

The telephony interface allows BlueZ to focus on Bluetooth communication part
(connection, disconnection, authentication, authorization) and let external
application (i.e. oFono) take charge of the Telephony tasks (AT parsing and
modem specific code).
This will allow code to be simpler, easier to maintain and debug in both BlueZ
and telephony application.


Design
======

External applications, which should implement AT parsing and telephony part
will have to register an org.bluez.TelephonyAgent using this new interface.
This will setup a SDP record for the profile and a RFCOMM server listening for
incoming connection.

When a new device is connected, NewConnection method of TelephonyAgent is
called. The telephony agent must reply with a TelephonyClient object after
proper communication establishment (after SLC setup completes for HFP, or
directly for other profiles).

For Headset and Handsfree profiles, the interaction with the audio component
(i.e. PulseAudio) will be done by listening to TelephonyClient properties
changes.


Flow charts
===========

Here is some flowcharts of interactions between BlueZ, telephony agent (oFono)
and audio component (PulseAudio):

        .....>  Bluetooth communication between headset and phone
        ----->  Dbus messages and signals

Outgoing SCO connection - HFP <= 1.5
------------------------------------

When PulseAudio needs to setup the audio connection it will call media
transport acquire method. This will perform a SCO connection and return the SCO
socket file descriptor to PulseAUdio.

	PulseAudio              BlueZ           HF/AG
	|                         |               |
	|    transport acquire    |               |
	|------------------------>|               |
	|                         |  connect SCO  |
	|                         |..............>|
	|      return SCO fd      |               |
	|<------------------------|               |
	|                         |               |

Incoming SCO connection - HFP <= 1.5
------------------------------------

On an incoming SCO connection the profile will change to playing state.
On reception of this state change, PulseAudio will call media transport acquire
method to retrieve the SCO socket file descriptor.

	PulseAudio              BlueZ           HF/AG
	|                         |               |
	|                         |  connect SCO  |
	|                         |<..............|
	|  state changed signal   |               |
	|<------------------------|               |
	|                         |               |
	|    transport acquire    |               |
	|------------------------>|               |
	|                         |               |
	|      return SCO fd      |               |
	|<------------------------|               |
	|                         |               |

Outgoing SCO connection - HFP AG - HFP v1.6
-------------------------------------------

On media transport acquire, the TelephonyClient is called to perform codec
negociation with the headset (if needed) and return the id of selected codec.
If current media transport does not use this codec it will be re-configured
with the correct one.
Then SCO link will be connected and its socket file descriptor will be returned
to PulseAudio.

	PulseAudio             BlueZ             oFono        HF
	|                        |                 |           |
	|   transport acquire    |                 |           |
	|----------------------->|                 |           |
	|                        |    get codec    |           |
	|                        |---------------->|           |
	|                        |                 |  +BCS:id  |
	|                        |                 |..........>|
	|                        |                 |           |
	|                        |                 | AT+BCS=id |
	|                        |                 |<..........|
	|                        |                 |           |
	|                        |                 |     OK    |
	|                        |                 |..........>|
	|                        | return codec id |           |
	|                        |<----------------|           |
	| re-configure Transport |                 |           |
	|        if needed       |                 |           |
	|<-----------------------|                 |           |
	|                        |         connect SCO         |
	|                        |............................>|
	|      return SCO fd     |                 |           |
	|<-----------------------|                 |           |
	|                        |                 |           |

Incoming SCO connection - HFP AG - HFP v1.6
-------------------------------------------

It is pretty the same here as for outgoing SCO connection, except that it is
started upon reception of AT+BCC from the headset.

	PulseAudio           BlueZ              oFono         HF
	|                      |                  |            |
	|                      |                  |   AT+BCC   |
	|                      |                  |<...........|
	|                      |                  |            |
	|                      |                  |     OK     |
	|                      |                  |...........>|
	|                      |    connection    |            |
	|                      | requested signal |            |
	|                      |<-----------------|            |
	| state changed signal |                  |            |
	|<---------------------|                  |            |
	|                      |                  |            |
	| /--------------------------------------------------\ |
	|/    Outgoing SCO connection - HFP AG - HFP v1.6     \|
	|\                                                    /|
	| \--------------------------------------------------/ |


Outgoing SCO connection - HFP HF - HFP v1.6
-------------------------------------------

On media transport acquire, the TelephonyClient is called to perform codec
negociation with the gateway (if needed) and return the id of selected codec.
If current media transport does not use this codec it will be re-configured
with the right one.
Then incoming SCO socket file descriptor will be returned to PulseAudio.

	PulseAudio             BlueZ             oFono        AG
	|                        |                 |           |
	|   transport acquire    |                 |           |
	|----------------------->|                 |           |
	|                        |    get codec    |           |
	|                        |---------------->|           |
	|                        |                 |  AT+BCC   |
	|                        |                 |..........>|
	|                        |                 |           |
	|                        |                 |     OK    |
	|                        |                 |<..........|
	|                        |                 |           |
	|                        |                 |  +BCS:id  |
	|                        |                 |<..........|
	|                        |                 |           |
	|                        |                 | AT+BCS=id |
	|                        |                 |..........>|
	|                        |                 |           |
	|                        |                 |     OK    |
	|                        |                 |<..........|
	|                        | return codec id |           |
	|                        |<----------------|           |
	| re-configure Transport |                 |           |
	|        if needed       |                 |           |
	|<-----------------------|                 |           |
	|                        |          connect SCO        |
	|                        |<............................|
	|      return SCO fd     |                 |           |
	|<-----------------------|                 |           |
	|                        |                 |           |

Incoming SCO connection - HFP HF - HFP v1.6
-------------------------------------------

When codec negotiation is completed, TelephonyClient will signal the
selected codec to BlueZ.
If current media transport does not use this codec it will be re-configured
with the correct one.
Next incoming SCO connection will change profile to playing state.
Upon reception of this state change, PulseAudio will call media transport
acquire method to retrieve the SCO socket file descriptor.

	PulseAudio             BlueZ             oFono        AG
	|                        |                 |           |
	|                        |                 |  +BCS:id  |
	|                        |                 |<..........|
	|                        |                 |           |
	|                        |                 | AT+BCS=id |
	|                        |                 |..........>|
	|                        |                 |           |
	|                        |                 |     OK    |
	|                        |                 |<..........|
	|                        | codec property  |           |
	|                        | changed signal  |           |
	|                        |<----------------|           |
	| re-configure Transport |                 |           |
	|        if needed       |                 |           |
	|<-----------------------|                 |           |
	|                        |          connect SCO        |
	|                        |<............................|
	|  state changed signal  |                 |           |
	|<-----------------------|                 |           |
	|                        |                 |           |
	|   transport acquire    |                 |           |
	|----------------------->|                 |           |
	|                        |                 |           |
	|     return SCO fd      |                 |           |
	|<-----------------------|                 |           |
	|                        |                 |           |

AT+NREC - HFP AG
----------------

Reception of AT+NREC will be signaled to Bluez by TelephonyClient.
This will update the NREC property of media transport interface (listened by
PulseAudio).

	HF          oFono            BlueZ         PulseAudio
	|   AT+NREC   |                |                |
	|............>|                |                |
	|             |    property    |                |
	|             | changed signal |                |
	|             |--------------->|                |
	|     OK      |                |    property    |
	|<............|                | changed signal |
	|             |                |--------------->|
	|             |                |                |

+BSIR - HFP AG
--------------

PulseAudio can change in-band ring tone by calling SetProperty method of media
transport interface.
This will call SetProperty of TelephonyClient interface, which will send the
proper +BSIR unsollicited event.

	HF          oFono            BlueZ         PulseAudio        app
	|             |                |                |             |
	|             |                |                |<------------|
	|             |                |  SetProperty   |             |
	|             |                |<---------------|             |
	|             |  SetProperty   |                |             |
	|             |<---------------|                |             |
	|   +BSIR:x   |                |                |             |
	|<............|                |                |             |
	|             |    property    |                |             |
	|             | changed signal |                |             |
	|             |--------------->|                |             |
	|             |                |                |             |

AT+VGS,AT+VGM - HFP AG
----------------------

Reception of volume management command will be signaled to Bluez by
TelephonyClient.
This will update the corresponding volume property of media transport interface
(listened by PulseAudio).

	HF          oFono            BlueZ         PulseAudio        app
	|             |                |                |             |
	|  AT+VGS=xx  |                |                |             |
	|............>|                |                |             |
	|             |    property    |                |             |
	|             | changed signal |                |             |
	|             |--------------->|                |             |
	|     OK      |                |                |             |
	|<............|                |    property    |             |
	|             |                | changed signal |             |
	|             |                |--------------->|             |
	|             |                |                |------------>|
	|             |                |                |             |

+VGS,+VGM - HFP AG
------------------

PulseAudio can change volume by calling SetProperty method of media transport
interface.
This will call SetProperty of TelephonyClient interface, which will send the
proper +VGx unsollicited event.

	HF          oFono            BlueZ         PulseAudio        app
	|             |                |                |             |
	|             |                |                |<------------|
	|             |                |  SetProperty   |             |
	|             |                |<---------------|             |
	|             |  SetProperty   |                |             |
	|             |<---------------|                |             |
	|   +VGS:xx   |                |    property    |             |
	|<............|                | changed signal |             |
	|             |    property    |--------------->|             |
	|             | changed signal |                |------------>|
	|             |--------------->|                |             |
	|             |                |                |             |

[-- Attachment #3: audio-api-new.txt --]
[-- Type: text/plain, Size: 4333 bytes --]

Telephony hierarchy
===================

Service		org.bluez
Interface	org.bluez.Telephony
Object path	[variable prefix]/{hci0,hci1,...}

Methods		void RegisterAgent(object path, dict properties)

			Register a TelephonyAgent to sender, the sender can
			register as many agents as it likes.
			Object path should be unique for an agent and a UUID.

			Note: If the sender disconnects its agents are
			automatically unregistered.

			possible properties:

				string UUID:

					UUID of the profile which the agent is
					for.

				uint16 Version:

					Version of the profile which the agent
					implements.

				uint16 Features:

					Agent supported features as defined in
					profile spec e.g. HFP.

			Possible Errors: org.bluez.Error.InvalidArguments

		void UnregisterAgent(object path)

			Unregister sender agent.

		dict GetProperties()

			Returns all properties for the interface. See the
			properties section for available properties.

			Possible Errors: org.bluez.Error.InvalidArguments

		void SetProperty(string name, variant value)

			Changes the value of the specified property. Only
			properties that are listed as read-write are changeable.
			On success this will emit a PropertyChanged signal.

			Possible Errors: org.bluez.Error.DoesNotExist
					 org.bluez.Error.InvalidArguments

Signals		void PropertyChanged(string name, variant value)

			This signal indicates a changed value of the given
			property.

Properties	boolean FastConnectable  [readwrite]

			Indicates if there is adapter in fast connectable mode.

TelephonyAgent hierarchy
========================

Service		unique name
Interface	org.bluez.TelephonyAgent
Object path	freely definable

Methods		object NewConnection(filedescriptor fd, dict properties)

			Returns a TelephonyClient object for the connection.

			This method gets called whenever a new connection
			has been established. This method assumes that D-Bus
			daemon with file descriptor passing capability is
			being used.

			The agent should only return successfully once the
			establishment of the service level connection (SLC)
			has been completed.  In the case of Handsfree this
			means that BRSF exchange has been performed and
			necessary initialization has been done.

			possible properties:

				object Device:

					BlueZ remote device object.

				uint16 Version:

					Remote profile version.

				uint16 Features:

					Optional. Remote profile features.

				string Codecs:

					Optional. List of supported audio
					codec ids separeted by a comma.

			Possible Errors: org.bluez.Error.InvalidArguments
					 org.bluez.Error.Failed

		void Release()

			This method gets called whenever the service daemon
			unregisters the agent or whenever the Adapter where
			the TelephonyAgent registers itself is removed.

TelephonyClient hierarchy
========================

Service		unique name
Interface	org.bluez.TelephonyClient
Object path	freely definable

Methods		dict GetProperties()

			Returns all properties for the interface. See the
			properties section for available properties.

			Possible Errors: org.bluez.Error.InvalidArguments

		void SetProperty(string name, variant value)

			Changes the value of the specified property. Only
			properties that are listed as read-write are changeable.
			On success this will emit a PropertyChanged signal.

			Possible Errors: org.bluez.Error.DoesNotExist
					 org.bluez.Error.InvalidArguments

		byte GetAudioCodec()

			Returns the codec to use for upcoming audio connection.
			This may start a new codec negotiation if needed.

Signals		void PropertyChanged(string name, variant value)

			This signal indicates a changed value of the given
			property.

		void AudioConnectionRequested()

			This signal indicates that remote has requested an audio
			connection.

Properties	byte	AudioCodec [readonly]

			Optional. Indicates the currently selected audio codec.

		boolean NREC [readwrite]

			Optional. Indicates if echo cancelling and noise
			reduction functions are active.

		boolean InbandRingtone [readwrite]

			Optional. Indicates if sending ringtones is supported.

		uint16 OutputGain  [readwrite]

			Optional. The speaker gain when available.

			Possible values: 0-15

		uint16 InputGain  [readwrite]

			Optional. The microphone gain when available.

			Possible values: 0-15

^ permalink raw reply

* Re: [PATCH BlueZ V2 0/3] Remove remained local A2DP endpoints
From: Luiz Augusto von Dentz @ 2012-08-09  9:50 UTC (permalink / raw)
  To: chanyeol.park; +Cc: linux-bluetooth
In-Reply-To: <1344498344-19268-1-git-send-email-chanyeol.park@samsung.com>

Hi chanyeol,

On Thu, Aug 9, 2012 at 10:45 AM,  <chanyeol.park@samsung.com> wrote:
> From: Chan-yeol Park <chanyeol.park@samsung.com>
>
> Local A2DP endpoints(SBC,MPEG) are not used anymore.
> So references, structures, and functions related to them should be
> removed.
>
> Chan-yeol Park (3):
>   audio: Remove unused local A2DP endpoints reference
>   audio: Remove legacy SBC endpoint
>   audio: Remove legacy MPEG endpoint
>
>  audio/a2dp.c |  484 +---------------------------------------------------------
>  audio/a2dp.h |   99 ------------
>  2 files changed, 3 insertions(+), 580 deletions(-)
>
> --
> 1.7.9.5

All 3 patches are now upstream, thanks.

-- 
Luiz Augusto von Dentz

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox