All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/5] Put all gatttool global options in a unique struct
@ 2011-02-08 15:32 Sheldon Demario
  2011-02-08 15:32 ` [PATCH 2/5] Include check to readline lib on acinlude.m4 Sheldon Demario
                   ` (3 more replies)
  0 siblings, 4 replies; 20+ messages in thread
From: Sheldon Demario @ 2011-02-08 15:32 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Sheldon Demario

---
 attrib/gatttool.c |  186 +++++++++++++++++++++++++++++++----------------------
 1 files changed, 108 insertions(+), 78 deletions(-)

diff --git a/attrib/gatttool.c b/attrib/gatttool.c
index 8e8ed8e..c612309 100644
--- a/attrib/gatttool.c
+++ b/attrib/gatttool.c
@@ -46,32 +46,56 @@
 /* Minimum MTU for L2CAP connections over BR/EDR */
 #define ATT_MIN_MTU_L2CAP 48
 
-static gchar *opt_src = NULL;
-static gchar *opt_dst = NULL;
-static gchar *opt_value = NULL;
-static gchar *opt_sec_level = "low";
-static uuid_t *opt_uuid = NULL;
-static int opt_start = 0x0001;
-static int opt_end = 0xffff;
-static int opt_handle = -1;
-static int opt_mtu = 0;
-static int opt_psm = 0x1f;
-static gboolean opt_primary = FALSE;
-static gboolean opt_characteristics = FALSE;
-static gboolean opt_char_read = FALSE;
-static gboolean opt_listen = FALSE;
-static gboolean opt_char_desc = FALSE;
-static gboolean opt_le = FALSE;
-static gboolean opt_char_write = FALSE;
 static GMainLoop *event_loop;
 static gboolean got_error = FALSE;
 
+static struct main_opts {
+	gchar *src;
+	gchar *dst;
+	gchar *value;
+	gchar *sec_level;
+	uuid_t *uuid;
+	int start;
+	int end;
+	int handle;
+	int mtu;
+	int psm;
+	gboolean primary;
+	gboolean char_disc;
+	gboolean char_read;
+	gboolean listen;
+	gboolean char_desc;
+	gboolean le;
+	gboolean char_write;
+} main_opts;
+
 struct characteristic_data {
 	GAttrib *attrib;
 	uint16_t start;
 	uint16_t end;
 };
 
+static void options_init(void)
+{
+	main_opts.src = NULL;
+	main_opts.dst = NULL;
+	main_opts.value = NULL;
+	main_opts.sec_level = "low";
+	main_opts.uuid = NULL;
+	main_opts.start = 0x0001;
+	main_opts.end = 0xffff;
+	main_opts.handle = -1;
+	main_opts.mtu = 0;
+	main_opts.psm = 0x1f;
+	main_opts.primary = FALSE;
+	main_opts.char_disc = FALSE;
+	main_opts.char_read = FALSE;
+	main_opts.listen = FALSE;
+	main_opts.char_desc = FALSE;
+	main_opts.le = FALSE;
+	main_opts.char_write = FALSE;
+}
+
 static void connect_cb(GIOChannel *io, GError *err, gpointer user_data)
 {
 	if (err) {
@@ -90,31 +114,31 @@ static GIOChannel *do_connect(gboolean le)
 
 	/* This check is required because currently setsockopt() returns no
 	 * errors for MTU values smaller than the allowed minimum. */
-	if (opt_mtu != 0 && opt_mtu < ATT_MIN_MTU_L2CAP) {
+	if (main_opts.mtu != 0 && main_opts.mtu < ATT_MIN_MTU_L2CAP) {
 		g_printerr("MTU cannot be smaller than %d\n",
 							ATT_MIN_MTU_L2CAP);
 		return NULL;
 	}
 
 	/* Remote device */
-	if (opt_dst == NULL) {
+	if (main_opts.dst == NULL) {
 		g_printerr("Remote Bluetooth address required\n");
 		return NULL;
 	}
-	str2ba(opt_dst, &dba);
+	str2ba(main_opts.dst, &dba);
 
 	/* Local adapter */
-	if (opt_src != NULL) {
-		if (!strncmp(opt_src, "hci", 3))
-			hci_devba(atoi(opt_src + 3), &sba);
+	if (main_opts.src != NULL) {
+		if (!strncmp(main_opts.src, "hci", 3))
+			hci_devba(atoi(main_opts.src + 3), &sba);
 		else
-			str2ba(opt_src, &sba);
+			str2ba(main_opts.src, &sba);
 	} else
 		bacpy(&sba, BDADDR_ANY);
 
-	if (strcmp(opt_sec_level, "medium") == 0)
+	if (strcmp(main_opts.sec_level, "medium") == 0)
 		sec_level = BT_IO_SEC_MEDIUM;
-	else if (strcmp(opt_sec_level, "high") == 0)
+	else if (strcmp(main_opts.sec_level, "high") == 0)
 		sec_level = BT_IO_SEC_HIGH;
 	else
 		sec_level = BT_IO_SEC_LOW;
@@ -124,15 +148,15 @@ static GIOChannel *do_connect(gboolean le)
 				BT_IO_OPT_SOURCE_BDADDR, &sba,
 				BT_IO_OPT_DEST_BDADDR, &dba,
 				BT_IO_OPT_CID, GATT_CID,
-				BT_IO_OPT_OMTU, opt_mtu,
+				BT_IO_OPT_OMTU, main_opts.mtu,
 				BT_IO_OPT_SEC_LEVEL, sec_level,
 				BT_IO_OPT_INVALID);
 	else
 		chan = bt_io_connect(BT_IO_L2CAP, connect_cb, NULL, NULL, &err,
 				BT_IO_OPT_SOURCE_BDADDR, &sba,
 				BT_IO_OPT_DEST_BDADDR, &dba,
-				BT_IO_OPT_PSM, opt_psm,
-				BT_IO_OPT_OMTU, opt_mtu,
+				BT_IO_OPT_PSM, main_opts.psm,
+				BT_IO_OPT_OMTU, main_opts.mtu,
 				BT_IO_OPT_SEC_LEVEL, sec_level,
 				BT_IO_OPT_INVALID);
 
@@ -236,9 +260,9 @@ static gboolean primary(gpointer user_data)
 {
 	GAttrib *attrib = user_data;
 
-	if (opt_uuid)
-		gatt_discover_primary(attrib, opt_uuid, primary_by_uuid_cb,
-									NULL);
+	if (main_opts.uuid)
+		gatt_discover_primary(attrib, main_opts.uuid,
+						primary_by_uuid_cb, NULL);
 	else
 		gatt_discover_primary(attrib, NULL, primary_all_cb, NULL);
 
@@ -272,7 +296,8 @@ static gboolean characteristics(gpointer user_data)
 {
 	GAttrib *attrib = user_data;
 
-	gatt_discover_char(attrib, opt_start, opt_end, char_discovered_cb, NULL);
+	gatt_discover_char(attrib, main_opts.start, main_opts.end,
+						char_discovered_cb, NULL);
 
 	return FALSE;
 }
@@ -298,7 +323,7 @@ static void char_read_cb(guint8 status, const guint8 *pdu, guint16 plen,
 	g_print("\n");
 
 done:
-	if (opt_listen == FALSE)
+	if (main_opts.listen == FALSE)
 		g_main_loop_quit(event_loop);
 }
 
@@ -310,7 +335,7 @@ static void char_read_by_uuid_cb(guint8 status, const guint8 *pdu,
 	int i;
 
 	if (status == ATT_ECODE_ATTR_NOT_FOUND &&
-					char_data->start != opt_start)
+					char_data->start != main_opts.start)
 		goto done;
 
 	if (status != 0) {
@@ -339,7 +364,7 @@ static void char_read_by_uuid_cb(guint8 status, const guint8 *pdu,
 	att_data_list_free(list);
 
 	gatt_read_char_by_uuid(char_data->attrib, char_data->start,
-					char_data->end, opt_uuid,
+					char_data->end, main_opts.uuid,
 					char_read_by_uuid_cb,
 					char_data);
 
@@ -353,27 +378,28 @@ static gboolean characteristics_read(gpointer user_data)
 {
 	GAttrib *attrib = user_data;
 
-	if (opt_uuid != NULL) {
+	if (main_opts.uuid != NULL) {
 		struct characteristic_data *char_data;
 
 		char_data = g_new(struct characteristic_data, 1);
 		char_data->attrib = attrib;
-		char_data->start = opt_start;
-		char_data->end = opt_end;
+		char_data->start = main_opts.start;
+		char_data->end = main_opts.end;
 
-		gatt_read_char_by_uuid(attrib, opt_start, opt_end, opt_uuid,
-						char_read_by_uuid_cb, char_data);
+		gatt_read_char_by_uuid(attrib, main_opts.start, main_opts.end,
+					main_opts.uuid, char_read_by_uuid_cb,
+					char_data);
 
 		return FALSE;
 	}
 
-	if (opt_handle <= 0) {
+	if (main_opts.handle <= 0) {
 		g_printerr("A valid handle is required\n");
 		g_main_loop_quit(event_loop);
 		return FALSE;
 	}
 
-	gatt_read_char(attrib, opt_handle, char_read_cb, attrib);
+	gatt_read_char(attrib, main_opts.handle, char_read_cb, attrib);
 
 	return FALSE;
 }
@@ -411,23 +437,24 @@ static gboolean characteristics_write(gpointer user_data)
 	uint8_t *value;
 	size_t len;
 
-	if (opt_handle <= 0) {
+	if (main_opts.handle <= 0) {
 		g_printerr("A valid handle is required\n");
 		goto error;
 	}
 
-	if (opt_value == NULL || opt_value[0] == '\0') {
+	if (main_opts.value == NULL || main_opts.value[0] == '\0') {
 		g_printerr("A value is required\n");
 		goto error;
 	}
 
-	len = attr_data_from_string(opt_value, &value);
+	len = attr_data_from_string(main_opts.value, &value);
 	if (len == 0) {
 		g_printerr("Invalid value\n");
 		goto error;
 	}
 
-	gatt_write_cmd(attrib, opt_handle, value, len, mainloop_quit, value);
+	gatt_write_cmd(attrib, main_opts.handle, value, len, mainloop_quit,
+									value);
 
 	return FALSE;
 
@@ -474,7 +501,7 @@ static void char_desc_cb(guint8 status, const guint8 *pdu, guint16 plen,
 	att_data_list_free(list);
 
 done:
-	if (opt_listen == FALSE)
+	if (main_opts.listen == FALSE)
 		g_main_loop_quit(event_loop);
 }
 
@@ -482,7 +509,8 @@ static gboolean characteristics_desc(gpointer user_data)
 {
 	GAttrib *attrib = user_data;
 
-	gatt_find_info(attrib, opt_start, opt_end, char_desc_cb, NULL);
+	gatt_find_info(attrib, main_opts.start, main_opts.end,
+							char_desc_cb, NULL);
 
 	return FALSE;
 }
@@ -493,20 +521,20 @@ static gboolean parse_uuid(const char *key, const char *value,
 	if (!value)
 		return FALSE;
 
-	opt_uuid = g_try_malloc(sizeof(uuid_t));
-	if (opt_uuid == NULL)
+	main_opts.uuid = g_try_malloc(sizeof(uuid_t));
+	if (main_opts.uuid == NULL)
 		return FALSE;
 
-	if (bt_string2uuid(opt_uuid, value) < 0)
+	if (bt_string2uuid(main_opts.uuid, value) < 0)
 		return FALSE;
 
 	return TRUE;
 }
 
 static GOptionEntry primary_char_options[] = {
-	{ "start", 's' , 0, G_OPTION_ARG_INT, &opt_start,
+	{ "start", 's' , 0, G_OPTION_ARG_INT, &main_opts.start,
 		"Starting handle(optional)", "0x0001" },
-	{ "end", 'e' , 0, G_OPTION_ARG_INT, &opt_end,
+	{ "end", 'e' , 0, G_OPTION_ARG_INT, &main_opts.end,
 		"Ending handle(optional)", "0xffff" },
 	{ "uuid", 'u', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_CALLBACK,
 		parse_uuid, "UUID16 or UUID128(optional)", "0x1801"},
@@ -514,42 +542,42 @@ static GOptionEntry primary_char_options[] = {
 };
 
 static GOptionEntry char_rw_options[] = {
-	{ "handle", 'a' , 0, G_OPTION_ARG_INT, &opt_handle,
+	{ "handle", 'a' , 0, G_OPTION_ARG_INT, &main_opts.handle,
 		"Read/Write characteristic by handle(required)", "0x0001" },
-	{ "value", 'n' , 0, G_OPTION_ARG_STRING, &opt_value,
+	{ "value", 'n' , 0, G_OPTION_ARG_STRING, &main_opts.value,
 		"Write characteristic value (required for write operation)",
 		"0x0001" },
 	{NULL},
 };
 
 static GOptionEntry gatt_options[] = {
-	{ "primary", 0, 0, G_OPTION_ARG_NONE, &opt_primary,
+	{ "primary", 0, 0, G_OPTION_ARG_NONE, &main_opts.primary,
 		"Primary Service Discovery", NULL },
-	{ "characteristics", 0, 0, G_OPTION_ARG_NONE, &opt_characteristics,
+	{ "characteristics", 0, 0, G_OPTION_ARG_NONE, &main_opts.char_disc,
 		"Characteristics Discovery", NULL },
-	{ "char-read", 0, 0, G_OPTION_ARG_NONE, &opt_char_read,
+	{ "char-read", 0, 0, G_OPTION_ARG_NONE, &main_opts.char_read,
 		"Characteristics Value/Descriptor Read", NULL },
-	{ "char-write", 0, 0, G_OPTION_ARG_NONE, &opt_char_write,
+	{ "char-write", 0, 0, G_OPTION_ARG_NONE, &main_opts.char_write,
 		"Characteristics Value Write", NULL },
-	{ "char-desc", 0, 0, G_OPTION_ARG_NONE, &opt_char_desc,
+	{ "char-desc", 0, 0, G_OPTION_ARG_NONE, &main_opts.char_desc,
 		"Characteristics Descriptor Discovery", NULL },
-	{ "listen", 0, 0, G_OPTION_ARG_NONE, &opt_listen,
+	{ "listen", 0, 0, G_OPTION_ARG_NONE, &main_opts.listen,
 		"Listen for notifications and indications", NULL },
-	{ "le", 0, 0, G_OPTION_ARG_NONE, &opt_le,
+	{ "le", 0, 0, G_OPTION_ARG_NONE, &main_opts.le,
 		"Use Bluetooth Low Energy transport", NULL },
 	{ NULL },
 };
 
 static GOptionEntry options[] = {
-	{ "adapter", 'i', 0, G_OPTION_ARG_STRING, &opt_src,
+	{ "adapter", 'i', 0, G_OPTION_ARG_STRING, &main_opts.src,
 		"Specify local adapter interface", "hciX" },
-	{ "device", 'b', 0, G_OPTION_ARG_STRING, &opt_dst,
+	{ "device", 'b', 0, G_OPTION_ARG_STRING, &main_opts.dst,
 		"Specify remote Bluetooth address", "MAC" },
-	{ "mtu", 'm', 0, G_OPTION_ARG_INT, &opt_mtu,
+	{ "mtu", 'm', 0, G_OPTION_ARG_INT, &main_opts.mtu,
 		"Specify the MTU size", "MTU" },
-	{ "psm", 'p', 0, G_OPTION_ARG_INT, &opt_psm,
+	{ "psm", 'p', 0, G_OPTION_ARG_INT, &main_opts.psm,
 		"Specify the PSM for GATT/ATT over BR/EDR", "PSM" },
-	{ "sec-level", 'l', 0, G_OPTION_ARG_STRING, &opt_sec_level,
+	{ "sec-level", 'l', 0, G_OPTION_ARG_STRING, &main_opts.sec_level,
 		"Set security level. Default: low", "[low | medium | high]"},
 	{ NULL },
 };
@@ -563,6 +591,8 @@ int main(int argc, char *argv[])
 	GIOChannel *chan;
 	GSourceFunc callback;
 
+	options_init();
+
 	context = g_option_context_new(NULL);
 	g_option_context_add_main_entries(context, options, NULL);
 
@@ -594,15 +624,15 @@ int main(int argc, char *argv[])
 		g_error_free(gerr);
 	}
 
-	if (opt_primary)
+	if (main_opts.primary)
 		callback = primary;
-	else if (opt_characteristics)
+	else if (main_opts.char_disc)
 		callback = characteristics;
-	else if (opt_char_read)
+	else if (main_opts.char_read)
 		callback = characteristics_read;
-	else if (opt_char_write)
+	else if (main_opts.char_write)
 		callback = characteristics_write;
-	else if (opt_char_desc)
+	else if (main_opts.char_desc)
 		callback = characteristics_desc;
 	else {
 		gchar *help = g_option_context_get_help(context, TRUE, NULL);
@@ -612,7 +642,7 @@ int main(int argc, char *argv[])
 		goto done;
 	}
 
-	chan = do_connect(opt_le);
+	chan = do_connect(main_opts.le);
 	if (chan == NULL) {
 		got_error = TRUE;
 		goto done;
@@ -622,7 +652,7 @@ int main(int argc, char *argv[])
 
 	event_loop = g_main_loop_new(NULL, FALSE);
 
-	if (opt_listen)
+	if (main_opts.listen)
 		g_idle_add(listen_start, attrib);
 
 	g_idle_add(callback, attrib);
@@ -638,9 +668,9 @@ int main(int argc, char *argv[])
 
 done:
 	g_option_context_free(context);
-	g_free(opt_src);
-	g_free(opt_dst);
-	g_free(opt_uuid);
+	g_free(main_opts.src);
+	g_free(main_opts.dst);
+	g_free(main_opts.uuid);
 
 	if (got_error)
 		exit(EXIT_FAILURE);
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 2/5] Include check to readline lib on acinlude.m4
  2011-02-08 15:32 [PATCH 1/5] Put all gatttool global options in a unique struct Sheldon Demario
@ 2011-02-08 15:32 ` Sheldon Demario
  2011-02-08 15:32 ` [PATCH 3/5] Add an initial interactive mode to gatttool Sheldon Demario
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 20+ messages in thread
From: Sheldon Demario @ 2011-02-08 15:32 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Sheldon Demario

---
 acinclude.m4 |   10 ++++++++++
 1 files changed, 10 insertions(+), 0 deletions(-)

diff --git a/acinclude.m4 b/acinclude.m4
index 9d3f6b2..91e0956 100644
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -153,6 +153,15 @@ AC_DEFUN([AC_PATH_SNDFILE], [
 	AC_SUBST(SNDFILE_LIBS)
 ])
 
+AC_DEFUN([AC_PATH_READLINE], [
+	AC_CHECK_HEADER(readline/readline.h,
+		AC_CHECK_LIB(readline, main,
+			[ readline_found=yes
+			AC_SUBST(READLINE_LIBS, "-lreadline")
+			], readline_found=no),
+		[])
+])
+
 AC_DEFUN([AC_PATH_OUI], [
 	AC_ARG_WITH(ouifile,
 		    AS_HELP_STRING([--with-ouifile=PATH],[Path to the oui.txt file @<:@auto@:>@]),
@@ -356,6 +365,7 @@ AC_DEFUN([AC_ARG_BLUEZ], [
 	AM_CONDITIONAL(HEALTHPLUGIN, test "${health_enable}" = "yes")
 	AM_CONDITIONAL(MCAP, test "${health_enable}" = "yes")
 	AM_CONDITIONAL(HAL, test "${hal_enable}" = "yes")
+	AM_CONDITIONAL(READLINE, test "${readline_found}" = "yes")
 	AM_CONDITIONAL(ATTRIBPLUGIN, test "${attrib_enable}" = "yes")
 	AM_CONDITIONAL(ECHOPLUGIN, test "no" = "yes")
 	AM_CONDITIONAL(PNATPLUGIN, test "${pnat_enable}" = "yes")
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 3/5] Add an initial interactive mode to gatttool
  2011-02-08 15:32 [PATCH 1/5] Put all gatttool global options in a unique struct Sheldon Demario
  2011-02-08 15:32 ` [PATCH 2/5] Include check to readline lib on acinlude.m4 Sheldon Demario
@ 2011-02-08 15:32 ` Sheldon Demario
  2011-02-09 21:26   ` Johan Hedberg
  2011-02-08 15:32 ` [PATCH 4/5] Move main_opts from gatttool.c to header file Sheldon Demario
  2011-02-08 15:32 ` [PATCH 5/5] Add connect/disconnect options on interactive mode of gatttool Sheldon Demario
  3 siblings, 1 reply; 20+ messages in thread
From: Sheldon Demario @ 2011-02-08 15:32 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Sheldon Demario

Mode required to allow better GATT procedures control. Some scenarios
require sequential commands without disconnection and delay between
operations. It is also desirable to change some connection parameters
of an active connection.
---
 Makefile.am        |    8 ++-
 attrib/gatttool.c  |    9 ++++
 attrib/gatttool.h  |   24 ++++++++++
 attrib/igatttool.c |  129 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 configure.ac       |    1 +
 5 files changed, 169 insertions(+), 2 deletions(-)
 create mode 100644 attrib/gatttool.h
 create mode 100644 attrib/igatttool.c

diff --git a/Makefile.am b/Makefile.am
index e6639a7..ee3cd82 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -175,12 +175,16 @@ builtin_sources += plugins/service.c
 endif
 
 if ATTRIBPLUGIN
+
+if READLINE
 bin_PROGRAMS += attrib/gatttool
 
 attrib_gatttool_SOURCES = attrib/gatttool.c attrib/att.c attrib/gatt.c \
 			  attrib/gattrib.c btio/btio.c \
-			  src/glib-helper.h src/glib-helper.c
-attrib_gatttool_LDADD = lib/libbluetooth.la @GLIB_LIBS@
+			  src/glib-helper.h src/glib-helper.c \
+			  attrib/gatttool.h attrib/igatttool.c
+attrib_gatttool_LDADD = lib/libbluetooth.la @GLIB_LIBS@ @READLINE_LIBS@
+endif
 
 builtin_modules += attrib
 builtin_sources += attrib/main.c \
diff --git a/attrib/gatttool.c b/attrib/gatttool.c
index c612309..3eb3b0b 100644
--- a/attrib/gatttool.c
+++ b/attrib/gatttool.c
@@ -42,6 +42,7 @@
 #include "gattrib.h"
 #include "glib-helper.h"
 #include "gatt.h"
+#include "gatttool.h"
 
 /* Minimum MTU for L2CAP connections over BR/EDR */
 #define ATT_MIN_MTU_L2CAP 48
@@ -67,6 +68,7 @@ static struct main_opts {
 	gboolean char_desc;
 	gboolean le;
 	gboolean char_write;
+	gboolean interactive;
 } main_opts;
 
 struct characteristic_data {
@@ -565,6 +567,8 @@ static GOptionEntry gatt_options[] = {
 		"Listen for notifications and indications", NULL },
 	{ "le", 0, 0, G_OPTION_ARG_NONE, &main_opts.le,
 		"Use Bluetooth Low Energy transport", NULL },
+	{ "interactive", 'I', G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_NONE,
+		&main_opts.interactive, "Use interactive mode", NULL },
 	{ NULL },
 };
 
@@ -624,6 +628,11 @@ int main(int argc, char *argv[])
 		g_error_free(gerr);
 	}
 
+	if (main_opts.interactive) {
+		do_interactive();
+		goto done;
+	}
+
 	if (main_opts.primary)
 		callback = primary;
 	else if (main_opts.char_disc)
diff --git a/attrib/gatttool.h b/attrib/gatttool.h
new file mode 100644
index 0000000..9190730
--- /dev/null
+++ b/attrib/gatttool.h
@@ -0,0 +1,24 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 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
+ *
+ */
+
+int do_interactive(void);
diff --git a/attrib/igatttool.c b/attrib/igatttool.c
new file mode 100644
index 0000000..cac97f0
--- /dev/null
+++ b/attrib/igatttool.c
@@ -0,0 +1,129 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 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
+ *
+ */
+#include <strings.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <glib.h>
+
+#include <readline/readline.h>
+#include <readline/history.h>
+
+#include "gatttool.h"
+
+static GMainLoop *event_loop;
+
+static void cmd_help(int argcp, char **argvp);
+static void cmd_exit(int argcp, char **argvp);
+
+static struct {
+	const char *cmd;
+	void (*func)(int argcp, char **argvp);
+	const char *desc;
+} commands[] = {
+	{ "help",	cmd_help,	"Show this help"},
+	{ "exit",	cmd_exit,	"Exit interactive mode"},
+	{ NULL, NULL, NULL}
+};
+
+static void cmd_help(int argcp, char **argvp)
+{
+	int i;
+
+	for (i = 0; commands[i].cmd; i++)
+		printf("%-12s\t%s\n", commands[i].cmd, commands[i].desc);
+}
+
+static void cmd_exit(int argcp, char **argvp)
+{
+	rl_callback_handler_remove();
+	g_main_loop_quit(event_loop);
+}
+
+static void parse_line(char *line_read)
+{
+	gchar **argvp;
+	int argcp;
+	int i;
+
+	if (line_read == NULL) {
+		printf("\n");
+		cmd_exit(0, NULL);
+		return;
+	}
+
+	line_read = g_strstrip(line_read);
+
+	if (*line_read == '\0')
+		return;
+
+	add_history(line_read);
+
+	g_shell_parse_argv(line_read, &argcp, &argvp, NULL);
+
+	for (i = 0; commands[i].cmd; i++)
+		if (strcasecmp(commands[i].cmd, argvp[0]) == 0)
+			break;
+
+	if (commands[i].cmd)
+		commands[i].func(argcp, argvp);
+	else
+		printf("%s: command not found\n", argvp[0]);
+
+	g_strfreev(argvp);
+}
+
+static gboolean prompt_read(GIOChannel *chan, GIOCondition cond,
+							gpointer user_data)
+{
+	if (cond & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) {
+		g_io_channel_unref(chan);
+		return FALSE;
+	}
+
+	rl_callback_read_char();
+
+	return TRUE;
+}
+
+int do_interactive(void)
+{
+	GIOChannel *pchan;
+	gint events;
+
+	event_loop = g_main_loop_new(NULL, FALSE);
+
+	pchan = g_io_channel_unix_new(fileno(stdin));
+	g_io_channel_set_close_on_unref(pchan, TRUE);
+	events = G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL;
+	g_io_add_watch(pchan, events, prompt_read, NULL);
+
+	rl_callback_handler_install("> ", parse_line);
+
+	g_main_loop_run(event_loop);
+
+	rl_callback_handler_remove();
+	g_io_channel_unref(pchan);
+	g_main_loop_unref(event_loop);
+
+	return 0;
+}
diff --git a/configure.ac b/configure.ac
index bebdc9c..a8e8fc6 100644
--- a/configure.ac
+++ b/configure.ac
@@ -42,6 +42,7 @@ AC_PATH_GSTREAMER
 AC_PATH_USB
 AC_PATH_SNDFILE
 AC_PATH_OUI
+AC_PATH_READLINE
 
 AC_ARG_BLUEZ
 
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 4/5] Move main_opts from gatttool.c to header file
  2011-02-08 15:32 [PATCH 1/5] Put all gatttool global options in a unique struct Sheldon Demario
  2011-02-08 15:32 ` [PATCH 2/5] Include check to readline lib on acinlude.m4 Sheldon Demario
  2011-02-08 15:32 ` [PATCH 3/5] Add an initial interactive mode to gatttool Sheldon Demario
@ 2011-02-08 15:32 ` Sheldon Demario
  2011-02-08 15:32 ` [PATCH 5/5] Add connect/disconnect options on interactive mode of gatttool Sheldon Demario
  3 siblings, 0 replies; 20+ messages in thread
From: Sheldon Demario @ 2011-02-08 15:32 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Sheldon Demario

---
 attrib/gatttool.c |   21 ---------------------
 attrib/gatttool.h |   21 +++++++++++++++++++++
 2 files changed, 21 insertions(+), 21 deletions(-)

diff --git a/attrib/gatttool.c b/attrib/gatttool.c
index 3eb3b0b..e0de05b 100644
--- a/attrib/gatttool.c
+++ b/attrib/gatttool.c
@@ -50,27 +50,6 @@
 static GMainLoop *event_loop;
 static gboolean got_error = FALSE;
 
-static struct main_opts {
-	gchar *src;
-	gchar *dst;
-	gchar *value;
-	gchar *sec_level;
-	uuid_t *uuid;
-	int start;
-	int end;
-	int handle;
-	int mtu;
-	int psm;
-	gboolean primary;
-	gboolean char_disc;
-	gboolean char_read;
-	gboolean listen;
-	gboolean char_desc;
-	gboolean le;
-	gboolean char_write;
-	gboolean interactive;
-} main_opts;
-
 struct characteristic_data {
 	GAttrib *attrib;
 	uint16_t start;
diff --git a/attrib/gatttool.h b/attrib/gatttool.h
index 9190730..0f78aa8 100644
--- a/attrib/gatttool.h
+++ b/attrib/gatttool.h
@@ -21,4 +21,25 @@
  *
  */
 
+struct main_opts {
+	gchar *src;
+	gchar *dst;
+	gchar *value;
+	gchar *sec_level;
+	uuid_t *uuid;
+	int start;
+	int end;
+	int handle;
+	int mtu;
+	int psm;
+	gboolean primary;
+	gboolean char_disc;
+	gboolean char_read;
+	gboolean listen;
+	gboolean char_desc;
+	gboolean le;
+	gboolean char_write;
+	gboolean interactive;
+} main_opts;
+
 int do_interactive(void);
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH 5/5] Add connect/disconnect options on interactive mode of gatttool
  2011-02-08 15:32 [PATCH 1/5] Put all gatttool global options in a unique struct Sheldon Demario
                   ` (2 preceding siblings ...)
  2011-02-08 15:32 ` [PATCH 4/5] Move main_opts from gatttool.c to header file Sheldon Demario
@ 2011-02-08 15:32 ` Sheldon Demario
  3 siblings, 0 replies; 20+ messages in thread
From: Sheldon Demario @ 2011-02-08 15:32 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Sheldon Demario

---
 attrib/gatttool.c  |    4 +-
 attrib/gatttool.h  |    1 +
 attrib/igatttool.c |  103 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 105 insertions(+), 3 deletions(-)

diff --git a/attrib/gatttool.c b/attrib/gatttool.c
index e0de05b..ac9bb60 100644
--- a/attrib/gatttool.c
+++ b/attrib/gatttool.c
@@ -86,7 +86,7 @@ static void connect_cb(GIOChannel *io, GError *err, gpointer user_data)
 	}
 }
 
-static GIOChannel *do_connect(gboolean le)
+GIOChannel *do_connect(gboolean le, BtIOConnect connect_cb)
 {
 	GIOChannel *chan;
 	bdaddr_t sba, dba;
@@ -630,7 +630,7 @@ int main(int argc, char *argv[])
 		goto done;
 	}
 
-	chan = do_connect(main_opts.le);
+	chan = do_connect(main_opts.le, connect_cb);
 	if (chan == NULL) {
 		got_error = TRUE;
 		goto done;
diff --git a/attrib/gatttool.h b/attrib/gatttool.h
index 0f78aa8..6fec2b0 100644
--- a/attrib/gatttool.h
+++ b/attrib/gatttool.h
@@ -43,3 +43,4 @@ struct main_opts {
 } main_opts;
 
 int do_interactive(void);
+GIOChannel *do_connect(gboolean le, BtIOConnect connect_cb);
diff --git a/attrib/igatttool.c b/attrib/igatttool.c
index cac97f0..fa014c3 100644
--- a/attrib/igatttool.c
+++ b/attrib/igatttool.c
@@ -25,15 +25,24 @@
 #include <stdio.h>
 #include <glib.h>
 
+#include <bluetooth/sdp.h>
+
 #include <readline/readline.h>
 #include <readline/history.h>
 
+#include "btio.h"
+#include "gattrib.h"
 #include "gatttool.h"
 
+static GIOChannel *iochannel = NULL;
+static GAttrib *attrib = NULL;
 static GMainLoop *event_loop;
+static GString *prompt;
 
 static void cmd_help(int argcp, char **argvp);
 static void cmd_exit(int argcp, char **argvp);
+static void cmd_connect(int argcp, char **argvp);
+static void cmd_disconnect(int argcp, char **argvp);
 
 static struct {
 	const char *cmd;
@@ -42,9 +51,62 @@ static struct {
 } commands[] = {
 	{ "help",	cmd_help,	"Show this help"},
 	{ "exit",	cmd_exit,	"Exit interactive mode"},
+	{ "connect",	cmd_connect,	"Connect to a remote device"},
+	{ "disconnect",	cmd_disconnect,	"Disconnect from a remote device"},
 	{ NULL, NULL, NULL}
 };
 
+enum state {
+	STATE_DISCONNECTED,
+	STATE_CONNECTING,
+	STATE_CONNECTED
+} conn_state;
+
+static char *get_prompt(void)
+{
+	if (conn_state == STATE_CONNECTING) {
+		g_string_assign(prompt, "Connecting... ");
+		return prompt->str;
+	}
+
+	if (conn_state == STATE_CONNECTED)
+		g_string_assign(prompt, "[CON]");
+	else
+		g_string_assign(prompt, "[   ]");
+
+	if (main_opts.dst)
+		g_string_append_printf(prompt, "[%17s]", main_opts.dst);
+	else
+		g_string_append_printf(prompt, "[%17s]", "");
+
+	if (main_opts.le)
+		g_string_append(prompt, "[LE]");
+	else
+		g_string_append(prompt, "[BR]");
+
+	g_string_append(prompt, "> ");
+
+	return prompt->str;
+}
+
+static void set_state(enum state st)
+{
+	conn_state = st;
+	rl_set_prompt(get_prompt());
+	rl_redisplay();
+}
+
+static void connect_cb(GIOChannel *io, GError *err, gpointer user_data)
+{
+	if (err) {
+		printf("connect error: %s\n", err->message);
+		return;
+	}
+
+	attrib = g_attrib_new(iochannel);
+	set_state(STATE_CONNECTED);
+}
+
 static void cmd_help(int argcp, char **argvp)
 {
 	int i;
@@ -59,6 +121,41 @@ static void cmd_exit(int argcp, char **argvp)
 	g_main_loop_quit(event_loop);
 }
 
+static void cmd_connect(int argcp, char **argvp)
+{
+	if (conn_state != STATE_DISCONNECTED)
+		return;
+
+	if (main_opts.dst == NULL) {
+		printf("Remote Bluetooth address required\n");
+		return;
+	}
+
+	set_state(STATE_CONNECTING);
+	iochannel = do_connect(main_opts.le, connect_cb);
+	if (iochannel == NULL)
+		set_state(STATE_DISCONNECTED);
+
+	return;
+}
+
+static void cmd_disconnect(int argcp, char **argvp)
+{
+	if (conn_state == STATE_DISCONNECTED)
+		return;
+
+	g_attrib_unref(attrib);
+	attrib = NULL;
+
+	g_io_channel_shutdown(iochannel, FALSE, NULL);
+	g_io_channel_unref(iochannel);
+	iochannel = NULL;
+
+	set_state(STATE_DISCONNECTED);
+
+	return;
+}
+
 static void parse_line(char *line_read)
 {
 	gchar **argvp;
@@ -110,6 +207,8 @@ int do_interactive(void)
 	GIOChannel *pchan;
 	gint events;
 
+	prompt = g_string_new(NULL);
+
 	event_loop = g_main_loop_new(NULL, FALSE);
 
 	pchan = g_io_channel_unix_new(fileno(stdin));
@@ -117,13 +216,15 @@ int do_interactive(void)
 	events = G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL;
 	g_io_add_watch(pchan, events, prompt_read, NULL);
 
-	rl_callback_handler_install("> ", parse_line);
+	rl_callback_handler_install(get_prompt(), parse_line);
 
 	g_main_loop_run(event_loop);
 
 	rl_callback_handler_remove();
+	cmd_disconnect(0, NULL);
 	g_io_channel_unref(pchan);
 	g_main_loop_unref(event_loop);
+	g_string_free(prompt, TRUE);
 
 	return 0;
 }
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* Re: [PATCH 3/5] Add an initial interactive mode to gatttool
  2011-02-08 15:32 ` [PATCH 3/5] Add an initial interactive mode to gatttool Sheldon Demario
@ 2011-02-09 21:26   ` Johan Hedberg
  2011-02-10 17:14     ` Sheldon Demario
                       ` (9 more replies)
  0 siblings, 10 replies; 20+ messages in thread
From: Johan Hedberg @ 2011-02-09 21:26 UTC (permalink / raw)
  To: Sheldon Demario; +Cc: linux-bluetooth

On Tue, Feb 08, 2011, Sheldon Demario wrote:
> +int do_interactive(void);

I don't really like having an exported function called do_*. The places
I've seen this naming convention have usually been when there's some
other function already with the name you want and in all places the do_
variant is static. How about simply interactive() or interactive_mode().
Also, shouldn't you be passing the minimum config options as parameters
to this function? Otherwise you'll have to have some sort of global
config variables.

> +++ b/attrib/igatttool.c

Since we don't have igattool anymore, how about calling this
interactive.c?

> +static void cmd_help(int argcp, char **argvp);
> +static void cmd_exit(int argcp, char **argvp);

No forward-declarations please. Just reorder the functions so that you
don't need to do this.

Johan

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 3/5] Add an initial interactive mode to gatttool
  2011-02-09 21:26   ` Johan Hedberg
@ 2011-02-10 17:14     ` Sheldon Demario
  2011-02-10 17:23       ` Johan Hedberg
  2011-02-11 14:17     ` [PATCH v2 1/5] Put all gatttool global options in a unique struct Sheldon Demario
                       ` (8 subsequent siblings)
  9 siblings, 1 reply; 20+ messages in thread
From: Sheldon Demario @ 2011-02-10 17:14 UTC (permalink / raw)
  To: Sheldon Demario, linux-bluetooth; +Cc: johan.hedberg

Hi Johan,

>> +static void cmd_help(int argcp, char **argvp);
>> +static void cmd_exit(int argcp, char **argvp);
>
> No forward-declarations please. Just reorder the functions so that you
> don't need to do this.

The problem is the cmd_help() function. It must be declared to be
known by commands[] array.
The commands[] array also must be known by cmd_help(), so what do you
suggest to solve this?

Sheldon

>
> Johan
>

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH 3/5] Add an initial interactive mode to gatttool
  2011-02-10 17:14     ` Sheldon Demario
@ 2011-02-10 17:23       ` Johan Hedberg
  0 siblings, 0 replies; 20+ messages in thread
From: Johan Hedberg @ 2011-02-10 17:23 UTC (permalink / raw)
  To: Sheldon Demario; +Cc: linux-bluetooth

Hi Sheldon,

On Thu, Feb 10, 2011, Sheldon Demario wrote:
> >> +static void cmd_help(int argcp, char **argvp);
> >> +static void cmd_exit(int argcp, char **argvp);
> >
> > No forward-declarations please. Just reorder the functions so that you
> > don't need to do this.
> 
> The problem is the cmd_help() function. It must be declared to be
> known by commands[] array.
> The commands[] array also must be known by cmd_help(), so what do you
> suggest to solve this?

For that one a forward-declaration is fine.

Johan

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH v2 1/5] Put all gatttool global options in a unique struct
  2011-02-09 21:26   ` Johan Hedberg
  2011-02-10 17:14     ` Sheldon Demario
@ 2011-02-11 14:17     ` Sheldon Demario
  2011-02-11 14:17     ` [PATCH v2 2/5] Include check to readline lib on acinlude.m4 Sheldon Demario
                       ` (7 subsequent siblings)
  9 siblings, 0 replies; 20+ messages in thread
From: Sheldon Demario @ 2011-02-11 14:17 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Sheldon Demario

---
 attrib/gatttool.c |  186 +++++++++++++++++++++++++++++++----------------------
 1 files changed, 108 insertions(+), 78 deletions(-)

diff --git a/attrib/gatttool.c b/attrib/gatttool.c
index 8e8ed8e..c612309 100644
--- a/attrib/gatttool.c
+++ b/attrib/gatttool.c
@@ -46,32 +46,56 @@
 /* Minimum MTU for L2CAP connections over BR/EDR */
 #define ATT_MIN_MTU_L2CAP 48
 
-static gchar *opt_src = NULL;
-static gchar *opt_dst = NULL;
-static gchar *opt_value = NULL;
-static gchar *opt_sec_level = "low";
-static uuid_t *opt_uuid = NULL;
-static int opt_start = 0x0001;
-static int opt_end = 0xffff;
-static int opt_handle = -1;
-static int opt_mtu = 0;
-static int opt_psm = 0x1f;
-static gboolean opt_primary = FALSE;
-static gboolean opt_characteristics = FALSE;
-static gboolean opt_char_read = FALSE;
-static gboolean opt_listen = FALSE;
-static gboolean opt_char_desc = FALSE;
-static gboolean opt_le = FALSE;
-static gboolean opt_char_write = FALSE;
 static GMainLoop *event_loop;
 static gboolean got_error = FALSE;
 
+static struct main_opts {
+	gchar *src;
+	gchar *dst;
+	gchar *value;
+	gchar *sec_level;
+	uuid_t *uuid;
+	int start;
+	int end;
+	int handle;
+	int mtu;
+	int psm;
+	gboolean primary;
+	gboolean char_disc;
+	gboolean char_read;
+	gboolean listen;
+	gboolean char_desc;
+	gboolean le;
+	gboolean char_write;
+} main_opts;
+
 struct characteristic_data {
 	GAttrib *attrib;
 	uint16_t start;
 	uint16_t end;
 };
 
+static void options_init(void)
+{
+	main_opts.src = NULL;
+	main_opts.dst = NULL;
+	main_opts.value = NULL;
+	main_opts.sec_level = "low";
+	main_opts.uuid = NULL;
+	main_opts.start = 0x0001;
+	main_opts.end = 0xffff;
+	main_opts.handle = -1;
+	main_opts.mtu = 0;
+	main_opts.psm = 0x1f;
+	main_opts.primary = FALSE;
+	main_opts.char_disc = FALSE;
+	main_opts.char_read = FALSE;
+	main_opts.listen = FALSE;
+	main_opts.char_desc = FALSE;
+	main_opts.le = FALSE;
+	main_opts.char_write = FALSE;
+}
+
 static void connect_cb(GIOChannel *io, GError *err, gpointer user_data)
 {
 	if (err) {
@@ -90,31 +114,31 @@ static GIOChannel *do_connect(gboolean le)
 
 	/* This check is required because currently setsockopt() returns no
 	 * errors for MTU values smaller than the allowed minimum. */
-	if (opt_mtu != 0 && opt_mtu < ATT_MIN_MTU_L2CAP) {
+	if (main_opts.mtu != 0 && main_opts.mtu < ATT_MIN_MTU_L2CAP) {
 		g_printerr("MTU cannot be smaller than %d\n",
 							ATT_MIN_MTU_L2CAP);
 		return NULL;
 	}
 
 	/* Remote device */
-	if (opt_dst == NULL) {
+	if (main_opts.dst == NULL) {
 		g_printerr("Remote Bluetooth address required\n");
 		return NULL;
 	}
-	str2ba(opt_dst, &dba);
+	str2ba(main_opts.dst, &dba);
 
 	/* Local adapter */
-	if (opt_src != NULL) {
-		if (!strncmp(opt_src, "hci", 3))
-			hci_devba(atoi(opt_src + 3), &sba);
+	if (main_opts.src != NULL) {
+		if (!strncmp(main_opts.src, "hci", 3))
+			hci_devba(atoi(main_opts.src + 3), &sba);
 		else
-			str2ba(opt_src, &sba);
+			str2ba(main_opts.src, &sba);
 	} else
 		bacpy(&sba, BDADDR_ANY);
 
-	if (strcmp(opt_sec_level, "medium") == 0)
+	if (strcmp(main_opts.sec_level, "medium") == 0)
 		sec_level = BT_IO_SEC_MEDIUM;
-	else if (strcmp(opt_sec_level, "high") == 0)
+	else if (strcmp(main_opts.sec_level, "high") == 0)
 		sec_level = BT_IO_SEC_HIGH;
 	else
 		sec_level = BT_IO_SEC_LOW;
@@ -124,15 +148,15 @@ static GIOChannel *do_connect(gboolean le)
 				BT_IO_OPT_SOURCE_BDADDR, &sba,
 				BT_IO_OPT_DEST_BDADDR, &dba,
 				BT_IO_OPT_CID, GATT_CID,
-				BT_IO_OPT_OMTU, opt_mtu,
+				BT_IO_OPT_OMTU, main_opts.mtu,
 				BT_IO_OPT_SEC_LEVEL, sec_level,
 				BT_IO_OPT_INVALID);
 	else
 		chan = bt_io_connect(BT_IO_L2CAP, connect_cb, NULL, NULL, &err,
 				BT_IO_OPT_SOURCE_BDADDR, &sba,
 				BT_IO_OPT_DEST_BDADDR, &dba,
-				BT_IO_OPT_PSM, opt_psm,
-				BT_IO_OPT_OMTU, opt_mtu,
+				BT_IO_OPT_PSM, main_opts.psm,
+				BT_IO_OPT_OMTU, main_opts.mtu,
 				BT_IO_OPT_SEC_LEVEL, sec_level,
 				BT_IO_OPT_INVALID);
 
@@ -236,9 +260,9 @@ static gboolean primary(gpointer user_data)
 {
 	GAttrib *attrib = user_data;
 
-	if (opt_uuid)
-		gatt_discover_primary(attrib, opt_uuid, primary_by_uuid_cb,
-									NULL);
+	if (main_opts.uuid)
+		gatt_discover_primary(attrib, main_opts.uuid,
+						primary_by_uuid_cb, NULL);
 	else
 		gatt_discover_primary(attrib, NULL, primary_all_cb, NULL);
 
@@ -272,7 +296,8 @@ static gboolean characteristics(gpointer user_data)
 {
 	GAttrib *attrib = user_data;
 
-	gatt_discover_char(attrib, opt_start, opt_end, char_discovered_cb, NULL);
+	gatt_discover_char(attrib, main_opts.start, main_opts.end,
+						char_discovered_cb, NULL);
 
 	return FALSE;
 }
@@ -298,7 +323,7 @@ static void char_read_cb(guint8 status, const guint8 *pdu, guint16 plen,
 	g_print("\n");
 
 done:
-	if (opt_listen == FALSE)
+	if (main_opts.listen == FALSE)
 		g_main_loop_quit(event_loop);
 }
 
@@ -310,7 +335,7 @@ static void char_read_by_uuid_cb(guint8 status, const guint8 *pdu,
 	int i;
 
 	if (status == ATT_ECODE_ATTR_NOT_FOUND &&
-					char_data->start != opt_start)
+					char_data->start != main_opts.start)
 		goto done;
 
 	if (status != 0) {
@@ -339,7 +364,7 @@ static void char_read_by_uuid_cb(guint8 status, const guint8 *pdu,
 	att_data_list_free(list);
 
 	gatt_read_char_by_uuid(char_data->attrib, char_data->start,
-					char_data->end, opt_uuid,
+					char_data->end, main_opts.uuid,
 					char_read_by_uuid_cb,
 					char_data);
 
@@ -353,27 +378,28 @@ static gboolean characteristics_read(gpointer user_data)
 {
 	GAttrib *attrib = user_data;
 
-	if (opt_uuid != NULL) {
+	if (main_opts.uuid != NULL) {
 		struct characteristic_data *char_data;
 
 		char_data = g_new(struct characteristic_data, 1);
 		char_data->attrib = attrib;
-		char_data->start = opt_start;
-		char_data->end = opt_end;
+		char_data->start = main_opts.start;
+		char_data->end = main_opts.end;
 
-		gatt_read_char_by_uuid(attrib, opt_start, opt_end, opt_uuid,
-						char_read_by_uuid_cb, char_data);
+		gatt_read_char_by_uuid(attrib, main_opts.start, main_opts.end,
+					main_opts.uuid, char_read_by_uuid_cb,
+					char_data);
 
 		return FALSE;
 	}
 
-	if (opt_handle <= 0) {
+	if (main_opts.handle <= 0) {
 		g_printerr("A valid handle is required\n");
 		g_main_loop_quit(event_loop);
 		return FALSE;
 	}
 
-	gatt_read_char(attrib, opt_handle, char_read_cb, attrib);
+	gatt_read_char(attrib, main_opts.handle, char_read_cb, attrib);
 
 	return FALSE;
 }
@@ -411,23 +437,24 @@ static gboolean characteristics_write(gpointer user_data)
 	uint8_t *value;
 	size_t len;
 
-	if (opt_handle <= 0) {
+	if (main_opts.handle <= 0) {
 		g_printerr("A valid handle is required\n");
 		goto error;
 	}
 
-	if (opt_value == NULL || opt_value[0] == '\0') {
+	if (main_opts.value == NULL || main_opts.value[0] == '\0') {
 		g_printerr("A value is required\n");
 		goto error;
 	}
 
-	len = attr_data_from_string(opt_value, &value);
+	len = attr_data_from_string(main_opts.value, &value);
 	if (len == 0) {
 		g_printerr("Invalid value\n");
 		goto error;
 	}
 
-	gatt_write_cmd(attrib, opt_handle, value, len, mainloop_quit, value);
+	gatt_write_cmd(attrib, main_opts.handle, value, len, mainloop_quit,
+									value);
 
 	return FALSE;
 
@@ -474,7 +501,7 @@ static void char_desc_cb(guint8 status, const guint8 *pdu, guint16 plen,
 	att_data_list_free(list);
 
 done:
-	if (opt_listen == FALSE)
+	if (main_opts.listen == FALSE)
 		g_main_loop_quit(event_loop);
 }
 
@@ -482,7 +509,8 @@ static gboolean characteristics_desc(gpointer user_data)
 {
 	GAttrib *attrib = user_data;
 
-	gatt_find_info(attrib, opt_start, opt_end, char_desc_cb, NULL);
+	gatt_find_info(attrib, main_opts.start, main_opts.end,
+							char_desc_cb, NULL);
 
 	return FALSE;
 }
@@ -493,20 +521,20 @@ static gboolean parse_uuid(const char *key, const char *value,
 	if (!value)
 		return FALSE;
 
-	opt_uuid = g_try_malloc(sizeof(uuid_t));
-	if (opt_uuid == NULL)
+	main_opts.uuid = g_try_malloc(sizeof(uuid_t));
+	if (main_opts.uuid == NULL)
 		return FALSE;
 
-	if (bt_string2uuid(opt_uuid, value) < 0)
+	if (bt_string2uuid(main_opts.uuid, value) < 0)
 		return FALSE;
 
 	return TRUE;
 }
 
 static GOptionEntry primary_char_options[] = {
-	{ "start", 's' , 0, G_OPTION_ARG_INT, &opt_start,
+	{ "start", 's' , 0, G_OPTION_ARG_INT, &main_opts.start,
 		"Starting handle(optional)", "0x0001" },
-	{ "end", 'e' , 0, G_OPTION_ARG_INT, &opt_end,
+	{ "end", 'e' , 0, G_OPTION_ARG_INT, &main_opts.end,
 		"Ending handle(optional)", "0xffff" },
 	{ "uuid", 'u', G_OPTION_FLAG_OPTIONAL_ARG, G_OPTION_ARG_CALLBACK,
 		parse_uuid, "UUID16 or UUID128(optional)", "0x1801"},
@@ -514,42 +542,42 @@ static GOptionEntry primary_char_options[] = {
 };
 
 static GOptionEntry char_rw_options[] = {
-	{ "handle", 'a' , 0, G_OPTION_ARG_INT, &opt_handle,
+	{ "handle", 'a' , 0, G_OPTION_ARG_INT, &main_opts.handle,
 		"Read/Write characteristic by handle(required)", "0x0001" },
-	{ "value", 'n' , 0, G_OPTION_ARG_STRING, &opt_value,
+	{ "value", 'n' , 0, G_OPTION_ARG_STRING, &main_opts.value,
 		"Write characteristic value (required for write operation)",
 		"0x0001" },
 	{NULL},
 };
 
 static GOptionEntry gatt_options[] = {
-	{ "primary", 0, 0, G_OPTION_ARG_NONE, &opt_primary,
+	{ "primary", 0, 0, G_OPTION_ARG_NONE, &main_opts.primary,
 		"Primary Service Discovery", NULL },
-	{ "characteristics", 0, 0, G_OPTION_ARG_NONE, &opt_characteristics,
+	{ "characteristics", 0, 0, G_OPTION_ARG_NONE, &main_opts.char_disc,
 		"Characteristics Discovery", NULL },
-	{ "char-read", 0, 0, G_OPTION_ARG_NONE, &opt_char_read,
+	{ "char-read", 0, 0, G_OPTION_ARG_NONE, &main_opts.char_read,
 		"Characteristics Value/Descriptor Read", NULL },
-	{ "char-write", 0, 0, G_OPTION_ARG_NONE, &opt_char_write,
+	{ "char-write", 0, 0, G_OPTION_ARG_NONE, &main_opts.char_write,
 		"Characteristics Value Write", NULL },
-	{ "char-desc", 0, 0, G_OPTION_ARG_NONE, &opt_char_desc,
+	{ "char-desc", 0, 0, G_OPTION_ARG_NONE, &main_opts.char_desc,
 		"Characteristics Descriptor Discovery", NULL },
-	{ "listen", 0, 0, G_OPTION_ARG_NONE, &opt_listen,
+	{ "listen", 0, 0, G_OPTION_ARG_NONE, &main_opts.listen,
 		"Listen for notifications and indications", NULL },
-	{ "le", 0, 0, G_OPTION_ARG_NONE, &opt_le,
+	{ "le", 0, 0, G_OPTION_ARG_NONE, &main_opts.le,
 		"Use Bluetooth Low Energy transport", NULL },
 	{ NULL },
 };
 
 static GOptionEntry options[] = {
-	{ "adapter", 'i', 0, G_OPTION_ARG_STRING, &opt_src,
+	{ "adapter", 'i', 0, G_OPTION_ARG_STRING, &main_opts.src,
 		"Specify local adapter interface", "hciX" },
-	{ "device", 'b', 0, G_OPTION_ARG_STRING, &opt_dst,
+	{ "device", 'b', 0, G_OPTION_ARG_STRING, &main_opts.dst,
 		"Specify remote Bluetooth address", "MAC" },
-	{ "mtu", 'm', 0, G_OPTION_ARG_INT, &opt_mtu,
+	{ "mtu", 'm', 0, G_OPTION_ARG_INT, &main_opts.mtu,
 		"Specify the MTU size", "MTU" },
-	{ "psm", 'p', 0, G_OPTION_ARG_INT, &opt_psm,
+	{ "psm", 'p', 0, G_OPTION_ARG_INT, &main_opts.psm,
 		"Specify the PSM for GATT/ATT over BR/EDR", "PSM" },
-	{ "sec-level", 'l', 0, G_OPTION_ARG_STRING, &opt_sec_level,
+	{ "sec-level", 'l', 0, G_OPTION_ARG_STRING, &main_opts.sec_level,
 		"Set security level. Default: low", "[low | medium | high]"},
 	{ NULL },
 };
@@ -563,6 +591,8 @@ int main(int argc, char *argv[])
 	GIOChannel *chan;
 	GSourceFunc callback;
 
+	options_init();
+
 	context = g_option_context_new(NULL);
 	g_option_context_add_main_entries(context, options, NULL);
 
@@ -594,15 +624,15 @@ int main(int argc, char *argv[])
 		g_error_free(gerr);
 	}
 
-	if (opt_primary)
+	if (main_opts.primary)
 		callback = primary;
-	else if (opt_characteristics)
+	else if (main_opts.char_disc)
 		callback = characteristics;
-	else if (opt_char_read)
+	else if (main_opts.char_read)
 		callback = characteristics_read;
-	else if (opt_char_write)
+	else if (main_opts.char_write)
 		callback = characteristics_write;
-	else if (opt_char_desc)
+	else if (main_opts.char_desc)
 		callback = characteristics_desc;
 	else {
 		gchar *help = g_option_context_get_help(context, TRUE, NULL);
@@ -612,7 +642,7 @@ int main(int argc, char *argv[])
 		goto done;
 	}
 
-	chan = do_connect(opt_le);
+	chan = do_connect(main_opts.le);
 	if (chan == NULL) {
 		got_error = TRUE;
 		goto done;
@@ -622,7 +652,7 @@ int main(int argc, char *argv[])
 
 	event_loop = g_main_loop_new(NULL, FALSE);
 
-	if (opt_listen)
+	if (main_opts.listen)
 		g_idle_add(listen_start, attrib);
 
 	g_idle_add(callback, attrib);
@@ -638,9 +668,9 @@ int main(int argc, char *argv[])
 
 done:
 	g_option_context_free(context);
-	g_free(opt_src);
-	g_free(opt_dst);
-	g_free(opt_uuid);
+	g_free(main_opts.src);
+	g_free(main_opts.dst);
+	g_free(main_opts.uuid);
 
 	if (got_error)
 		exit(EXIT_FAILURE);
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH v2 2/5] Include check to readline lib on acinlude.m4
  2011-02-09 21:26   ` Johan Hedberg
  2011-02-10 17:14     ` Sheldon Demario
  2011-02-11 14:17     ` [PATCH v2 1/5] Put all gatttool global options in a unique struct Sheldon Demario
@ 2011-02-11 14:17     ` Sheldon Demario
  2011-02-11 14:17     ` [PATCH v2 3/5] Add an initial interactive mode to gatttool Sheldon Demario
                       ` (6 subsequent siblings)
  9 siblings, 0 replies; 20+ messages in thread
From: Sheldon Demario @ 2011-02-11 14:17 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Sheldon Demario

---
 acinclude.m4 |   10 ++++++++++
 1 files changed, 10 insertions(+), 0 deletions(-)

diff --git a/acinclude.m4 b/acinclude.m4
index 9d3f6b2..91e0956 100644
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -153,6 +153,15 @@ AC_DEFUN([AC_PATH_SNDFILE], [
 	AC_SUBST(SNDFILE_LIBS)
 ])
 
+AC_DEFUN([AC_PATH_READLINE], [
+	AC_CHECK_HEADER(readline/readline.h,
+		AC_CHECK_LIB(readline, main,
+			[ readline_found=yes
+			AC_SUBST(READLINE_LIBS, "-lreadline")
+			], readline_found=no),
+		[])
+])
+
 AC_DEFUN([AC_PATH_OUI], [
 	AC_ARG_WITH(ouifile,
 		    AS_HELP_STRING([--with-ouifile=PATH],[Path to the oui.txt file @<:@auto@:>@]),
@@ -356,6 +365,7 @@ AC_DEFUN([AC_ARG_BLUEZ], [
 	AM_CONDITIONAL(HEALTHPLUGIN, test "${health_enable}" = "yes")
 	AM_CONDITIONAL(MCAP, test "${health_enable}" = "yes")
 	AM_CONDITIONAL(HAL, test "${hal_enable}" = "yes")
+	AM_CONDITIONAL(READLINE, test "${readline_found}" = "yes")
 	AM_CONDITIONAL(ATTRIBPLUGIN, test "${attrib_enable}" = "yes")
 	AM_CONDITIONAL(ECHOPLUGIN, test "no" = "yes")
 	AM_CONDITIONAL(PNATPLUGIN, test "${pnat_enable}" = "yes")
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH v2 3/5] Add an initial interactive mode to gatttool
  2011-02-09 21:26   ` Johan Hedberg
                       ` (2 preceding siblings ...)
  2011-02-11 14:17     ` [PATCH v2 2/5] Include check to readline lib on acinlude.m4 Sheldon Demario
@ 2011-02-11 14:17     ` Sheldon Demario
  2011-02-11 14:17     ` [PATCH v2 4/5] Move main_opts from gatttool.c to header file Sheldon Demario
                       ` (5 subsequent siblings)
  9 siblings, 0 replies; 20+ messages in thread
From: Sheldon Demario @ 2011-02-11 14:17 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Sheldon Demario

Mode required to allow better GATT procedures control. Some scenarios
require sequential commands without disconnection and delay between
operations. It is also desirable to change some connection parameters
of an active connection.
---
 Makefile.am          |    8 ++-
 attrib/gatttool.c    |    9 ++++
 attrib/gatttool.h    |   24 +++++++++
 attrib/interactive.c |  128 ++++++++++++++++++++++++++++++++++++++++++++++++++
 configure.ac         |    1 +
 5 files changed, 168 insertions(+), 2 deletions(-)
 create mode 100644 attrib/gatttool.h
 create mode 100644 attrib/interactive.c

diff --git a/Makefile.am b/Makefile.am
index e6639a7..11f990b 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -175,12 +175,16 @@ builtin_sources += plugins/service.c
 endif
 
 if ATTRIBPLUGIN
+
+if READLINE
 bin_PROGRAMS += attrib/gatttool
 
 attrib_gatttool_SOURCES = attrib/gatttool.c attrib/att.c attrib/gatt.c \
 			  attrib/gattrib.c btio/btio.c \
-			  src/glib-helper.h src/glib-helper.c
-attrib_gatttool_LDADD = lib/libbluetooth.la @GLIB_LIBS@
+			  src/glib-helper.h src/glib-helper.c \
+			  attrib/gatttool.h attrib/interactive.c
+attrib_gatttool_LDADD = lib/libbluetooth.la @GLIB_LIBS@ @READLINE_LIBS@
+endif
 
 builtin_modules += attrib
 builtin_sources += attrib/main.c \
diff --git a/attrib/gatttool.c b/attrib/gatttool.c
index c612309..cd6e68a 100644
--- a/attrib/gatttool.c
+++ b/attrib/gatttool.c
@@ -42,6 +42,7 @@
 #include "gattrib.h"
 #include "glib-helper.h"
 #include "gatt.h"
+#include "gatttool.h"
 
 /* Minimum MTU for L2CAP connections over BR/EDR */
 #define ATT_MIN_MTU_L2CAP 48
@@ -67,6 +68,7 @@ static struct main_opts {
 	gboolean char_desc;
 	gboolean le;
 	gboolean char_write;
+	gboolean interactive;
 } main_opts;
 
 struct characteristic_data {
@@ -565,6 +567,8 @@ static GOptionEntry gatt_options[] = {
 		"Listen for notifications and indications", NULL },
 	{ "le", 0, 0, G_OPTION_ARG_NONE, &main_opts.le,
 		"Use Bluetooth Low Energy transport", NULL },
+	{ "interactive", 'I', G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_NONE,
+		&main_opts.interactive, "Use interactive mode", NULL },
 	{ NULL },
 };
 
@@ -624,6 +628,11 @@ int main(int argc, char *argv[])
 		g_error_free(gerr);
 	}
 
+	if (main_opts.interactive) {
+		interactive();
+		goto done;
+	}
+
 	if (main_opts.primary)
 		callback = primary;
 	else if (main_opts.char_disc)
diff --git a/attrib/gatttool.h b/attrib/gatttool.h
new file mode 100644
index 0000000..ed5d9d6
--- /dev/null
+++ b/attrib/gatttool.h
@@ -0,0 +1,24 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 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
+ *
+ */
+
+int interactive(void);
diff --git a/attrib/interactive.c b/attrib/interactive.c
new file mode 100644
index 0000000..0653609
--- /dev/null
+++ b/attrib/interactive.c
@@ -0,0 +1,128 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 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
+ *
+ */
+#include <strings.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <glib.h>
+
+#include <readline/readline.h>
+#include <readline/history.h>
+
+#include "gatttool.h"
+
+static GMainLoop *event_loop;
+
+static void cmd_help(int argcp, char **argvp);
+
+static void cmd_exit(int argcp, char **argvp)
+{
+	rl_callback_handler_remove();
+	g_main_loop_quit(event_loop);
+}
+
+static struct {
+	const char *cmd;
+	void (*func)(int argcp, char **argvp);
+	const char *desc;
+} commands[] = {
+	{ "help",	cmd_help,	"Show this help"},
+	{ "exit",	cmd_exit,	"Exit interactive mode"},
+	{ NULL, NULL, NULL}
+};
+
+static void cmd_help(int argcp, char **argvp)
+{
+	int i;
+
+	for (i = 0; commands[i].cmd; i++)
+		printf("%-12s\t%s\n", commands[i].cmd, commands[i].desc);
+}
+
+static void parse_line(char *line_read)
+{
+	gchar **argvp;
+	int argcp;
+	int i;
+
+	if (line_read == NULL) {
+		printf("\n");
+		cmd_exit(0, NULL);
+		return;
+	}
+
+	line_read = g_strstrip(line_read);
+
+	if (*line_read == '\0')
+		return;
+
+	add_history(line_read);
+
+	g_shell_parse_argv(line_read, &argcp, &argvp, NULL);
+
+	for (i = 0; commands[i].cmd; i++)
+		if (strcasecmp(commands[i].cmd, argvp[0]) == 0)
+			break;
+
+	if (commands[i].cmd)
+		commands[i].func(argcp, argvp);
+	else
+		printf("%s: command not found\n", argvp[0]);
+
+	g_strfreev(argvp);
+}
+
+static gboolean prompt_read(GIOChannel *chan, GIOCondition cond,
+							gpointer user_data)
+{
+	if (cond & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) {
+		g_io_channel_unref(chan);
+		return FALSE;
+	}
+
+	rl_callback_read_char();
+
+	return TRUE;
+}
+
+int interactive(void)
+{
+	GIOChannel *pchan;
+	gint events;
+
+	event_loop = g_main_loop_new(NULL, FALSE);
+
+	pchan = g_io_channel_unix_new(fileno(stdin));
+	g_io_channel_set_close_on_unref(pchan, TRUE);
+	events = G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL;
+	g_io_add_watch(pchan, events, prompt_read, NULL);
+
+	rl_callback_handler_install("> ", parse_line);
+
+	g_main_loop_run(event_loop);
+
+	rl_callback_handler_remove();
+	g_io_channel_unref(pchan);
+	g_main_loop_unref(event_loop);
+
+	return 0;
+}
diff --git a/configure.ac b/configure.ac
index bebdc9c..a8e8fc6 100644
--- a/configure.ac
+++ b/configure.ac
@@ -42,6 +42,7 @@ AC_PATH_GSTREAMER
 AC_PATH_USB
 AC_PATH_SNDFILE
 AC_PATH_OUI
+AC_PATH_READLINE
 
 AC_ARG_BLUEZ
 
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH v2 4/5] Move main_opts from gatttool.c to header file
  2011-02-09 21:26   ` Johan Hedberg
                       ` (3 preceding siblings ...)
  2011-02-11 14:17     ` [PATCH v2 3/5] Add an initial interactive mode to gatttool Sheldon Demario
@ 2011-02-11 14:17     ` Sheldon Demario
  2011-02-11 14:17     ` [PATCH v2 5/5] Add connect/disconnect options on interactive mode of gatttool Sheldon Demario
                       ` (4 subsequent siblings)
  9 siblings, 0 replies; 20+ messages in thread
From: Sheldon Demario @ 2011-02-11 14:17 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Sheldon Demario

---
 attrib/gatttool.c    |   22 +---------------------
 attrib/gatttool.h    |   21 +++++++++++++++++++++
 attrib/interactive.c |    2 ++
 3 files changed, 24 insertions(+), 21 deletions(-)

diff --git a/attrib/gatttool.c b/attrib/gatttool.c
index cd6e68a..badd3b0 100644
--- a/attrib/gatttool.c
+++ b/attrib/gatttool.c
@@ -49,27 +49,7 @@
 
 static GMainLoop *event_loop;
 static gboolean got_error = FALSE;
-
-static struct main_opts {
-	gchar *src;
-	gchar *dst;
-	gchar *value;
-	gchar *sec_level;
-	uuid_t *uuid;
-	int start;
-	int end;
-	int handle;
-	int mtu;
-	int psm;
-	gboolean primary;
-	gboolean char_disc;
-	gboolean char_read;
-	gboolean listen;
-	gboolean char_desc;
-	gboolean le;
-	gboolean char_write;
-	gboolean interactive;
-} main_opts;
+static struct main_opts main_opts;
 
 struct characteristic_data {
 	GAttrib *attrib;
diff --git a/attrib/gatttool.h b/attrib/gatttool.h
index ed5d9d6..3dbe88b 100644
--- a/attrib/gatttool.h
+++ b/attrib/gatttool.h
@@ -21,4 +21,25 @@
  *
  */
 
+struct main_opts {
+	gchar *src;
+	gchar *dst;
+	gchar *value;
+	gchar *sec_level;
+	uuid_t *uuid;
+	int start;
+	int end;
+	int handle;
+	int mtu;
+	int psm;
+	gboolean primary;
+	gboolean char_disc;
+	gboolean char_read;
+	gboolean listen;
+	gboolean char_desc;
+	gboolean le;
+	gboolean char_write;
+	gboolean interactive;
+};
+
 int interactive(void);
diff --git a/attrib/interactive.c b/attrib/interactive.c
index 0653609..425a9b2 100644
--- a/attrib/interactive.c
+++ b/attrib/interactive.c
@@ -25,6 +25,8 @@
 #include <stdio.h>
 #include <glib.h>
 
+#include <bluetooth/sdp.h>
+
 #include <readline/readline.h>
 #include <readline/history.h>
 
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH v2 5/5] Add connect/disconnect options on interactive mode of gatttool
  2011-02-09 21:26   ` Johan Hedberg
                       ` (4 preceding siblings ...)
  2011-02-11 14:17     ` [PATCH v2 4/5] Move main_opts from gatttool.c to header file Sheldon Demario
@ 2011-02-11 14:17     ` Sheldon Demario
  2011-02-14 15:07     ` [PATCH v3 1/3] Include check to readline lib on acinlude.m4 Sheldon Demario
                       ` (3 subsequent siblings)
  9 siblings, 0 replies; 20+ messages in thread
From: Sheldon Demario @ 2011-02-11 14:17 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Sheldon Demario

---
 attrib/gatttool.c    |    6 +-
 attrib/gatttool.h    |    3 +-
 attrib/interactive.c |  105 +++++++++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 108 insertions(+), 6 deletions(-)

diff --git a/attrib/gatttool.c b/attrib/gatttool.c
index badd3b0..1b89d9f 100644
--- a/attrib/gatttool.c
+++ b/attrib/gatttool.c
@@ -87,7 +87,7 @@ static void connect_cb(GIOChannel *io, GError *err, gpointer user_data)
 	}
 }
 
-static GIOChannel *do_connect(gboolean le)
+GIOChannel *do_connect(gboolean le, BtIOConnect connect_cb)
 {
 	GIOChannel *chan;
 	bdaddr_t sba, dba;
@@ -609,7 +609,7 @@ int main(int argc, char *argv[])
 	}
 
 	if (main_opts.interactive) {
-		interactive();
+		interactive(&main_opts);
 		goto done;
 	}
 
@@ -631,7 +631,7 @@ int main(int argc, char *argv[])
 		goto done;
 	}
 
-	chan = do_connect(main_opts.le);
+	chan = do_connect(main_opts.le, connect_cb);
 	if (chan == NULL) {
 		got_error = TRUE;
 		goto done;
diff --git a/attrib/gatttool.h b/attrib/gatttool.h
index 3dbe88b..c80026c 100644
--- a/attrib/gatttool.h
+++ b/attrib/gatttool.h
@@ -42,4 +42,5 @@ struct main_opts {
 	gboolean interactive;
 };
 
-int interactive(void);
+int interactive(struct main_opts *config);
+GIOChannel *do_connect(gboolean le, BtIOConnect connect_cb);
diff --git a/attrib/interactive.c b/attrib/interactive.c
index 425a9b2..5fb6f8e 100644
--- a/attrib/interactive.c
+++ b/attrib/interactive.c
@@ -30,18 +30,111 @@
 #include <readline/readline.h>
 #include <readline/history.h>
 
+#include "btio.h"
+#include "gattrib.h"
 #include "gatttool.h"
 
+static GIOChannel *iochannel = NULL;
+static GAttrib *attrib = NULL;
 static GMainLoop *event_loop;
+static GString *prompt;
+static struct main_opts *main_opts;
 
 static void cmd_help(int argcp, char **argvp);
 
+enum state {
+	STATE_DISCONNECTED,
+	STATE_CONNECTING,
+	STATE_CONNECTED
+} conn_state;
+
+static char *get_prompt(void)
+{
+	if (conn_state == STATE_CONNECTING) {
+		g_string_assign(prompt, "Connecting... ");
+		return prompt->str;
+	}
+
+	if (conn_state == STATE_CONNECTED)
+		g_string_assign(prompt, "[CON]");
+	else
+		g_string_assign(prompt, "[   ]");
+
+	if (main_opts->dst)
+		g_string_append_printf(prompt, "[%17s]", main_opts->dst);
+	else
+		g_string_append_printf(prompt, "[%17s]", "");
+
+	if (main_opts->le)
+		g_string_append(prompt, "[LE]");
+	else
+		g_string_append(prompt, "[BR]");
+
+	g_string_append(prompt, "> ");
+
+	return prompt->str;
+}
+
+
+static void set_state(enum state st)
+{
+	conn_state = st;
+	rl_set_prompt(get_prompt());
+	rl_redisplay();
+}
+
+static void connect_cb(GIOChannel *io, GError *err, gpointer user_data)
+{
+	if (err) {
+		printf("connect error: %s\n", err->message);
+		return;
+	}
+
+	attrib = g_attrib_new(iochannel);
+	set_state(STATE_CONNECTED);
+}
+
 static void cmd_exit(int argcp, char **argvp)
 {
 	rl_callback_handler_remove();
 	g_main_loop_quit(event_loop);
 }
 
+static void cmd_connect(int argcp, char **argvp)
+{
+	if (conn_state != STATE_DISCONNECTED)
+		return;
+
+	if (main_opts->dst == NULL) {
+		printf("Remote Bluetooth address required\n");
+		return;
+	}
+
+	set_state(STATE_CONNECTING);
+	iochannel = do_connect(main_opts->le, connect_cb);
+	if (iochannel == NULL)
+		set_state(STATE_DISCONNECTED);
+
+	return;
+}
+
+static void cmd_disconnect(int argcp, char **argvp)
+{
+	if (conn_state == STATE_DISCONNECTED)
+		return;
+
+	g_attrib_unref(attrib);
+	attrib = NULL;
+
+	g_io_channel_shutdown(iochannel, FALSE, NULL);
+	g_io_channel_unref(iochannel);
+	iochannel = NULL;
+
+	set_state(STATE_DISCONNECTED);
+
+	return;
+}
+
 static struct {
 	const char *cmd;
 	void (*func)(int argcp, char **argvp);
@@ -49,6 +142,8 @@ static struct {
 } commands[] = {
 	{ "help",	cmd_help,	"Show this help"},
 	{ "exit",	cmd_exit,	"Exit interactive mode"},
+	{ "connect",	cmd_connect,	"Connect to a remote device"},
+	{ "disconnect",	cmd_disconnect,	"Disconnect from a remote device"},
 	{ NULL, NULL, NULL}
 };
 
@@ -106,11 +201,15 @@ static gboolean prompt_read(GIOChannel *chan, GIOCondition cond,
 	return TRUE;
 }
 
-int interactive(void)
+int interactive(struct main_opts *config)
 {
 	GIOChannel *pchan;
 	gint events;
 
+	main_opts = config;
+
+	prompt = g_string_new(NULL);
+
 	event_loop = g_main_loop_new(NULL, FALSE);
 
 	pchan = g_io_channel_unix_new(fileno(stdin));
@@ -118,13 +217,15 @@ int interactive(void)
 	events = G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL;
 	g_io_add_watch(pchan, events, prompt_read, NULL);
 
-	rl_callback_handler_install("> ", parse_line);
+	rl_callback_handler_install(get_prompt(), parse_line);
 
 	g_main_loop_run(event_loop);
 
 	rl_callback_handler_remove();
+	cmd_disconnect(0, NULL);
 	g_io_channel_unref(pchan);
 	g_main_loop_unref(event_loop);
+	g_string_free(prompt, TRUE);
 
 	return 0;
 }
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH v3 1/3] Include check to readline lib on acinlude.m4
  2011-02-09 21:26   ` Johan Hedberg
                       ` (5 preceding siblings ...)
  2011-02-11 14:17     ` [PATCH v2 5/5] Add connect/disconnect options on interactive mode of gatttool Sheldon Demario
@ 2011-02-14 15:07     ` Sheldon Demario
  2011-02-15 17:20       ` Johan Hedberg
  2011-02-14 15:07     ` [PATCH v3 2/3] Add an initial interactive mode to gatttool Sheldon Demario
                       ` (2 subsequent siblings)
  9 siblings, 1 reply; 20+ messages in thread
From: Sheldon Demario @ 2011-02-14 15:07 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Sheldon Demario

---
 acinclude.m4 |   10 ++++++++++
 1 files changed, 10 insertions(+), 0 deletions(-)

diff --git a/acinclude.m4 b/acinclude.m4
index 9d3f6b2..91e0956 100644
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -153,6 +153,15 @@ AC_DEFUN([AC_PATH_SNDFILE], [
 	AC_SUBST(SNDFILE_LIBS)
 ])
 
+AC_DEFUN([AC_PATH_READLINE], [
+	AC_CHECK_HEADER(readline/readline.h,
+		AC_CHECK_LIB(readline, main,
+			[ readline_found=yes
+			AC_SUBST(READLINE_LIBS, "-lreadline")
+			], readline_found=no),
+		[])
+])
+
 AC_DEFUN([AC_PATH_OUI], [
 	AC_ARG_WITH(ouifile,
 		    AS_HELP_STRING([--with-ouifile=PATH],[Path to the oui.txt file @<:@auto@:>@]),
@@ -356,6 +365,7 @@ AC_DEFUN([AC_ARG_BLUEZ], [
 	AM_CONDITIONAL(HEALTHPLUGIN, test "${health_enable}" = "yes")
 	AM_CONDITIONAL(MCAP, test "${health_enable}" = "yes")
 	AM_CONDITIONAL(HAL, test "${hal_enable}" = "yes")
+	AM_CONDITIONAL(READLINE, test "${readline_found}" = "yes")
 	AM_CONDITIONAL(ATTRIBPLUGIN, test "${attrib_enable}" = "yes")
 	AM_CONDITIONAL(ECHOPLUGIN, test "no" = "yes")
 	AM_CONDITIONAL(PNATPLUGIN, test "${pnat_enable}" = "yes")
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH v3 2/3] Add an initial interactive mode to gatttool
  2011-02-09 21:26   ` Johan Hedberg
                       ` (6 preceding siblings ...)
  2011-02-14 15:07     ` [PATCH v3 1/3] Include check to readline lib on acinlude.m4 Sheldon Demario
@ 2011-02-14 15:07     ` Sheldon Demario
  2011-02-14 18:13       ` Gustavo F. Padovan
  2011-02-14 15:07     ` [PATCH v3 3/3] Add connect/disconnect options on interactive mode of gatttool Sheldon Demario
  2011-02-15 17:09     ` [PATCH v4] Add an initial interactive mode to gatttool Sheldon Demario
  9 siblings, 1 reply; 20+ messages in thread
From: Sheldon Demario @ 2011-02-14 15:07 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Sheldon Demario

Mode required to allow better GATT procedures control. Some scenarios
require sequential commands without disconnection and delay between
operations. It is also desirable to change some connection parameters
of an active connection.
---
 Makefile.am          |    8 ++-
 attrib/gatttool.c    |    9 ++++
 attrib/gatttool.h    |   24 +++++++++
 attrib/interactive.c |  128 ++++++++++++++++++++++++++++++++++++++++++++++++++
 configure.ac         |    1 +
 5 files changed, 168 insertions(+), 2 deletions(-)
 create mode 100644 attrib/gatttool.h
 create mode 100644 attrib/interactive.c

diff --git a/Makefile.am b/Makefile.am
index e6639a7..11f990b 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -175,12 +175,16 @@ builtin_sources += plugins/service.c
 endif
 
 if ATTRIBPLUGIN
+
+if READLINE
 bin_PROGRAMS += attrib/gatttool
 
 attrib_gatttool_SOURCES = attrib/gatttool.c attrib/att.c attrib/gatt.c \
 			  attrib/gattrib.c btio/btio.c \
-			  src/glib-helper.h src/glib-helper.c
-attrib_gatttool_LDADD = lib/libbluetooth.la @GLIB_LIBS@
+			  src/glib-helper.h src/glib-helper.c \
+			  attrib/gatttool.h attrib/interactive.c
+attrib_gatttool_LDADD = lib/libbluetooth.la @GLIB_LIBS@ @READLINE_LIBS@
+endif
 
 builtin_modules += attrib
 builtin_sources += attrib/main.c \
diff --git a/attrib/gatttool.c b/attrib/gatttool.c
index 8e8ed8e..d663eb5 100644
--- a/attrib/gatttool.c
+++ b/attrib/gatttool.c
@@ -42,6 +42,7 @@
 #include "gattrib.h"
 #include "glib-helper.h"
 #include "gatt.h"
+#include "gatttool.h"
 
 /* Minimum MTU for L2CAP connections over BR/EDR */
 #define ATT_MIN_MTU_L2CAP 48
@@ -63,6 +64,7 @@ static gboolean opt_listen = FALSE;
 static gboolean opt_char_desc = FALSE;
 static gboolean opt_le = FALSE;
 static gboolean opt_char_write = FALSE;
+static gboolean opt_interactive = FALSE;
 static GMainLoop *event_loop;
 static gboolean got_error = FALSE;
 
@@ -537,6 +539,8 @@ static GOptionEntry gatt_options[] = {
 		"Listen for notifications and indications", NULL },
 	{ "le", 0, 0, G_OPTION_ARG_NONE, &opt_le,
 		"Use Bluetooth Low Energy transport", NULL },
+	{ "interactive", 'I', G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_NONE,
+		&opt_interactive, "Use interactive mode", NULL },
 	{ NULL },
 };
 
@@ -594,6 +598,11 @@ int main(int argc, char *argv[])
 		g_error_free(gerr);
 	}
 
+	if (opt_interactive) {
+		interactive();
+		goto done;
+	}
+
 	if (opt_primary)
 		callback = primary;
 	else if (opt_characteristics)
diff --git a/attrib/gatttool.h b/attrib/gatttool.h
new file mode 100644
index 0000000..ed5d9d6
--- /dev/null
+++ b/attrib/gatttool.h
@@ -0,0 +1,24 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 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
+ *
+ */
+
+int interactive(void);
diff --git a/attrib/interactive.c b/attrib/interactive.c
new file mode 100644
index 0000000..0653609
--- /dev/null
+++ b/attrib/interactive.c
@@ -0,0 +1,128 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 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
+ *
+ */
+#include <strings.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <glib.h>
+
+#include <readline/readline.h>
+#include <readline/history.h>
+
+#include "gatttool.h"
+
+static GMainLoop *event_loop;
+
+static void cmd_help(int argcp, char **argvp);
+
+static void cmd_exit(int argcp, char **argvp)
+{
+	rl_callback_handler_remove();
+	g_main_loop_quit(event_loop);
+}
+
+static struct {
+	const char *cmd;
+	void (*func)(int argcp, char **argvp);
+	const char *desc;
+} commands[] = {
+	{ "help",	cmd_help,	"Show this help"},
+	{ "exit",	cmd_exit,	"Exit interactive mode"},
+	{ NULL, NULL, NULL}
+};
+
+static void cmd_help(int argcp, char **argvp)
+{
+	int i;
+
+	for (i = 0; commands[i].cmd; i++)
+		printf("%-12s\t%s\n", commands[i].cmd, commands[i].desc);
+}
+
+static void parse_line(char *line_read)
+{
+	gchar **argvp;
+	int argcp;
+	int i;
+
+	if (line_read == NULL) {
+		printf("\n");
+		cmd_exit(0, NULL);
+		return;
+	}
+
+	line_read = g_strstrip(line_read);
+
+	if (*line_read == '\0')
+		return;
+
+	add_history(line_read);
+
+	g_shell_parse_argv(line_read, &argcp, &argvp, NULL);
+
+	for (i = 0; commands[i].cmd; i++)
+		if (strcasecmp(commands[i].cmd, argvp[0]) == 0)
+			break;
+
+	if (commands[i].cmd)
+		commands[i].func(argcp, argvp);
+	else
+		printf("%s: command not found\n", argvp[0]);
+
+	g_strfreev(argvp);
+}
+
+static gboolean prompt_read(GIOChannel *chan, GIOCondition cond,
+							gpointer user_data)
+{
+	if (cond & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) {
+		g_io_channel_unref(chan);
+		return FALSE;
+	}
+
+	rl_callback_read_char();
+
+	return TRUE;
+}
+
+int interactive(void)
+{
+	GIOChannel *pchan;
+	gint events;
+
+	event_loop = g_main_loop_new(NULL, FALSE);
+
+	pchan = g_io_channel_unix_new(fileno(stdin));
+	g_io_channel_set_close_on_unref(pchan, TRUE);
+	events = G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL;
+	g_io_add_watch(pchan, events, prompt_read, NULL);
+
+	rl_callback_handler_install("> ", parse_line);
+
+	g_main_loop_run(event_loop);
+
+	rl_callback_handler_remove();
+	g_io_channel_unref(pchan);
+	g_main_loop_unref(event_loop);
+
+	return 0;
+}
diff --git a/configure.ac b/configure.ac
index bebdc9c..a8e8fc6 100644
--- a/configure.ac
+++ b/configure.ac
@@ -42,6 +42,7 @@ AC_PATH_GSTREAMER
 AC_PATH_USB
 AC_PATH_SNDFILE
 AC_PATH_OUI
+AC_PATH_READLINE
 
 AC_ARG_BLUEZ
 
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* [PATCH v3 3/3] Add connect/disconnect options on interactive mode of gatttool
  2011-02-09 21:26   ` Johan Hedberg
                       ` (7 preceding siblings ...)
  2011-02-14 15:07     ` [PATCH v3 2/3] Add an initial interactive mode to gatttool Sheldon Demario
@ 2011-02-14 15:07     ` Sheldon Demario
  2011-02-15 17:09     ` [PATCH v4] Add an initial interactive mode to gatttool Sheldon Demario
  9 siblings, 0 replies; 20+ messages in thread
From: Sheldon Demario @ 2011-02-14 15:07 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Sheldon Demario

---
 attrib/gatttool.c    |   10 ++--
 attrib/gatttool.h    |    3 +-
 attrib/interactive.c |  114 +++++++++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 119 insertions(+), 8 deletions(-)

diff --git a/attrib/gatttool.c b/attrib/gatttool.c
index d663eb5..cd6b60d 100644
--- a/attrib/gatttool.c
+++ b/attrib/gatttool.c
@@ -83,7 +83,7 @@ static void connect_cb(GIOChannel *io, GError *err, gpointer user_data)
 	}
 }
 
-static GIOChannel *do_connect(gboolean le)
+GIOChannel *do_connect(gchar *dst, gboolean le, BtIOConnect connect_cb)
 {
 	GIOChannel *chan;
 	bdaddr_t sba, dba;
@@ -99,11 +99,11 @@ static GIOChannel *do_connect(gboolean le)
 	}
 
 	/* Remote device */
-	if (opt_dst == NULL) {
+	if (dst == NULL) {
 		g_printerr("Remote Bluetooth address required\n");
 		return NULL;
 	}
-	str2ba(opt_dst, &dba);
+	str2ba(dst, &dba);
 
 	/* Local adapter */
 	if (opt_src != NULL) {
@@ -599,7 +599,7 @@ int main(int argc, char *argv[])
 	}
 
 	if (opt_interactive) {
-		interactive();
+		interactive(opt_dst, opt_le);
 		goto done;
 	}
 
@@ -621,7 +621,7 @@ int main(int argc, char *argv[])
 		goto done;
 	}
 
-	chan = do_connect(opt_le);
+	chan = do_connect(opt_dst, opt_le, connect_cb);
 	if (chan == NULL) {
 		got_error = TRUE;
 		goto done;
diff --git a/attrib/gatttool.h b/attrib/gatttool.h
index ed5d9d6..2237330 100644
--- a/attrib/gatttool.h
+++ b/attrib/gatttool.h
@@ -21,4 +21,5 @@
  *
  */
 
-int interactive(void);
+int interactive(gchar *dst, gboolean le);
+GIOChannel *do_connect(gchar *dst, gboolean le, BtIOConnect connect_cb);
diff --git a/attrib/interactive.c b/attrib/interactive.c
index 0653609..83a0778 100644
--- a/attrib/interactive.c
+++ b/attrib/interactive.c
@@ -28,18 +28,119 @@
 #include <readline/readline.h>
 #include <readline/history.h>
 
+#include "btio.h"
+#include "gattrib.h"
 #include "gatttool.h"
 
+static GIOChannel *iochannel = NULL;
+static GAttrib *attrib = NULL;
 static GMainLoop *event_loop;
+static GString *prompt;
+
+static gchar *opt_dst = NULL;
+static gboolean opt_le = FALSE;
 
 static void cmd_help(int argcp, char **argvp);
 
+enum state {
+	STATE_DISCONNECTED,
+	STATE_CONNECTING,
+	STATE_CONNECTED
+} conn_state;
+
+static char *get_prompt(void)
+{
+	if (conn_state == STATE_CONNECTING) {
+		g_string_assign(prompt, "Connecting... ");
+		return prompt->str;
+	}
+
+	if (conn_state == STATE_CONNECTED)
+		g_string_assign(prompt, "[CON]");
+	else
+		g_string_assign(prompt, "[   ]");
+
+	if (opt_dst)
+		g_string_append_printf(prompt, "[%17s]", opt_dst);
+	else
+		g_string_append_printf(prompt, "[%17s]", "");
+
+	if (opt_le)
+		g_string_append(prompt, "[LE]");
+	else
+		g_string_append(prompt, "[BR]");
+
+	g_string_append(prompt, "> ");
+
+	return prompt->str;
+}
+
+
+static void set_state(enum state st)
+{
+	conn_state = st;
+	rl_set_prompt(get_prompt());
+	rl_redisplay();
+}
+
+static void connect_cb(GIOChannel *io, GError *err, gpointer user_data)
+{
+	if (err) {
+		printf("connect error: %s\n", err->message);
+		set_state(STATE_DISCONNECTED);
+		return;
+	}
+
+	attrib = g_attrib_new(iochannel);
+	set_state(STATE_CONNECTED);
+}
+
 static void cmd_exit(int argcp, char **argvp)
 {
 	rl_callback_handler_remove();
 	g_main_loop_quit(event_loop);
 }
 
+static void cmd_connect(int argcp, char **argvp)
+{
+	if (conn_state != STATE_DISCONNECTED)
+		return;
+
+	if (argcp > 1) {
+		g_free(opt_dst);
+		opt_dst = strdup(argvp[1]);
+	}
+
+	if (opt_dst == NULL) {
+		printf("Remote Bluetooth address required\n");
+		return;
+	}
+
+	set_state(STATE_CONNECTING);
+	iochannel = do_connect(opt_dst, opt_le, connect_cb);
+	if (iochannel == NULL)
+		set_state(STATE_DISCONNECTED);
+
+	return;
+}
+
+static void cmd_disconnect(int argcp, char **argvp)
+{
+	if (conn_state == STATE_DISCONNECTED)
+		return;
+
+	g_attrib_unref(attrib);
+	attrib = NULL;
+
+	g_io_channel_shutdown(iochannel, FALSE, NULL);
+	g_io_channel_unref(iochannel);
+	iochannel = NULL;
+
+	set_state(STATE_DISCONNECTED);
+
+	return;
+}
+
 static struct {
 	const char *cmd;
 	void (*func)(int argcp, char **argvp);
@@ -47,6 +148,8 @@ static struct {
 } commands[] = {
 	{ "help",	cmd_help,	"Show this help"},
 	{ "exit",	cmd_exit,	"Exit interactive mode"},
+	{ "connect",	cmd_connect,	"Connect to a remote device"},
+	{ "disconnect",	cmd_disconnect,	"Disconnect from a remote device"},
 	{ NULL, NULL, NULL}
 };
 
@@ -104,11 +207,16 @@ static gboolean prompt_read(GIOChannel *chan, GIOCondition cond,
 	return TRUE;
 }
 
-int interactive(void)
+int interactive(gchar *dst, gboolean le)
 {
 	GIOChannel *pchan;
 	gint events;
 
+	opt_dst = dst;
+	opt_le = le;
+
+	prompt = g_string_new(NULL);
+
 	event_loop = g_main_loop_new(NULL, FALSE);
 
 	pchan = g_io_channel_unix_new(fileno(stdin));
@@ -116,13 +224,15 @@ int interactive(void)
 	events = G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL;
 	g_io_add_watch(pchan, events, prompt_read, NULL);
 
-	rl_callback_handler_install("> ", parse_line);
+	rl_callback_handler_install(get_prompt(), parse_line);
 
 	g_main_loop_run(event_loop);
 
 	rl_callback_handler_remove();
+	cmd_disconnect(0, NULL);
 	g_io_channel_unref(pchan);
 	g_main_loop_unref(event_loop);
+	g_string_free(prompt, TRUE);
 
 	return 0;
 }
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* Re: [PATCH v3 2/3] Add an initial interactive mode to gatttool
  2011-02-14 15:07     ` [PATCH v3 2/3] Add an initial interactive mode to gatttool Sheldon Demario
@ 2011-02-14 18:13       ` Gustavo F. Padovan
  2011-02-14 18:40         ` Sheldon Demario
  0 siblings, 1 reply; 20+ messages in thread
From: Gustavo F. Padovan @ 2011-02-14 18:13 UTC (permalink / raw)
  To: Sheldon Demario; +Cc: linux-bluetooth

Hi Sheldon,

* Sheldon Demario <sheldon.demario@openbossa.org> [2011-02-14 12:07:19 -0300]:

> Mode required to allow better GATT procedures control. Some scenarios
> require sequential commands without disconnection and delay between
> operations. It is also desirable to change some connection parameters
> of an active connection.
> ---
>  Makefile.am          |    8 ++-
>  attrib/gatttool.c    |    9 ++++
>  attrib/gatttool.h    |   24 +++++++++
>  attrib/interactive.c |  128 ++++++++++++++++++++++++++++++++++++++++++++++++++
>  configure.ac         |    1 +
>  5 files changed, 168 insertions(+), 2 deletions(-)
>  create mode 100644 attrib/gatttool.h
>  create mode 100644 attrib/interactive.c
> 
> diff --git a/Makefile.am b/Makefile.am
> index e6639a7..11f990b 100644
> --- a/Makefile.am
> +++ b/Makefile.am
> @@ -175,12 +175,16 @@ builtin_sources += plugins/service.c
>  endif
>  
>  if ATTRIBPLUGIN
> +
> +if READLINE

Is that really needed? You already checked for READLINE in ./configure at
this point.

>  bin_PROGRAMS += attrib/gatttool
>  
>  attrib_gatttool_SOURCES = attrib/gatttool.c attrib/att.c attrib/gatt.c \
>  			  attrib/gattrib.c btio/btio.c \
> -			  src/glib-helper.h src/glib-helper.c
> -attrib_gatttool_LDADD = lib/libbluetooth.la @GLIB_LIBS@
> +			  src/glib-helper.h src/glib-helper.c \
> +			  attrib/gatttool.h attrib/interactive.c
> +attrib_gatttool_LDADD = lib/libbluetooth.la @GLIB_LIBS@ @READLINE_LIBS@
> +endif
>  
>  builtin_modules += attrib
>  builtin_sources += attrib/main.c \
> diff --git a/attrib/gatttool.c b/attrib/gatttool.c
> index 8e8ed8e..d663eb5 100644
> --- a/attrib/gatttool.c
> +++ b/attrib/gatttool.c
> @@ -42,6 +42,7 @@
>  #include "gattrib.h"
>  #include "glib-helper.h"
>  #include "gatt.h"
> +#include "gatttool.h"
>  
>  /* Minimum MTU for L2CAP connections over BR/EDR */
>  #define ATT_MIN_MTU_L2CAP 48
> @@ -63,6 +64,7 @@ static gboolean opt_listen = FALSE;
>  static gboolean opt_char_desc = FALSE;
>  static gboolean opt_le = FALSE;
>  static gboolean opt_char_write = FALSE;
> +static gboolean opt_interactive = FALSE;
>  static GMainLoop *event_loop;
>  static gboolean got_error = FALSE;
>  
> @@ -537,6 +539,8 @@ static GOptionEntry gatt_options[] = {
>  		"Listen for notifications and indications", NULL },
>  	{ "le", 0, 0, G_OPTION_ARG_NONE, &opt_le,
>  		"Use Bluetooth Low Energy transport", NULL },
> +	{ "interactive", 'I', G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_NONE,
> +		&opt_interactive, "Use interactive mode", NULL },
>  	{ NULL },
>  };
>  
> @@ -594,6 +598,11 @@ int main(int argc, char *argv[])
>  		g_error_free(gerr);
>  	}
>  
> +	if (opt_interactive) {
> +		interactive();
> +		goto done;
> +	}
> +
>  	if (opt_primary)
>  		callback = primary;
>  	else if (opt_characteristics)
> diff --git a/attrib/gatttool.h b/attrib/gatttool.h
> new file mode 100644
> index 0000000..ed5d9d6
> --- /dev/null
> +++ b/attrib/gatttool.h
> @@ -0,0 +1,24 @@
> +/*
> + *
> + *  BlueZ - Bluetooth protocol stack for Linux
> + *
> + *  Copyright (C) 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
> + *
> + */
> +
> +int interactive(void);
> diff --git a/attrib/interactive.c b/attrib/interactive.c
> new file mode 100644
> index 0000000..0653609
> --- /dev/null
> +++ b/attrib/interactive.c
> @@ -0,0 +1,128 @@
> +/*
> + *
> + *  BlueZ - Bluetooth protocol stack for Linux
> + *
> + *  Copyright (C) 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
> + *
> + */
> +#include <strings.h>
> +#include <stdlib.h>
> +#include <stdio.h>
> +#include <glib.h>
> +
> +#include <readline/readline.h>
> +#include <readline/history.h>
> +
> +#include "gatttool.h"
> +
> +static GMainLoop *event_loop;
> +
> +static void cmd_help(int argcp, char **argvp);

Just move cmd_help() up to avoid this.

> +
> +static void cmd_exit(int argcp, char **argvp)
> +{
> +	rl_callback_handler_remove();
> +	g_main_loop_quit(event_loop);
> +}
> +
> +static struct {
> +	const char *cmd;
> +	void (*func)(int argcp, char **argvp);
> +	const char *desc;
> +} commands[] = {
> +	{ "help",	cmd_help,	"Show this help"},
> +	{ "exit",	cmd_exit,	"Exit interactive mode"},
> +	{ NULL, NULL, NULL}
> +};
> +
> +static void cmd_help(int argcp, char **argvp)
> +{
> +	int i;
> +
> +	for (i = 0; commands[i].cmd; i++)
> +		printf("%-12s\t%s\n", commands[i].cmd, commands[i].desc);
> +}
> +
> +static void parse_line(char *line_read)
> +{
> +	gchar **argvp;
> +	int argcp;
> +	int i;
> +
> +	if (line_read == NULL) {
> +		printf("\n");
> +		cmd_exit(0, NULL);
> +		return;
> +	}
> +
> +	line_read = g_strstrip(line_read);
> +
> +	if (*line_read == '\0')
> +		return;
> +
> +	add_history(line_read);
> +
> +	g_shell_parse_argv(line_read, &argcp, &argvp, NULL);
> +
> +	for (i = 0; commands[i].cmd; i++)
> +		if (strcasecmp(commands[i].cmd, argvp[0]) == 0)
> +			break;
> +
> +	if (commands[i].cmd)
> +		commands[i].func(argcp, argvp);
> +	else
> +		printf("%s: command not found\n", argvp[0]);
> +
> +	g_strfreev(argvp);
> +}
> +
> +static gboolean prompt_read(GIOChannel *chan, GIOCondition cond,
> +							gpointer user_data)
> +{
> +	if (cond & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) {
> +		g_io_channel_unref(chan);
> +		return FALSE;
> +	}
> +
> +	rl_callback_read_char();
> +
> +	return TRUE;
> +}
> +
> +int interactive(void)
> +{
> +	GIOChannel *pchan;
> +	gint events;
> +
> +	event_loop = g_main_loop_new(NULL, FALSE);
> +
> +	pchan = g_io_channel_unix_new(fileno(stdin));
> +	g_io_channel_set_close_on_unref(pchan, TRUE);

Please add a blank line here.

-- 
Gustavo F. Padovan
http://profusion.mobi

^ permalink raw reply	[flat|nested] 20+ messages in thread

* Re: [PATCH v3 2/3] Add an initial interactive mode to gatttool
  2011-02-14 18:13       ` Gustavo F. Padovan
@ 2011-02-14 18:40         ` Sheldon Demario
  0 siblings, 0 replies; 20+ messages in thread
From: Sheldon Demario @ 2011-02-14 18:40 UTC (permalink / raw)
  To: Gustavo F. Padovan; +Cc: linux-bluetooth

Hi Gustavo,

On Mon, Feb 14, 2011 at 3:13 PM, Gustavo F. Padovan
<padovan@profusion.mobi> wrote:
> Hi Sheldon,
>
> * Sheldon Demario <sheldon.demario@openbossa.org> [2011-02-14 12:07:19 -0300]:
>
>> Mode required to allow better GATT procedures control. Some scenarios
>> require sequential commands without disconnection and delay between
>> operations. It is also desirable to change some connection parameters
>> of an active connection.
>> ---
>>  Makefile.am          |    8 ++-
>>  attrib/gatttool.c    |    9 ++++
>>  attrib/gatttool.h    |   24 +++++++++
>>  attrib/interactive.c |  128 ++++++++++++++++++++++++++++++++++++++++++++++++++
>>  configure.ac         |    1 +
>>  5 files changed, 168 insertions(+), 2 deletions(-)
>>  create mode 100644 attrib/gatttool.h
>>  create mode 100644 attrib/interactive.c
>>
>> diff --git a/Makefile.am b/Makefile.am
>> index e6639a7..11f990b 100644
>> --- a/Makefile.am
>> +++ b/Makefile.am
>> @@ -175,12 +175,16 @@ builtin_sources += plugins/service.c
>>  endif
>>
>>  if ATTRIBPLUGIN
>> +
>> +if READLINE
>
> Is that really needed? You already checked for READLINE in ./configure at
> this point.

Actually ./configure just check if it exists and doesn't fail if so.
The libreadline doesn't have pkgconfig files to make  this process
easy, thats why it is just not compiled if it is missing.

>
>>  bin_PROGRAMS += attrib/gatttool
>>
>>  attrib_gatttool_SOURCES = attrib/gatttool.c attrib/att.c attrib/gatt.c \
>>                         attrib/gattrib.c btio/btio.c \
>> -                       src/glib-helper.h src/glib-helper.c
>> -attrib_gatttool_LDADD = lib/libbluetooth.la @GLIB_LIBS@
>> +                       src/glib-helper.h src/glib-helper.c \
>> +                       attrib/gatttool.h attrib/interactive.c
>> +attrib_gatttool_LDADD = lib/libbluetooth.la @GLIB_LIBS@ @READLINE_LIBS@
>> +endif
>>
>>  builtin_modules += attrib
>>  builtin_sources += attrib/main.c \
>> diff --git a/attrib/gatttool.c b/attrib/gatttool.c
>> index 8e8ed8e..d663eb5 100644
>> --- a/attrib/gatttool.c
>> +++ b/attrib/gatttool.c
>> @@ -42,6 +42,7 @@
>>  #include "gattrib.h"
>>  #include "glib-helper.h"
>>  #include "gatt.h"
>> +#include "gatttool.h"
>>
>>  /* Minimum MTU for L2CAP connections over BR/EDR */
>>  #define ATT_MIN_MTU_L2CAP 48
>> @@ -63,6 +64,7 @@ static gboolean opt_listen = FALSE;
>>  static gboolean opt_char_desc = FALSE;
>>  static gboolean opt_le = FALSE;
>>  static gboolean opt_char_write = FALSE;
>> +static gboolean opt_interactive = FALSE;
>>  static GMainLoop *event_loop;
>>  static gboolean got_error = FALSE;
>>
>> @@ -537,6 +539,8 @@ static GOptionEntry gatt_options[] = {
>>               "Listen for notifications and indications", NULL },
>>       { "le", 0, 0, G_OPTION_ARG_NONE, &opt_le,
>>               "Use Bluetooth Low Energy transport", NULL },
>> +     { "interactive", 'I', G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_NONE,
>> +             &opt_interactive, "Use interactive mode", NULL },
>>       { NULL },
>>  };
>>
>> @@ -594,6 +598,11 @@ int main(int argc, char *argv[])
>>               g_error_free(gerr);
>>       }
>>
>> +     if (opt_interactive) {
>> +             interactive();
>> +             goto done;
>> +     }
>> +
>>       if (opt_primary)
>>               callback = primary;
>>       else if (opt_characteristics)
>> diff --git a/attrib/gatttool.h b/attrib/gatttool.h
>> new file mode 100644
>> index 0000000..ed5d9d6
>> --- /dev/null
>> +++ b/attrib/gatttool.h
>> @@ -0,0 +1,24 @@
>> +/*
>> + *
>> + *  BlueZ - Bluetooth protocol stack for Linux
>> + *
>> + *  Copyright (C) 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
>> + *
>> + */
>> +
>> +int interactive(void);
>> diff --git a/attrib/interactive.c b/attrib/interactive.c
>> new file mode 100644
>> index 0000000..0653609
>> --- /dev/null
>> +++ b/attrib/interactive.c
>> @@ -0,0 +1,128 @@
>> +/*
>> + *
>> + *  BlueZ - Bluetooth protocol stack for Linux
>> + *
>> + *  Copyright (C) 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
>> + *
>> + */
>> +#include <strings.h>
>> +#include <stdlib.h>
>> +#include <stdio.h>
>> +#include <glib.h>
>> +
>> +#include <readline/readline.h>
>> +#include <readline/history.h>
>> +
>> +#include "gatttool.h"
>> +
>> +static GMainLoop *event_loop;
>> +
>> +static void cmd_help(int argcp, char **argvp);
>
> Just move cmd_help() up to avoid this.
>
>> +
>> +static void cmd_exit(int argcp, char **argvp)
>> +{
>> +     rl_callback_handler_remove();
>> +     g_main_loop_quit(event_loop);
>> +}
>> +
>> +static struct {
>> +     const char *cmd;
>> +     void (*func)(int argcp, char **argvp);
>> +     const char *desc;
>> +} commands[] = {
>> +     { "help",       cmd_help,       "Show this help"},
>> +     { "exit",       cmd_exit,       "Exit interactive mode"},
>> +     { NULL, NULL, NULL}
>> +};
>> +
>> +static void cmd_help(int argcp, char **argvp)
>> +{
>> +     int i;
>> +
>> +     for (i = 0; commands[i].cmd; i++)
>> +             printf("%-12s\t%s\n", commands[i].cmd, commands[i].desc);
>> +}
>> +
>> +static void parse_line(char *line_read)
>> +{
>> +     gchar **argvp;
>> +     int argcp;
>> +     int i;
>> +
>> +     if (line_read == NULL) {
>> +             printf("\n");
>> +             cmd_exit(0, NULL);
>> +             return;
>> +     }
>> +
>> +     line_read = g_strstrip(line_read);
>> +
>> +     if (*line_read == '\0')
>> +             return;
>> +
>> +     add_history(line_read);
>> +
>> +     g_shell_parse_argv(line_read, &argcp, &argvp, NULL);
>> +
>> +     for (i = 0; commands[i].cmd; i++)
>> +             if (strcasecmp(commands[i].cmd, argvp[0]) == 0)
>> +                     break;
>> +
>> +     if (commands[i].cmd)
>> +             commands[i].func(argcp, argvp);
>> +     else
>> +             printf("%s: command not found\n", argvp[0]);
>> +
>> +     g_strfreev(argvp);
>> +}
>> +
>> +static gboolean prompt_read(GIOChannel *chan, GIOCondition cond,
>> +                                                     gpointer user_data)
>> +{
>> +     if (cond & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) {
>> +             g_io_channel_unref(chan);
>> +             return FALSE;
>> +     }
>> +
>> +     rl_callback_read_char();
>> +
>> +     return TRUE;
>> +}
>> +
>> +int interactive(void)
>> +{
>> +     GIOChannel *pchan;
>> +     gint events;
>> +
>> +     event_loop = g_main_loop_new(NULL, FALSE);
>> +
>> +     pchan = g_io_channel_unix_new(fileno(stdin));
>> +     g_io_channel_set_close_on_unref(pchan, TRUE);
>
> Please add a blank line here.
>
> --
> Gustavo F. Padovan
> http://profusion.mobi
>

Sheldon

^ permalink raw reply	[flat|nested] 20+ messages in thread

* [PATCH v4] Add an initial interactive mode to gatttool
  2011-02-09 21:26   ` Johan Hedberg
                       ` (8 preceding siblings ...)
  2011-02-14 15:07     ` [PATCH v3 3/3] Add connect/disconnect options on interactive mode of gatttool Sheldon Demario
@ 2011-02-15 17:09     ` Sheldon Demario
  9 siblings, 0 replies; 20+ messages in thread
From: Sheldon Demario @ 2011-02-15 17:09 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Sheldon Demario

Mode required to allow better GATT procedures control. Some scenarios
require sequential commands without disconnection and delay between
operations. It is also desirable to change some connection parameters
of an active connection.
---
 Makefile.am          |    8 ++-
 attrib/gatttool.c    |    9 ++++
 attrib/gatttool.h    |   24 +++++++++
 attrib/interactive.c |  128 ++++++++++++++++++++++++++++++++++++++++++++++++++
 configure.ac         |    1 +
 5 files changed, 168 insertions(+), 2 deletions(-)
 create mode 100644 attrib/gatttool.h
 create mode 100644 attrib/interactive.c

diff --git a/Makefile.am b/Makefile.am
index 275f511..7e5d0ee 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -175,12 +175,16 @@ builtin_sources += plugins/service.c
 endif
 
 if ATTRIBPLUGIN
+
+if READLINE
 bin_PROGRAMS += attrib/gatttool
 
 attrib_gatttool_SOURCES = attrib/gatttool.c attrib/att.c attrib/gatt.c \
 			  attrib/gattrib.c btio/btio.c \
-			  src/glib-helper.h src/glib-helper.c
-attrib_gatttool_LDADD = lib/libbluetooth.la @GLIB_LIBS@
+			  src/glib-helper.h src/glib-helper.c \
+			  attrib/gatttool.h attrib/interactive.c
+attrib_gatttool_LDADD = lib/libbluetooth.la @GLIB_LIBS@ @READLINE_LIBS@
+endif
 
 builtin_modules += attrib
 builtin_sources += attrib/main.c \
diff --git a/attrib/gatttool.c b/attrib/gatttool.c
index b9f0087..c3d0472 100644
--- a/attrib/gatttool.c
+++ b/attrib/gatttool.c
@@ -42,6 +42,7 @@
 #include "gattrib.h"
 #include "glib-helper.h"
 #include "gatt.h"
+#include "gatttool.h"
 
 /* Minimum MTU for L2CAP connections over BR/EDR */
 #define ATT_MIN_MTU_L2CAP 48
@@ -64,6 +65,7 @@ static gboolean opt_char_desc = FALSE;
 static gboolean opt_le = FALSE;
 static gboolean opt_char_write = FALSE;
 static gboolean opt_char_write_req = FALSE;
+static gboolean opt_interactive = FALSE;
 static GMainLoop *event_loop;
 static gboolean got_error = FALSE;
 
@@ -594,6 +596,8 @@ static GOptionEntry gatt_options[] = {
 		"Listen for notifications and indications", NULL },
 	{ "le", 0, 0, G_OPTION_ARG_NONE, &opt_le,
 		"Use Bluetooth Low Energy transport", NULL },
+	{ "interactive", 'I', G_OPTION_FLAG_IN_MAIN, G_OPTION_ARG_NONE,
+		&opt_interactive, "Use interactive mode", NULL },
 	{ NULL },
 };
 
@@ -651,6 +655,11 @@ int main(int argc, char *argv[])
 		g_error_free(gerr);
 	}
 
+	if (opt_interactive) {
+		interactive();
+		goto done;
+	}
+
 	if (opt_primary)
 		callback = primary;
 	else if (opt_characteristics)
diff --git a/attrib/gatttool.h b/attrib/gatttool.h
new file mode 100644
index 0000000..ed5d9d6
--- /dev/null
+++ b/attrib/gatttool.h
@@ -0,0 +1,24 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 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
+ *
+ */
+
+int interactive(void);
diff --git a/attrib/interactive.c b/attrib/interactive.c
new file mode 100644
index 0000000..0653609
--- /dev/null
+++ b/attrib/interactive.c
@@ -0,0 +1,128 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 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
+ *
+ */
+#include <strings.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <glib.h>
+
+#include <readline/readline.h>
+#include <readline/history.h>
+
+#include "gatttool.h"
+
+static GMainLoop *event_loop;
+
+static void cmd_help(int argcp, char **argvp);
+
+static void cmd_exit(int argcp, char **argvp)
+{
+	rl_callback_handler_remove();
+	g_main_loop_quit(event_loop);
+}
+
+static struct {
+	const char *cmd;
+	void (*func)(int argcp, char **argvp);
+	const char *desc;
+} commands[] = {
+	{ "help",	cmd_help,	"Show this help"},
+	{ "exit",	cmd_exit,	"Exit interactive mode"},
+	{ NULL, NULL, NULL}
+};
+
+static void cmd_help(int argcp, char **argvp)
+{
+	int i;
+
+	for (i = 0; commands[i].cmd; i++)
+		printf("%-12s\t%s\n", commands[i].cmd, commands[i].desc);
+}
+
+static void parse_line(char *line_read)
+{
+	gchar **argvp;
+	int argcp;
+	int i;
+
+	if (line_read == NULL) {
+		printf("\n");
+		cmd_exit(0, NULL);
+		return;
+	}
+
+	line_read = g_strstrip(line_read);
+
+	if (*line_read == '\0')
+		return;
+
+	add_history(line_read);
+
+	g_shell_parse_argv(line_read, &argcp, &argvp, NULL);
+
+	for (i = 0; commands[i].cmd; i++)
+		if (strcasecmp(commands[i].cmd, argvp[0]) == 0)
+			break;
+
+	if (commands[i].cmd)
+		commands[i].func(argcp, argvp);
+	else
+		printf("%s: command not found\n", argvp[0]);
+
+	g_strfreev(argvp);
+}
+
+static gboolean prompt_read(GIOChannel *chan, GIOCondition cond,
+							gpointer user_data)
+{
+	if (cond & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) {
+		g_io_channel_unref(chan);
+		return FALSE;
+	}
+
+	rl_callback_read_char();
+
+	return TRUE;
+}
+
+int interactive(void)
+{
+	GIOChannel *pchan;
+	gint events;
+
+	event_loop = g_main_loop_new(NULL, FALSE);
+
+	pchan = g_io_channel_unix_new(fileno(stdin));
+	g_io_channel_set_close_on_unref(pchan, TRUE);
+	events = G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL;
+	g_io_add_watch(pchan, events, prompt_read, NULL);
+
+	rl_callback_handler_install("> ", parse_line);
+
+	g_main_loop_run(event_loop);
+
+	rl_callback_handler_remove();
+	g_io_channel_unref(pchan);
+	g_main_loop_unref(event_loop);
+
+	return 0;
+}
diff --git a/configure.ac b/configure.ac
index 88dd177..0002af2 100644
--- a/configure.ac
+++ b/configure.ac
@@ -42,6 +42,7 @@ AC_PATH_GSTREAMER
 AC_PATH_USB
 AC_PATH_SNDFILE
 AC_PATH_OUI
+AC_PATH_READLINE
 
 AC_ARG_BLUEZ
 
-- 
1.7.1


^ permalink raw reply related	[flat|nested] 20+ messages in thread

* Re: [PATCH v3 1/3] Include check to readline lib on acinlude.m4
  2011-02-14 15:07     ` [PATCH v3 1/3] Include check to readline lib on acinlude.m4 Sheldon Demario
@ 2011-02-15 17:20       ` Johan Hedberg
  0 siblings, 0 replies; 20+ messages in thread
From: Johan Hedberg @ 2011-02-15 17:20 UTC (permalink / raw)
  To: Sheldon Demario; +Cc: linux-bluetooth

Hi Sheldon,

On Mon, Feb 14, 2011, Sheldon Demario wrote:
> ---
>  acinclude.m4 |   10 ++++++++++
>  1 files changed, 10 insertions(+), 0 deletions(-)

All three patches (v4 of 2/3) have been pushed upstream. Thanks.

Johan

^ permalink raw reply	[flat|nested] 20+ messages in thread

end of thread, other threads:[~2011-02-15 17:20 UTC | newest]

Thread overview: 20+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-02-08 15:32 [PATCH 1/5] Put all gatttool global options in a unique struct Sheldon Demario
2011-02-08 15:32 ` [PATCH 2/5] Include check to readline lib on acinlude.m4 Sheldon Demario
2011-02-08 15:32 ` [PATCH 3/5] Add an initial interactive mode to gatttool Sheldon Demario
2011-02-09 21:26   ` Johan Hedberg
2011-02-10 17:14     ` Sheldon Demario
2011-02-10 17:23       ` Johan Hedberg
2011-02-11 14:17     ` [PATCH v2 1/5] Put all gatttool global options in a unique struct Sheldon Demario
2011-02-11 14:17     ` [PATCH v2 2/5] Include check to readline lib on acinlude.m4 Sheldon Demario
2011-02-11 14:17     ` [PATCH v2 3/5] Add an initial interactive mode to gatttool Sheldon Demario
2011-02-11 14:17     ` [PATCH v2 4/5] Move main_opts from gatttool.c to header file Sheldon Demario
2011-02-11 14:17     ` [PATCH v2 5/5] Add connect/disconnect options on interactive mode of gatttool Sheldon Demario
2011-02-14 15:07     ` [PATCH v3 1/3] Include check to readline lib on acinlude.m4 Sheldon Demario
2011-02-15 17:20       ` Johan Hedberg
2011-02-14 15:07     ` [PATCH v3 2/3] Add an initial interactive mode to gatttool Sheldon Demario
2011-02-14 18:13       ` Gustavo F. Padovan
2011-02-14 18:40         ` Sheldon Demario
2011-02-14 15:07     ` [PATCH v3 3/3] Add connect/disconnect options on interactive mode of gatttool Sheldon Demario
2011-02-15 17:09     ` [PATCH v4] Add an initial interactive mode to gatttool Sheldon Demario
2011-02-08 15:32 ` [PATCH 4/5] Move main_opts from gatttool.c to header file Sheldon Demario
2011-02-08 15:32 ` [PATCH 5/5] Add connect/disconnect options on interactive mode of gatttool Sheldon Demario

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.