* [PATCHv2 6/6] android: Add cap to bind to port < 1024
From: Andrei Emeltchenko @ 2013-10-16 8:46 UTC (permalink / raw)
To: linux-bluetooth
In-Reply-To: <1381913215-17957-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>
From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
For SDP server we need to bind to lower port, acquire this capability.
---
android/main.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
configure.ac | 4 ++++
2 files changed, 75 insertions(+)
diff --git a/android/main.c b/android/main.c
index 2b8675d..19d382a 100644
--- a/android/main.c
+++ b/android/main.c
@@ -32,6 +32,22 @@
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/prctl.h>
+#include <linux/capability.h>
+
+/**
+ * Include <sys/capability.h> for host build and
+ * also for Android 4.3 when it is added to bionic
+ */
+#if !defined(ANDROID) || (PLATFORM_SDK_VERSION > 17)
+#include <sys/capability.h>
+#endif
+
+#if defined(ANDROID)
+#include <private/android_filesystem_config.h>
+#endif
#include <glib.h>
@@ -232,6 +248,58 @@ static void cleanup_mgmt_interface(void)
mgmt_if = NULL;
}
+static bool set_capabilities(void)
+{
+ struct __user_cap_header_struct header;
+ struct __user_cap_data_struct cap;
+#if defined(ANDROID)
+ gid_t groups[] = {AID_NET_BT, AID_NET_BT_ADMIN, AID_NET_ADMIN};
+#endif
+
+ DBG("pid %d uid %d gid %d", getpid(), getuid(), getgid());
+
+ header.version = _LINUX_CAPABILITY_VERSION;
+
+ prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
+
+#if defined(ANDROID)
+ if (setgid(AID_BLUETOOTH) < 0)
+ warn("%s: setgid(): %s", __func__, strerror(errno));
+
+ if (setuid(AID_BLUETOOTH) < 0)
+ warn("%s: setuid(): %s", __func__, strerror(errno));
+#endif
+
+ header.version = _LINUX_CAPABILITY_VERSION;
+ header.pid = 0;
+
+ cap.effective = cap.permitted =
+ CAP_TO_MASK(CAP_SETGID) |
+ CAP_TO_MASK(CAP_NET_RAW) |
+ CAP_TO_MASK(CAP_NET_ADMIN) |
+ CAP_TO_MASK(CAP_NET_BIND_SERVICE);
+ cap.inheritable = 0;
+
+ if (capset(&header, &cap) < 0) {
+ error("%s: capset(): %s", __func__, strerror(errno));
+ return false;
+ }
+
+#if defined(ANDROID)
+ if (setgroups(sizeof(groups)/sizeof(groups[0]), groups) < 0)
+ warn("%s: setgroups: %s", __func__, strerror(errno));
+#endif
+ if (capget(&header, &cap) < 0)
+ error("%s: capget(): %s", __func__, strerror(errno));
+ else
+ DBG("Caps: eff: 0x%x, perm: 0x%x, inh: 0x%x", cap.effective,
+ cap.permitted, cap.inheritable);
+
+ DBG("pid %d uid %d gid %d", getpid(), getuid(), getgid());
+
+ return true;
+}
+
int main(int argc, char *argv[])
{
GOptionContext *context;
@@ -265,6 +333,9 @@ int main(int argc, char *argv[])
sigaction(SIGINT, &sa, NULL);
sigaction(SIGTERM, &sa, NULL);
+ if (!set_capabilities())
+ return EXIT_FAILURE;
+
if (!init_mgmt_interface())
return EXIT_FAILURE;
diff --git a/configure.ac b/configure.ac
index 7b1f64a..a14264f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -247,4 +247,8 @@ AC_ARG_ENABLE(android, AC_HELP_STRING([--enable-android],
[enable_android=${enableval}])
AM_CONDITIONAL(ANDROID, test "${enable_android}" = "yes")
+if (test "${enable_android}" = "yes"); then
+ AC_CHECK_LIB(cap, capget, dummy=yes, AC_MSG_ERROR(libcap is required))
+fi
+
AC_OUTPUT(Makefile src/bluetoothd.8 lib/bluez.pc)
--
1.7.10.4
^ permalink raw reply related
* Re: [PATCH 1/2] Bluetooth: Ignore A2MP data on non-BR/EDR links
From: Andrei Emeltchenko @ 2013-10-16 8:54 UTC (permalink / raw)
To: johan.hedberg; +Cc: linux-bluetooth
In-Reply-To: <1381912621-10238-1-git-send-email-johan.hedberg@gmail.com>
Hi Johan,
On Wed, Oct 16, 2013 at 11:37:00AM +0300, johan.hedberg@gmail.com wrote:
> From: Johan Hedberg <johan.hedberg@intel.com>
>
> The A2MP CID is only valid for BR/EDR transports. We should ignore A2MP
> data on non-BR/EDR links and refuse to create an amp_mgr object.
>
> Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
> ---
> net/bluetooth/a2mp.c | 3 +++
> 1 file changed, 3 insertions(+)
>
> diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
> index fe32a33..efcd108 100644
> --- a/net/bluetooth/a2mp.c
> +++ b/net/bluetooth/a2mp.c
> @@ -836,6 +836,9 @@ struct l2cap_chan *a2mp_channel_create(struct l2cap_conn *conn,
> {
> struct amp_mgr *mgr;
>
> + if (conn->hcon->type != ACL_LINK)
> + return NULL;
> +
Have you experienced this ever happened?
Best regards
Andrei Emeltchenko
^ permalink raw reply
* [PATCH] Bluetooth: Remove enable_hs declaration
From: Marcel Holtmann @ 2013-10-16 9:09 UTC (permalink / raw)
To: linux-bluetooth
This seems to be a left-over. The module parameter enable_hs has
been removed, but its extern declaration is still present. It is
not needed anymore, so just remove it.
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
---
include/net/bluetooth/hci.h | 2 --
1 file changed, 2 deletions(-)
diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h
index c8bc7bf..77a971a 100644
--- a/include/net/bluetooth/hci.h
+++ b/include/net/bluetooth/hci.h
@@ -1787,6 +1787,4 @@ struct hci_inquiry_req {
};
#define IREQ_CACHE_FLUSH 0x0001
-extern bool enable_hs;
-
#endif /* __HCI_H */
--
1.8.3.1
^ permalink raw reply related
* Re: [PATCH 1/2] Bluetooth: Ignore A2MP data on non-BR/EDR links
From: Marcel Holtmann @ 2013-10-16 9:10 UTC (permalink / raw)
To: Andrei Emeltchenko; +Cc: johan.hedberg, linux-bluetooth
In-Reply-To: <20131016085445.GL2861@aemeltch-MOBL1>
Hi Andrei,
>> The A2MP CID is only valid for BR/EDR transports. We should ignore A2MP
>> data on non-BR/EDR links and refuse to create an amp_mgr object.
>>
>> Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
>> ---
>> net/bluetooth/a2mp.c | 3 +++
>> 1 file changed, 3 insertions(+)
>>
>> diff --git a/net/bluetooth/a2mp.c b/net/bluetooth/a2mp.c
>> index fe32a33..efcd108 100644
>> --- a/net/bluetooth/a2mp.c
>> +++ b/net/bluetooth/a2mp.c
>> @@ -836,6 +836,9 @@ struct l2cap_chan *a2mp_channel_create(struct l2cap_conn *conn,
>> {
>> struct amp_mgr *mgr;
>>
>> + if (conn->hcon->type != ACL_LINK)
>> + return NULL;
>> +
>
> Have you experienced this ever happened?
this is how good software is written. You check that your input is valid first. Otherwise you open yourself up to vulnerabilities.
Regards
Marcel
^ permalink raw reply
* Re: [PATCH] Bluetooth: Remove enable_hs declaration
From: Johan Hedberg @ 2013-10-16 9:29 UTC (permalink / raw)
To: Marcel Holtmann; +Cc: linux-bluetooth
In-Reply-To: <1381914541-48086-1-git-send-email-marcel@holtmann.org>
Hi Marcel,
On Wed, Oct 16, 2013, Marcel Holtmann wrote:
> This seems to be a left-over. The module parameter enable_hs has
> been removed, but its extern declaration is still present. It is
> not needed anymore, so just remove it.
>
> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
> ---
> include/net/bluetooth/hci.h | 2 --
> 1 file changed, 2 deletions(-)
Applied to bluetooth-next. Thanks.
Johan
^ permalink raw reply
* Re: [PATCHv2 1/6] sdp: Check that correct packet received in recv
From: Johan Hedberg @ 2013-10-16 10:21 UTC (permalink / raw)
To: Andrei Emeltchenko; +Cc: linux-bluetooth
In-Reply-To: <1381913215-17957-2-git-send-email-Andrei.Emeltchenko.news@gmail.com>
Hi Andrei,
On Wed, Oct 16, 2013, Andrei Emeltchenko wrote:
> ---
> unit/test-sdp.c | 5 ++---
> 1 file changed, 2 insertions(+), 3 deletions(-)
This patch has been applied. Thanks.
Johan
^ permalink raw reply
* Re: [PATCHv2 2/6] android: Create HAL API header skeleton
From: Johan Hedberg @ 2013-10-16 10:23 UTC (permalink / raw)
To: Andrei Emeltchenko; +Cc: linux-bluetooth
In-Reply-To: <1381913215-17957-3-git-send-email-Andrei.Emeltchenko.news@gmail.com>
Hi Andrei,
On Wed, Oct 16, 2013, Andrei Emeltchenko wrote:
> Header describes the protocol between Android HAL threads and BlueZ
> daemon.
> ---
> android/hal-msg.h | 246 +++++++++++++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 246 insertions(+)
> create mode 100644 android/hal-msg.h
Where's the code/patch that adds this to "make dist"?
Johan
^ permalink raw reply
* Re: [PATCHv2 3/6] android: Add basic mgmt initialization sequence
From: Johan Hedberg @ 2013-10-16 10:28 UTC (permalink / raw)
To: Andrei Emeltchenko; +Cc: linux-bluetooth
In-Reply-To: <1381913215-17957-4-git-send-email-Andrei.Emeltchenko.news@gmail.com>
Hi Andrei,
On Wed, Oct 16, 2013, Andrei Emeltchenko wrote:
> +static void read_index_list_complete(uint8_t status, uint16_t length,
> + const void *param, void *user_data)
> +{
> + const struct mgmt_rp_read_index_list *rp = param;
> + uint16_t num;
> + int i;
> +
> + info(__func__);
Seems like this one should just be a DBG("") (or just remove it
completely).
> + num = btohs(rp->num_controllers);
> +
> + DBG("%s: Number of controllers: %u", __func__, num);
Again, the __func__ seems redundant since this is a DBG() call.
Johan
^ permalink raw reply
* [PATCH] Bluetooth: Expose inquiry_cache debugfs only on BR/EDR controllers
From: Marcel Holtmann @ 2013-10-16 10:28 UTC (permalink / raw)
To: linux-bluetooth
The inquiry_cache debugfs entry is only valid for BR/EDR capable
controllers. In case of single mode LE-only controllers that
entry is not valid.
Move the creating of the debugfs entries to the end of controller
init and only create the inquiry_cache entry if BR/EDR is actually
supported.
At the same time this avoids creating any debugfs entries for
AMP controllers since none of the entries are valid there.
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
---
net/bluetooth/hci_core.c | 57 +++++++++++++++++++++++++++++++++++++++++++++--
net/bluetooth/hci_sysfs.c | 39 --------------------------------
2 files changed, 55 insertions(+), 41 deletions(-)
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index 2af0bac..73c8def 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -27,8 +27,8 @@
#include <linux/export.h>
#include <linux/idr.h>
-
#include <linux/rfkill.h>
+#include <linux/debugfs.h>
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
@@ -55,6 +55,44 @@ static void hci_notify(struct hci_dev *hdev, int event)
hci_sock_dev_event(hdev, event);
}
+/* ---- HCI debugfs entries ---- */
+
+static int inquiry_cache_show(struct seq_file *f, void *p)
+{
+ struct hci_dev *hdev = f->private;
+ struct discovery_state *cache = &hdev->discovery;
+ struct inquiry_entry *e;
+
+ hci_dev_lock(hdev);
+
+ list_for_each_entry(e, &cache->all, all) {
+ struct inquiry_data *data = &e->data;
+ seq_printf(f, "%pMR %d %d %d 0x%.2x%.2x%.2x 0x%.4x %d %d %u\n",
+ &data->bdaddr,
+ data->pscan_rep_mode, data->pscan_period_mode,
+ data->pscan_mode, data->dev_class[2],
+ data->dev_class[1], data->dev_class[0],
+ __le16_to_cpu(data->clock_offset),
+ data->rssi, data->ssp_mode, e->timestamp);
+ }
+
+ hci_dev_unlock(hdev);
+
+ return 0;
+}
+
+static int inquiry_cache_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, inquiry_cache_show, inode->i_private);
+}
+
+static const struct file_operations inquiry_cache_fops = {
+ .open = inquiry_cache_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
/* ---- HCI requests ---- */
static void hci_req_sync_complete(struct hci_dev *hdev, u8 result)
@@ -734,7 +772,22 @@ static int __hci_init(struct hci_dev *hdev)
if (err < 0)
return err;
- return __hci_req_sync(hdev, hci_init4_req, 0, HCI_INIT_TIMEOUT);
+ err = __hci_req_sync(hdev, hci_init4_req, 0, HCI_INIT_TIMEOUT);
+ if (err < 0)
+ return err;
+
+ /* Only create debugfs entries during the initial setup
+ * phase and not every time the controller gets powered on.
+ */
+ if (!test_bit(HCI_SETUP, &hdev->dev_flags))
+ return 0;
+
+ if (lmp_bredr_capable(hdev)) {
+ debugfs_create_file("inquiry_cache", 0444, hdev->debugfs,
+ hdev, &inquiry_cache_fops);
+ }
+
+ return 0;
}
static void hci_scan_req(struct hci_request *req, unsigned long opt)
diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c
index edf623a..65ecb9e 100644
--- a/net/bluetooth/hci_sysfs.c
+++ b/net/bluetooth/hci_sysfs.c
@@ -396,42 +396,6 @@ static struct device_type bt_host = {
.release = bt_host_release,
};
-static int inquiry_cache_show(struct seq_file *f, void *p)
-{
- struct hci_dev *hdev = f->private;
- struct discovery_state *cache = &hdev->discovery;
- struct inquiry_entry *e;
-
- hci_dev_lock(hdev);
-
- list_for_each_entry(e, &cache->all, all) {
- struct inquiry_data *data = &e->data;
- seq_printf(f, "%pMR %d %d %d 0x%.2x%.2x%.2x 0x%.4x %d %d %u\n",
- &data->bdaddr,
- data->pscan_rep_mode, data->pscan_period_mode,
- data->pscan_mode, data->dev_class[2],
- data->dev_class[1], data->dev_class[0],
- __le16_to_cpu(data->clock_offset),
- data->rssi, data->ssp_mode, e->timestamp);
- }
-
- hci_dev_unlock(hdev);
-
- return 0;
-}
-
-static int inquiry_cache_open(struct inode *inode, struct file *file)
-{
- return single_open(file, inquiry_cache_show, inode->i_private);
-}
-
-static const struct file_operations inquiry_cache_fops = {
- .open = inquiry_cache_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
static int blacklist_show(struct seq_file *f, void *p)
{
struct hci_dev *hdev = f->private;
@@ -562,9 +526,6 @@ int hci_add_sysfs(struct hci_dev *hdev)
if (!hdev->debugfs)
return 0;
- debugfs_create_file("inquiry_cache", 0444, hdev->debugfs,
- hdev, &inquiry_cache_fops);
-
debugfs_create_file("blacklist", 0444, hdev->debugfs,
hdev, &blacklist_fops);
--
1.8.3.1
^ permalink raw reply related
* Re: [PATCHv2 4/6] android: Add adapter and device struct for BlueZ daemon
From: Johan Hedberg @ 2013-10-16 10:31 UTC (permalink / raw)
To: Andrei Emeltchenko; +Cc: linux-bluetooth
In-Reply-To: <1381913215-17957-5-git-send-email-Andrei.Emeltchenko.news@gmail.com>
On Wed, Oct 16, 2013, Andrei Emeltchenko wrote:
> +struct bt_adapter {
> + struct mgmt *mgmt;
> + bdaddr_t bdaddr;
> + uint32_t dev_class;
> +
> + char *name;
> +
> + uint32_t supported_settings;
> + uint32_t current_settings;
> +
> + GList *found_devices;
> +};
Please don't add variables this way if you don't have code that actually
uses them at least later in the patch set. Just add them when they
eventually are needed.
> +struct bt_device {
> + bdaddr_t bdaddr;
> + uint8_t bdaddr_type;
> + uint32_t cod;
> + char *name;
> +};
Same thing here.
Johan
^ permalink raw reply
* [PATCH] Bluetooth: Reintroduce socket restrictions for LE sockets
From: johan.hedberg @ 2013-10-16 10:37 UTC (permalink / raw)
To: linux-bluetooth
From: Johan Hedberg <johan.hedberg@intel.com>
Right now we do not allow user space to use connection oriented channels
on LE, and the only CID that can be used is the Attribute Protocol one.
These restrictions went away together with the recent refactoring of the
L2CAP code, but this patch puts them back to their appropriate places.
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
---
net/bluetooth/l2cap_sock.c | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/net/bluetooth/l2cap_sock.c b/net/bluetooth/l2cap_sock.c
index 68f486a..bda52d7 100644
--- a/net/bluetooth/l2cap_sock.c
+++ b/net/bluetooth/l2cap_sock.c
@@ -72,6 +72,16 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
if (!bdaddr_type_is_valid(la.l2_bdaddr_type))
return -EINVAL;
+ if (la.l2_bdaddr_type == BDADDR_LE_PUBLIC ||
+ la.l2_bdaddr_type == BDADDR_LE_RANDOM) {
+ /* Connection oriented channels are not supported on LE */
+ if (la.l2_psm)
+ return -EINVAL;
+ /* We only allow ATT user space socket */
+ if (la.l2_cid != L2CAP_CID_ATT)
+ return -EINVAL;
+ }
+
lock_sock(sk);
if (sk->sk_state != BT_OPEN) {
@@ -156,6 +166,16 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr,
if (chan->src_type != BDADDR_BREDR && la.l2_bdaddr_type == BDADDR_BREDR)
return -EINVAL;
+ if (la.l2_bdaddr_type == BDADDR_LE_PUBLIC ||
+ la.l2_bdaddr_type == BDADDR_LE_RANDOM) {
+ /* Connection oriented channels are not supported on LE */
+ if (la.l2_psm)
+ return -EINVAL;
+ /* We only allow ATT user space socket */
+ if (la.l2_cid != L2CAP_CID_ATT)
+ return -EINVAL;
+ }
+
err = l2cap_chan_connect(chan, la.l2_psm, __le16_to_cpu(la.l2_cid),
&la.l2_bdaddr, la.l2_bdaddr_type);
if (err)
--
1.8.3.1
^ permalink raw reply related
* Re: [PATCH 1/3] Bluetooth: Fix L2CAP "Command Reject: Invalid CID" response
From: Anderson Lizardo @ 2013-10-16 11:34 UTC (permalink / raw)
To: Johan Hedberg; +Cc: BlueZ development
In-Reply-To: <1381910801-3130-2-git-send-email-johan.hedberg@gmail.com>
Hi Johan,
On Wed, Oct 16, 2013 at 4:06 AM, <johan.hedberg@gmail.com> wrote:
> @@ -4217,8 +4225,8 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn,
>
> chan = __l2cap_get_chan_by_scid(conn, dcid);
> if (!chan) {
> - mutex_unlock(&conn->chan_lock);
> - return -EBADSLT;
> + cmd_reject_invalid_cid(conn, cmd->ident, dcid, scid);
> + return 0;
> }
>
> l2cap_chan_lock(chan);
Are you sure this mutex_unlock() call should be removed?
Best Regards,
--
Anderson Lizardo
Instituto Nokia de Tecnologia - INdT
Manaus - Brazil
^ permalink raw reply
* Re: [PATCH 1/3] Bluetooth: Fix L2CAP "Command Reject: Invalid CID" response
From: Johan Hedberg @ 2013-10-16 11:43 UTC (permalink / raw)
To: Anderson Lizardo; +Cc: BlueZ development
In-Reply-To: <CAJdJm_Pmjnag0HrK7N8T6Q5L138pYN4HDHcrwAQ-m_hEYsUyMA@mail.gmail.com>
Hi Lizardo,
On Wed, Oct 16, 2013, Anderson Lizardo wrote:
> On Wed, Oct 16, 2013 at 4:06 AM, <johan.hedberg@gmail.com> wrote:
> > @@ -4217,8 +4225,8 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn,
> >
> > chan = __l2cap_get_chan_by_scid(conn, dcid);
> > if (!chan) {
> > - mutex_unlock(&conn->chan_lock);
> > - return -EBADSLT;
> > + cmd_reject_invalid_cid(conn, cmd->ident, dcid, scid);
> > + return 0;
> > }
> >
> > l2cap_chan_lock(chan);
>
> Are you sure this mutex_unlock() call should be removed?
It was indeed a bug which got fixed before this went upstream. Good that
you spotted it too though.
Johan
^ permalink raw reply
* Re: [PATCHv2 3/6] android: Add basic mgmt initialization sequence
From: Szymon Janc @ 2013-10-16 12:03 UTC (permalink / raw)
To: Andrei Emeltchenko; +Cc: linux-bluetooth
In-Reply-To: <1381913215-17957-4-git-send-email-Andrei.Emeltchenko.news@gmail.com>
Hi Andrei,
> From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
>
> Initialize bluetooth controller via mgmt interface.
> ---
> Makefile.android | 4 +-
> android/Android.mk | 5 ++
> android/main.c | 168 ++++++++++++++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 176 insertions(+), 1 deletion(-)
>
> diff --git a/Makefile.android b/Makefile.android
> index 3ceefd8..7371a77 100644
> --- a/Makefile.android
> +++ b/Makefile.android
> @@ -1,7 +1,9 @@
> if ANDROID
> noinst_PROGRAMS += android/bluetoothd
>
> -android_bluetoothd_SOURCES = android/main.c src/log.c
> +android_bluetoothd_SOURCES = android/main.c src/log.c \
> + src/shared/util.h src/shared/util.c \
> + src/shared/mgmt.h src/shared/mgmt.c
> android_bluetoothd_LDADD = @GLIB_LIBS@
> endif
>
> diff --git a/android/Android.mk b/android/Android.mk
> index 0e025ac..4996080 100644
> --- a/android/Android.mk
> +++ b/android/Android.mk
> @@ -15,10 +15,15 @@ include $(CLEAR_VARS)
> LOCAL_SRC_FILES := \
> main.c \
> log.c \
> + ../src/shared/mgmt.c \
> + ../src/shared/util.c \
>
> LOCAL_C_INCLUDES := \
> $(call include-path-for, glib) \
> $(call include-path-for, glib)/glib \
> +
> +LOCAL_C_INCLUDES += \
> + $(LOCAL_PATH)/../ \
> $(LOCAL_PATH)/../src \
>
> LOCAL_CFLAGS := -DVERSION=\"$(BLUEZ_VERSION)\"
> diff --git a/android/main.c b/android/main.c
> index f75b0a8..ba25b84 100644
> --- a/android/main.c
> +++ b/android/main.c
> @@ -25,6 +25,7 @@
> #include <config.h>
> #endif
>
> +#include <stdbool.h>
> #include <signal.h>
> #include <stdint.h>
> #include <stdio.h>
> @@ -36,9 +37,17 @@
>
> #include "log.h"
>
> +#include "lib/bluetooth.h"
> +#include "lib/mgmt.h"
> +#include "src/shared/mgmt.h"
> +
> #define SHUTDOWN_GRACE_SECONDS 10
>
> static GMainLoop *event_loop;
> +static struct mgmt *mgmt_if = NULL;
> +
> +static uint8_t mgmt_version = 0;
> +static uint8_t mgmt_revision = 0;
>
> static gboolean quit_eventloop(gpointer user_data)
> {
> @@ -67,6 +76,161 @@ static GOptionEntry options[] = {
> { NULL }
> };
>
> +static void read_info_complete(uint8_t status, uint16_t length,
> + const void *param, void *user_data)
> +{
> + /* TODO: Store Controller information */
> +
> + /* TODO: Register all event notification handlers */
> +}
> +
> +
> +static void mgmt_index_added_event(uint16_t index, uint16_t length,
> + const void *param, void *user_data)
> +{
> + DBG("index %u", index);
> +
> + if (mgmt_send(mgmt_if, MGMT_OP_READ_INFO, index, 0, NULL,
> + read_info_complete, NULL, NULL) > 0)
> + return;
> +
> + error("Failed to read adapter info for index %u", index);
> +
> +}
> +
> +static void mgmt_index_removed_event(uint16_t index, uint16_t length,
> + const void *param, void *user_data)
> +{
> + DBG("index %u", index);
> +}
> +
> +static void read_index_list_complete(uint8_t status, uint16_t length,
> + const void *param, void *user_data)
> +{
> + const struct mgmt_rp_read_index_list *rp = param;
> + uint16_t num;
> + int i;
> +
> + info(__func__);
> +
> + if (!status) {
> + error("%s: Failed to read index list: %s (0x%02x)",
> + __func__, mgmt_errstr(status), status);
> + return;
> + }
> +
> + if (length < sizeof(*rp)) {
> + error("%s: Wrong size of read index list response", __func__);
> + return;
> + }
> +
> + num = btohs(rp->num_controllers);
> +
> + DBG("%s: Number of controllers: %u", __func__, num);
> +
> + if (num * sizeof(uint16_t) + sizeof(*rp) != length) {
> + error("%s: Incorrect pkt size for index list rsp", __func__);
> + return;
> + }
> +
> + for (i = 0; i < num; i++) {
> + uint16_t index;
> +
> + index = btohs(rp->index[i]);
> +
> + /**
> + * Use index added event notification.
> + */
> + mgmt_index_added_event(index, 0, NULL, NULL);
> + }
> +}
> +
> +static void read_commands_complete(uint8_t status, uint16_t length,
> + const void *param, void *user_data)
> +{
> + const struct mgmt_rp_read_commands *rp = param;
> +
> + DBG("");
> +
> + if (!status) {
> + error("Failed to read supported commands: %s (0x%02x)",
> + mgmt_errstr(status), status);
> + return;
> + }
This will always fail... I would use explicit comparison to MGMT status code
if (status != MGMT_STATUS_SUCCESS) { ... }
> +
> + if (length < sizeof(*rp)) {
> + error("Wrong size response");
> + return;
> + }
> +}
> +
> +static void read_version_complete(uint8_t status, uint16_t length,
> + const void *param, void *user_data)
> +{
> + const struct mgmt_rp_read_version *rp = param;
> +
> + DBG("");
> +
> + if (!status) {
> + error("Failed to read version information: %s (0x%02x)",
> + mgmt_errstr(status), status);
> + return;
> + }
Ditto.
> +
> + if (length < sizeof(*rp)) {
> + error("Wrong size response");
> + return;
> + }
> +
> + mgmt_version = rp->version;
> + mgmt_revision = btohs(rp->revision);
> +
> + info("Bluetooth management interface %u.%u initialized",
> + mgmt_version, mgmt_revision);
> +
> + if (mgmt_version < 1) {
> + error("Version 1.0 or later of management interface required");
> + abort();
> + }
> +
> + mgmt_send(mgmt_if, MGMT_OP_READ_COMMANDS, MGMT_INDEX_NONE, 0, NULL,
> + read_commands_complete, NULL, NULL);
> +
> + mgmt_register(mgmt_if, MGMT_EV_INDEX_ADDED, MGMT_INDEX_NONE,
> + mgmt_index_added_event, NULL, NULL);
> + mgmt_register(mgmt_if, MGMT_EV_INDEX_REMOVED, MGMT_INDEX_NONE,
> + mgmt_index_removed_event, NULL, NULL);
> +
> + if (mgmt_send(mgmt_if, MGMT_OP_READ_INDEX_LIST, MGMT_INDEX_NONE, 0,
> + NULL, read_index_list_complete, NULL, NULL) > 0)
> + return;
> +
> + error("Failed to read controller index list");
> +}
> +
> +static bool init_mgmt_interface(void)
> +{
> + mgmt_if = mgmt_new_default();
> + if (!mgmt_if) {
> + error("Failed to access management interface");
> + return false;
> + }
> +
> + if (mgmt_send(mgmt_if, MGMT_OP_READ_VERSION, MGMT_INDEX_NONE, 0, NULL,
> + read_version_complete, NULL, NULL) == 0) {
> + error("Error sending READ_VERSION mgmt command");
> + return false;
> + }
> +
> + return true;
> +}
> +
> +static void cleanup_mgmt_interface(void)
> +{
> + mgmt_unref(mgmt_if);
> + mgmt_if = NULL;
> +}
> +
> int main(int argc, char *argv[])
> {
> GOptionContext *context;
> @@ -100,10 +264,14 @@ int main(int argc, char *argv[])
> sigaction(SIGINT, &sa, NULL);
> sigaction(SIGTERM, &sa, NULL);
>
> + if (!init_mgmt_interface())
> + return EXIT_FAILURE;
> +
> DBG("Entering main loop");
>
> g_main_loop_run(event_loop);
>
> + cleanup_mgmt_interface();
> g_main_loop_unref(event_loop);
>
> info("Exit");
>
--
BR
Szymon Janc
^ permalink raw reply
* Re: [PATCH 3/6] Bluetooth: Set the scan response data when needed
From: Anderson Lizardo @ 2013-10-16 12:10 UTC (permalink / raw)
To: Marcel Holtmann; +Cc: BlueZ development
In-Reply-To: <1381907811-33872-3-git-send-email-marcel@holtmann.org>
Hi Marcel,
On Wed, Oct 16, 2013 at 3:16 AM, Marcel Holtmann <marcel@holtmann.org> wrote:
> +static void update_scan_rsp_data(struct hci_request *req)
> +{
> + struct hci_dev *hdev = req->hdev;
> + struct hci_cp_le_set_scan_rsp_data cp;
> + u8 len;
> +
> + if (!lmp_le_capable(hdev))
> + return;
> +
> + memset(&cp, 0, sizeof(cp));
> +
> + len = create_scan_rsp_data(hdev, cp.data);
> +
> + if (hdev->adv_data_len == len &&
> + memcmp(cp.data, hdev->adv_data, len) == 0)
> + return;
> +
> + memcpy(hdev->adv_data, cp.data, sizeof(cp.data));
> + hdev->adv_data_len = len;
Shouldn't you be using hdev->scan_rsp_data/scan_rsp_data_len here?
(I still haven't read the later patches, so this may already be fixed.)
> +
> + cp.length = len;
> +
> + hci_req_add(req, HCI_OP_LE_SET_SCAN_RSP_DATA, sizeof(cp), &cp);
> +}
Best Regards,
--
Anderson Lizardo
Instituto Nokia de Tecnologia - INdT
Manaus - Brazil
^ permalink raw reply
* Re: [PATCH v2 5/5] android: Add calls to adapter methods in haltest
From: Johan Hedberg @ 2013-10-16 12:21 UTC (permalink / raw)
To: Jerzy Kasenberg; +Cc: linux-bluetooth
In-Reply-To: <1381842800-3554-6-git-send-email-jerzy.kasenberg@tieto.com>
Hi Jerzy,
On Tue, Oct 15, 2013, Jerzy Kasenberg wrote:
> +static bt_callbacks_t bt_callbacks = {
> + sizeof(bt_callbacks),
> + adapter_state_changed_cb,
> + adapter_properties_cb,
> + remote_device_properties_cb,
> + device_found_cb,
> + discovery_state_changed_cb,
> + pin_request_cb,
> + ssp_request_cb,
> + bond_state_changed_cb,
> + acl_state_changed_cb,
> + thread_evt_cb,
> + dut_mode_recv_cb,
> + le_test_mode_cb
> +};
Could we get structure initializations like this to use follow the
coding style, i.e.:
static bt_callbacks_t bt_callbacks = {
.member1 = sizeof(),
.member2 = adapter_state_changed_cb,
...
};
This way you can directly see that the right members are initialized to
the right values and there's no risk that e.g. two members with the same
type are swapped (something the compiler wouldn't warn about).
As a general point to others working on the android code: if there are
any other similar places elsewhere in the code please fix those too.
> +static void init_p(int argc, const char **argv)
> +{
> + int err;
> + const hw_module_t *module;
> + hw_device_t *device;
> +
> + err = hw_get_module(BT_HARDWARE_MODULE_ID, &module);
> + if (err) {
> + haltest_error("he_get_module returned %d\n", err);
> + return;
> + }
> +
> + err = module->methods->open(module, BT_HARDWARE_MODULE_ID, &device);
> + if (err) {
> + haltest_error("module->methods->open returned %d\n", err);
> + return;
> + }
> +
> + if_bluetooth =
> + ((bluetooth_device_t *)device)->get_bluetooth_interface();
The user space coding style convention is to have a space between the
type cast and the variable. In this case you might make the code more
readable by adding an extra variable, something like:
bluetooth_device_t *btdev;
...
btdev = (bluetooth_device_t *) device;
if_bluetooth = btdev->get_bluetooth_interface();
...
Johan
^ permalink raw reply
* Re: [PATCHv2 3/6] android: Add basic mgmt initialization sequence
From: Andrei Emeltchenko @ 2013-10-16 12:24 UTC (permalink / raw)
To: Szymon Janc; +Cc: linux-bluetooth
In-Reply-To: <7351603.qM58B1tehZ@uw000953>
Hi Szymon,
On Wed, Oct 16, 2013 at 02:03:54PM +0200, Szymon Janc wrote:
> Hi Andrei,
>
> > From: Andrei Emeltchenko <andrei.emeltchenko@intel.com>
> >
> > Initialize bluetooth controller via mgmt interface.
> > ---
> > Makefile.android | 4 +-
> > android/Android.mk | 5 ++
> > android/main.c | 168 ++++++++++++++++++++++++++++++++++++++++++++++++++++
> > 3 files changed, 176 insertions(+), 1 deletion(-)
> >
> > diff --git a/Makefile.android b/Makefile.android
> > index 3ceefd8..7371a77 100644
> > --- a/Makefile.android
> > +++ b/Makefile.android
> > @@ -1,7 +1,9 @@
> > if ANDROID
> > noinst_PROGRAMS += android/bluetoothd
> >
> > -android_bluetoothd_SOURCES = android/main.c src/log.c
> > +android_bluetoothd_SOURCES = android/main.c src/log.c \
> > + src/shared/util.h src/shared/util.c \
> > + src/shared/mgmt.h src/shared/mgmt.c
> > android_bluetoothd_LDADD = @GLIB_LIBS@
> > endif
> >
> > diff --git a/android/Android.mk b/android/Android.mk
> > index 0e025ac..4996080 100644
> > --- a/android/Android.mk
> > +++ b/android/Android.mk
> > @@ -15,10 +15,15 @@ include $(CLEAR_VARS)
> > LOCAL_SRC_FILES := \
> > main.c \
> > log.c \
> > + ../src/shared/mgmt.c \
> > + ../src/shared/util.c \
> >
> > LOCAL_C_INCLUDES := \
> > $(call include-path-for, glib) \
> > $(call include-path-for, glib)/glib \
> > +
> > +LOCAL_C_INCLUDES += \
> > + $(LOCAL_PATH)/../ \
> > $(LOCAL_PATH)/../src \
> >
> > LOCAL_CFLAGS := -DVERSION=\"$(BLUEZ_VERSION)\"
> > diff --git a/android/main.c b/android/main.c
> > index f75b0a8..ba25b84 100644
> > --- a/android/main.c
> > +++ b/android/main.c
> > @@ -25,6 +25,7 @@
> > #include <config.h>
> > #endif
> >
> > +#include <stdbool.h>
> > #include <signal.h>
> > #include <stdint.h>
> > #include <stdio.h>
> > @@ -36,9 +37,17 @@
> >
> > #include "log.h"
> >
> > +#include "lib/bluetooth.h"
> > +#include "lib/mgmt.h"
> > +#include "src/shared/mgmt.h"
> > +
> > #define SHUTDOWN_GRACE_SECONDS 10
> >
> > static GMainLoop *event_loop;
> > +static struct mgmt *mgmt_if = NULL;
> > +
> > +static uint8_t mgmt_version = 0;
> > +static uint8_t mgmt_revision = 0;
> >
> > static gboolean quit_eventloop(gpointer user_data)
> > {
> > @@ -67,6 +76,161 @@ static GOptionEntry options[] = {
> > { NULL }
> > };
> >
> > +static void read_info_complete(uint8_t status, uint16_t length,
> > + const void *param, void *user_data)
> > +{
> > + /* TODO: Store Controller information */
> > +
> > + /* TODO: Register all event notification handlers */
> > +}
> > +
> > +
> > +static void mgmt_index_added_event(uint16_t index, uint16_t length,
> > + const void *param, void *user_data)
> > +{
> > + DBG("index %u", index);
> > +
> > + if (mgmt_send(mgmt_if, MGMT_OP_READ_INFO, index, 0, NULL,
> > + read_info_complete, NULL, NULL) > 0)
> > + return;
> > +
> > + error("Failed to read adapter info for index %u", index);
> > +
> > +}
> > +
> > +static void mgmt_index_removed_event(uint16_t index, uint16_t length,
> > + const void *param, void *user_data)
> > +{
> > + DBG("index %u", index);
> > +}
> > +
> > +static void read_index_list_complete(uint8_t status, uint16_t length,
> > + const void *param, void *user_data)
> > +{
> > + const struct mgmt_rp_read_index_list *rp = param;
> > + uint16_t num;
> > + int i;
> > +
> > + info(__func__);
> > +
> > + if (!status) {
> > + error("%s: Failed to read index list: %s (0x%02x)",
> > + __func__, mgmt_errstr(status), status);
> > + return;
> > + }
> > +
> > + if (length < sizeof(*rp)) {
> > + error("%s: Wrong size of read index list response", __func__);
> > + return;
> > + }
> > +
> > + num = btohs(rp->num_controllers);
> > +
> > + DBG("%s: Number of controllers: %u", __func__, num);
> > +
> > + if (num * sizeof(uint16_t) + sizeof(*rp) != length) {
> > + error("%s: Incorrect pkt size for index list rsp", __func__);
> > + return;
> > + }
> > +
> > + for (i = 0; i < num; i++) {
> > + uint16_t index;
> > +
> > + index = btohs(rp->index[i]);
> > +
> > + /**
> > + * Use index added event notification.
> > + */
> > + mgmt_index_added_event(index, 0, NULL, NULL);
> > + }
> > +}
> > +
> > +static void read_commands_complete(uint8_t status, uint16_t length,
> > + const void *param, void *user_data)
> > +{
> > + const struct mgmt_rp_read_commands *rp = param;
> > +
> > + DBG("");
> > +
> > + if (!status) {
> > + error("Failed to read supported commands: %s (0x%02x)",
> > + mgmt_errstr(status), status);
> > + return;
> > + }
>
> This will always fail... I would use explicit comparison to MGMT status code
> if (status != MGMT_STATUS_SUCCESS) { ... }
Yes, sorry this was automatic style change :( I just check for status
then.
Best regards
Andrei Emeltchenko
>
> > +
> > + if (length < sizeof(*rp)) {
> > + error("Wrong size response");
> > + return;
> > + }
> > +}
> > +
> > +static void read_version_complete(uint8_t status, uint16_t length,
> > + const void *param, void *user_data)
> > +{
> > + const struct mgmt_rp_read_version *rp = param;
> > +
> > + DBG("");
> > +
> > + if (!status) {
> > + error("Failed to read version information: %s (0x%02x)",
> > + mgmt_errstr(status), status);
> > + return;
> > + }
>
> Ditto.
>
> > +
> > + if (length < sizeof(*rp)) {
> > + error("Wrong size response");
> > + return;
> > + }
> > +
> > + mgmt_version = rp->version;
> > + mgmt_revision = btohs(rp->revision);
> > +
> > + info("Bluetooth management interface %u.%u initialized",
> > + mgmt_version, mgmt_revision);
> > +
> > + if (mgmt_version < 1) {
> > + error("Version 1.0 or later of management interface required");
> > + abort();
> > + }
> > +
> > + mgmt_send(mgmt_if, MGMT_OP_READ_COMMANDS, MGMT_INDEX_NONE, 0, NULL,
> > + read_commands_complete, NULL, NULL);
> > +
> > + mgmt_register(mgmt_if, MGMT_EV_INDEX_ADDED, MGMT_INDEX_NONE,
> > + mgmt_index_added_event, NULL, NULL);
> > + mgmt_register(mgmt_if, MGMT_EV_INDEX_REMOVED, MGMT_INDEX_NONE,
> > + mgmt_index_removed_event, NULL, NULL);
> > +
> > + if (mgmt_send(mgmt_if, MGMT_OP_READ_INDEX_LIST, MGMT_INDEX_NONE, 0,
> > + NULL, read_index_list_complete, NULL, NULL) > 0)
> > + return;
> > +
> > + error("Failed to read controller index list");
> > +}
> > +
> > +static bool init_mgmt_interface(void)
> > +{
> > + mgmt_if = mgmt_new_default();
> > + if (!mgmt_if) {
> > + error("Failed to access management interface");
> > + return false;
> > + }
> > +
> > + if (mgmt_send(mgmt_if, MGMT_OP_READ_VERSION, MGMT_INDEX_NONE, 0, NULL,
> > + read_version_complete, NULL, NULL) == 0) {
> > + error("Error sending READ_VERSION mgmt command");
> > + return false;
> > + }
> > +
> > + return true;
> > +}
> > +
> > +static void cleanup_mgmt_interface(void)
> > +{
> > + mgmt_unref(mgmt_if);
> > + mgmt_if = NULL;
> > +}
> > +
> > int main(int argc, char *argv[])
> > {
> > GOptionContext *context;
> > @@ -100,10 +264,14 @@ int main(int argc, char *argv[])
> > sigaction(SIGINT, &sa, NULL);
> > sigaction(SIGTERM, &sa, NULL);
> >
> > + if (!init_mgmt_interface())
> > + return EXIT_FAILURE;
> > +
> > DBG("Entering main loop");
> >
> > g_main_loop_run(event_loop);
> >
> > + cleanup_mgmt_interface();
> > g_main_loop_unref(event_loop);
> >
> > info("Exit");
> >
>
> --
> BR
> Szymon Janc
>
^ permalink raw reply
* Re: [PATCH 3/6] Bluetooth: Set the scan response data when needed
From: Johan Hedberg @ 2013-10-16 12:28 UTC (permalink / raw)
To: Anderson Lizardo; +Cc: Marcel Holtmann, BlueZ development
In-Reply-To: <CAJdJm_NtG8XyMYFL5DbiAiuwN=-kf-WFzckiiY_7uSpowTGKYA@mail.gmail.com>
Hi Lizardo,
On Wed, Oct 16, 2013, Anderson Lizardo wrote:
> On Wed, Oct 16, 2013 at 3:16 AM, Marcel Holtmann <marcel@holtmann.org> wrote:
> > +static void update_scan_rsp_data(struct hci_request *req)
> > +{
> > + struct hci_dev *hdev = req->hdev;
> > + struct hci_cp_le_set_scan_rsp_data cp;
> > + u8 len;
> > +
> > + if (!lmp_le_capable(hdev))
> > + return;
> > +
> > + memset(&cp, 0, sizeof(cp));
> > +
> > + len = create_scan_rsp_data(hdev, cp.data);
> > +
> > + if (hdev->adv_data_len == len &&
> > + memcmp(cp.data, hdev->adv_data, len) == 0)
> > + return;
> > +
> > + memcpy(hdev->adv_data, cp.data, sizeof(cp.data));
> > + hdev->adv_data_len = len;
>
> Shouldn't you be using hdev->scan_rsp_data/scan_rsp_data_len here?
>
> (I still haven't read the later patches, so this may already be fixed.)
Nope, it's still broken upstream. Good that you noticed it. Bad that I
didn't and bad that it seems Marcel didn't actually test this one
properly ;)
Johan
^ permalink raw reply
* [PATCH] Bluetooth: Fix updating the right variable in update_scan_rsp_data()
From: johan.hedberg @ 2013-10-16 12:31 UTC (permalink / raw)
To: linux-bluetooth
From: Johan Hedberg <johan.hedberg@intel.com>
This function should be operating on scan_rsp_data_len and scan_rsp_data
and not the advertising data variables.
Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
---
net/bluetooth/mgmt.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/net/bluetooth/mgmt.c b/net/bluetooth/mgmt.c
index 0bf823b..a727b47 100644
--- a/net/bluetooth/mgmt.c
+++ b/net/bluetooth/mgmt.c
@@ -575,12 +575,12 @@ static void update_scan_rsp_data(struct hci_request *req)
len = create_scan_rsp_data(hdev, cp.data);
- if (hdev->adv_data_len == len &&
- memcmp(cp.data, hdev->adv_data, len) == 0)
+ if (hdev->scan_rsp_data_len == len &&
+ memcmp(cp.data, hdev->scan_rsp_data, len) == 0)
return;
- memcpy(hdev->adv_data, cp.data, sizeof(cp.data));
- hdev->adv_data_len = len;
+ memcpy(hdev->scan_rsp_data, cp.data, sizeof(cp.data));
+ hdev->scan_rsp_data_len = len;
cp.length = len;
--
1.8.3.1
^ permalink raw reply related
* Re: [PATCH 3/6] Bluetooth: Set the scan response data when needed
From: Johan Hedberg @ 2013-10-16 12:31 UTC (permalink / raw)
To: Anderson Lizardo, Marcel Holtmann, BlueZ development
In-Reply-To: <20131016122801.GA2803@x220.p-661hnu-f1>
Hi,
On Wed, Oct 16, 2013, Johan Hedberg wrote:
> On Wed, Oct 16, 2013, Anderson Lizardo wrote:
> > On Wed, Oct 16, 2013 at 3:16 AM, Marcel Holtmann <marcel@holtmann.org> wrote:
> > > +static void update_scan_rsp_data(struct hci_request *req)
> > > +{
> > > + struct hci_dev *hdev = req->hdev;
> > > + struct hci_cp_le_set_scan_rsp_data cp;
> > > + u8 len;
> > > +
> > > + if (!lmp_le_capable(hdev))
> > > + return;
> > > +
> > > + memset(&cp, 0, sizeof(cp));
> > > +
> > > + len = create_scan_rsp_data(hdev, cp.data);
> > > +
> > > + if (hdev->adv_data_len == len &&
> > > + memcmp(cp.data, hdev->adv_data, len) == 0)
> > > + return;
> > > +
> > > + memcpy(hdev->adv_data, cp.data, sizeof(cp.data));
> > > + hdev->adv_data_len = len;
> >
> > Shouldn't you be using hdev->scan_rsp_data/scan_rsp_data_len here?
> >
> > (I still haven't read the later patches, so this may already be fixed.)
>
> Nope, it's still broken upstream. Good that you noticed it. Bad that I
> didn't and bad that it seems Marcel didn't actually test this one
> properly ;)
I just sent a patch to fix this which Marcel can push if he's fine with
it.
Johan
^ permalink raw reply
* [PATCH v3 0/5] Stack independent BT HAL test tool
From: Jerzy Kasenberg @ 2013-10-16 14:00 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Jerzy Kasenberg
v3:
- underscores changed to dash in file names.
- corrected cast style (space after cast).
- structure initialization with explicit filed names.
v2:
- license changed to apache
- source folder changed to hal-client (underscore to dash)
v1:
This tool is for testing Android HAL interfaces from command line.
Due to lack of readline on Android simple equivalent is hand coded.
This tool can be used with bluedroid stack so no glib dependency.
Tool source code is in folder hal_client, please comment if it should be
somewhere else.
Comments welcome.
Best regards
Jerzy Kasenberg
Jerzy Kasenberg (5):
android: Add haltest skeleton
android: Add line editing to haltest
android: Add history to line editor in haltest
android: Add text conversion helpers to haltest
android: Add calls to adapter methods in haltest
android/Android.mk | 21 ++
android/client/haltest.c | 161 +++++++++++
android/client/history.c | 98 +++++++
android/client/history.h | 21 ++
android/client/if-bt.c | 631 ++++++++++++++++++++++++++++++++++++++++++
android/client/if-main.h | 99 +++++++
android/client/pollhandler.c | 123 ++++++++
android/client/pollhandler.h | 26 ++
android/client/terminal.c | 538 +++++++++++++++++++++++++++++++++++
android/client/terminal.h | 59 ++++
android/client/textconv.c | 205 ++++++++++++++
android/client/textconv.h | 113 ++++++++
12 files changed, 2095 insertions(+)
create mode 100644 android/client/haltest.c
create mode 100644 android/client/history.c
create mode 100644 android/client/history.h
create mode 100644 android/client/if-bt.c
create mode 100644 android/client/if-main.h
create mode 100644 android/client/pollhandler.c
create mode 100644 android/client/pollhandler.h
create mode 100644 android/client/terminal.c
create mode 100644 android/client/terminal.h
create mode 100644 android/client/textconv.c
create mode 100644 android/client/textconv.h
--
1.7.9.5
^ permalink raw reply
* [PATCH v3 1/5] android: Add haltest skeleton
From: Jerzy Kasenberg @ 2013-10-16 14:00 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Jerzy Kasenberg
In-Reply-To: <1381932012-29641-1-git-send-email-jerzy.kasenberg@tieto.com>
This tool will be used to test Android Bluetooth HAL implementation.
---
android/Android.mk | 17 ++++++
android/client/haltest.c | 51 ++++++++++++++++++
android/client/pollhandler.c | 123 ++++++++++++++++++++++++++++++++++++++++++
android/client/pollhandler.h | 26 +++++++++
4 files changed, 217 insertions(+)
create mode 100644 android/client/haltest.c
create mode 100644 android/client/pollhandler.c
create mode 100644 android/client/pollhandler.h
diff --git a/android/Android.mk b/android/Android.mk
index 0e025ac..c2a0797 100644
--- a/android/Android.mk
+++ b/android/Android.mk
@@ -49,3 +49,20 @@ LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_CLASS := SHARED_LIBRARIES
include $(BUILD_SHARED_LIBRARY)
+
+#
+# haltest
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ client/haltest.c \
+ client/pollhandler.c \
+
+LOCAL_SHARED_LIBRARIES := libhardware
+
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE := haltest
+
+include $(BUILD_EXECUTABLE)
diff --git a/android/client/haltest.c b/android/client/haltest.c
new file mode 100644
index 0000000..11cdd97
--- /dev/null
+++ b/android/client/haltest.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2013 Intel Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <stdlib.h>
+#include <poll.h>
+#include <unistd.h>
+
+#include "pollhandler.h"
+
+
+/* called when there is something on stdin */
+static void stdin_handler(struct pollfd *pollfd)
+{
+ char buf[10];
+
+ if (pollfd->revents & POLLIN) {
+ int count = read(0, buf, 10);
+
+ if (count > 0) {
+ int i;
+
+ for (i = 0; i < count; ++i) {
+ /* TODO: process input */
+ }
+ }
+ }
+}
+
+int main(int argc, char **argv)
+{
+ /* Register command line handler */
+ poll_register_fd(0, POLLIN, stdin_handler);
+
+ poll_dispatch_loop();
+
+ return 0;
+}
diff --git a/android/client/pollhandler.c b/android/client/pollhandler.c
new file mode 100644
index 0000000..4e982b8
--- /dev/null
+++ b/android/client/pollhandler.c
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2013 Intel Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <stdio.h>
+#include <errno.h>
+#include <poll.h>
+
+#include "pollhandler.h"
+
+/*
+ * Code that allows to poll multiply file descriptors for events
+ * File descriptors can be added and removed at runtime
+ *
+ * Call poll_register_fd function first to add file descriptors to monitor
+ * Then call poll_dispatch_loop that will poll all registered file descriptors
+ * as long as they are not unregistered.
+ *
+ * When event happen on given fd appropriate user supplied handler is called
+ */
+
+/* Maximum number of files to monitor */
+#define MAX_OPEN_FD 10
+
+/* Storage for pollfd structures for monitored file descriptors */
+static struct pollfd fds[MAX_OPEN_FD];
+static poll_handler fds_handler[MAX_OPEN_FD];
+/* Number of registered file descriptors */
+static int fds_count = 0;
+
+/*
+ * Function polls file descriptor in loop and calls appropriate handler
+ * on event. Function returns when there is no more file descriptor to
+ * monitor
+ */
+void poll_dispatch_loop(void)
+{
+ while (fds_count > 0) {
+ int i;
+ int cur_fds_count = fds_count;
+ int ready = poll(fds, fds_count, 1000);
+
+ for (i = 0; i < fds_count && ready > 0; ++i) {
+ if (fds[i].revents == 0)
+ continue;
+
+ fds_handler[i](fds + i);
+ ready--;
+ /*
+ * If handler was remove from table
+ * just skip the rest and poll again
+ * This is due to reordering of tables in
+ * register/unregister functions
+ */
+ if (cur_fds_count != fds_count)
+ break;
+ }
+ /*
+ * This seems to be needed for correct output handling
+ * when all waiting is performed in poll
+ */
+ fflush(stdout);
+ }
+}
+
+/*
+ * Registers file descriptor to be monitored for events (see man poll(2))
+ * for events.
+ *
+ * return non negative value on success
+ * -EMFILE when there are to much descriptors
+ */
+int poll_register_fd(int fd, short events, poll_handler ph)
+{
+ if (fds_count >= MAX_OPEN_FD)
+ return -EMFILE;
+
+ fds_handler[fds_count] = ph;
+ fds[fds_count].fd = fd;
+ fds[fds_count].events = events;
+ fds_count++;
+
+ return fds_count;
+}
+
+/*
+ * Unregisters file descriptor
+ * Both fd and ph must match previously registered data
+ *
+ * return 0 if unregister succeeded
+ * -EBADF if arguments do not match any register handler
+ */
+int poll_unregister_fd(int fd, poll_handler ph)
+{
+ int i;
+
+ for (i = 0; i < fds_count; ++i) {
+ if (fds_handler[i] == ph && fds[i].fd == fd) {
+ fds_count--;
+ if (i < fds_count) {
+ fds[i].fd = fds[fds_count].fd;
+ fds[i].events = fds[fds_count].events;
+ fds_handler[i] = fds_handler[fds_count];
+ }
+ return 0;
+ }
+ }
+ return -EBADF;
+}
+
diff --git a/android/client/pollhandler.h b/android/client/pollhandler.h
new file mode 100644
index 0000000..e2f22df
--- /dev/null
+++ b/android/client/pollhandler.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2013 Intel Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <poll.h>
+
+/* Function to be called when there are event for some descriptor */
+typedef void (*poll_handler)(struct pollfd *pollfd);
+
+int poll_register_fd(int fd, short events, poll_handler ph);
+int poll_unregister_fd(int fd, poll_handler ph);
+
+void poll_dispatch_loop(void);
--
1.7.9.5
^ permalink raw reply related
* [PATCH v3 2/5] android: Add line editing to haltest
From: Jerzy Kasenberg @ 2013-10-16 14:00 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Jerzy Kasenberg
In-Reply-To: <1381932012-29641-1-git-send-email-jerzy.kasenberg@tieto.com>
Android does not have readline.
This patch allows to edit command line.
---
android/Android.mk | 1 +
android/client/haltest.c | 39 +++-
android/client/terminal.c | 431 +++++++++++++++++++++++++++++++++++++++++++++
android/client/terminal.h | 59 +++++++
4 files changed, 527 insertions(+), 3 deletions(-)
create mode 100644 android/client/terminal.c
create mode 100644 android/client/terminal.h
diff --git a/android/Android.mk b/android/Android.mk
index c2a0797..2eac3ec 100644
--- a/android/Android.mk
+++ b/android/Android.mk
@@ -59,6 +59,7 @@ include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
client/haltest.c \
client/pollhandler.c \
+ client/terminal.c \
LOCAL_SHARED_LIBRARIES := libhardware
diff --git a/android/client/haltest.c b/android/client/haltest.c
index 11cdd97..de98079 100644
--- a/android/client/haltest.c
+++ b/android/client/haltest.c
@@ -19,8 +19,40 @@
#include <poll.h>
#include <unistd.h>
+#include "terminal.h"
#include "pollhandler.h"
+/*
+ * This function changes input parameter line_buffer so it has
+ * null termination after each token (due to strtok)
+ * Output argv is filled with pointers to arguments
+ * returns number of tokens parsed - argc
+ */
+static int command_line_to_argv(char *line_buffer,
+ char *argv[], int argv_size)
+{
+ static const char *token_breaks = "\r\n\t ";
+ char *token;
+ int argc = 0;
+
+ token = strtok(line_buffer, token_breaks);
+ while (token != NULL && argc < (int) argv_size) {
+ argv[argc++] = token;
+ token = strtok(NULL, token_breaks);
+ }
+
+ return argc;
+}
+
+static void process_line(char *line_buffer)
+{
+ char *argv[10];
+ int argc;
+
+ argc = command_line_to_argv(line_buffer, argv, 10);
+
+ /* TODO: process command line */
+}
/* called when there is something on stdin */
static void stdin_handler(struct pollfd *pollfd)
@@ -33,15 +65,16 @@ static void stdin_handler(struct pollfd *pollfd)
if (count > 0) {
int i;
- for (i = 0; i < count; ++i) {
- /* TODO: process input */
- }
+ for (i = 0; i < count; ++i)
+ terminal_process_char(buf[i], process_line);
}
}
}
int main(int argc, char **argv)
{
+ terminal_setup();
+
/* Register command line handler */
poll_register_fd(0, POLLIN, stdin_handler);
diff --git a/android/client/terminal.c b/android/client/terminal.c
new file mode 100644
index 0000000..95108a0
--- /dev/null
+++ b/android/client/terminal.c
@@ -0,0 +1,431 @@
+/*
+ * Copyright (C) 2013 Intel Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdbool.h>
+#include <termios.h>
+
+#include "terminal.h"
+
+/*
+ * Character sequences recognized by code in this file
+ * Leading ESC 0x1B is not included
+ */
+#define SEQ_INSERT "[2~"
+#define SEQ_DELETE "[3~"
+#define SEQ_HOME "OH"
+#define SEQ_END "OF"
+#define SEQ_PGUP "[5~"
+#define SEQ_PGDOWN "[6~"
+#define SEQ_LEFT "[D"
+#define SEQ_RIGHT "[C"
+#define SEQ_UP "[A"
+#define SEQ_DOWN "[B"
+#define SEQ_STAB "[Z"
+#define SEQ_M_n "n"
+#define SEQ_M_p "p"
+#define SEQ_CLEFT "[1;5D"
+#define SEQ_CRIGHT "[1;5C"
+#define SEQ_CUP "[1;5A"
+#define SEQ_CDOWN "[1;5B"
+#define SEQ_SLEFT "[1;2D"
+#define SEQ_SRIGHT "[1;2C"
+#define SEQ_SUP "[1;2A"
+#define SEQ_SDOWN "[1;2B"
+#define SEQ_MLEFT "[1;3D"
+#define SEQ_MRIGHT "[1;3C"
+#define SEQ_MUP "[1;3A"
+#define SEQ_MDOWN "[1;3B"
+
+#define KEY_SEQUENCE(k) { KEY_##k, SEQ_##k }
+struct ansii_sequence {
+ int code;
+ const char *sequence;
+};
+
+/* Table connects single int key codes with character sequences */
+static const struct ansii_sequence ansii_sequnces[] = {
+ KEY_SEQUENCE(INSERT),
+ KEY_SEQUENCE(DELETE),
+ KEY_SEQUENCE(HOME),
+ KEY_SEQUENCE(END),
+ KEY_SEQUENCE(PGUP),
+ KEY_SEQUENCE(PGDOWN),
+ KEY_SEQUENCE(LEFT),
+ KEY_SEQUENCE(RIGHT),
+ KEY_SEQUENCE(UP),
+ KEY_SEQUENCE(DOWN),
+ KEY_SEQUENCE(CLEFT),
+ KEY_SEQUENCE(CRIGHT),
+ KEY_SEQUENCE(CUP),
+ KEY_SEQUENCE(CDOWN),
+ KEY_SEQUENCE(SLEFT),
+ KEY_SEQUENCE(SRIGHT),
+ KEY_SEQUENCE(SUP),
+ KEY_SEQUENCE(SDOWN),
+ KEY_SEQUENCE(MLEFT),
+ KEY_SEQUENCE(MRIGHT),
+ KEY_SEQUENCE(MUP),
+ KEY_SEQUENCE(MDOWN),
+ KEY_SEQUENCE(STAB),
+ KEY_SEQUENCE(M_p),
+ KEY_SEQUENCE(M_n),
+ { 0, NULL }
+};
+
+#define isseqence(c) ((c) == 0x1B)
+
+/*
+ * Number of characters that consist of ANSII sequence
+ * Should not be less then longest string in ansii_sequnces
+ */
+#define MAX_ASCII_SEQUENCE 10
+
+static char current_sequence[MAX_ASCII_SEQUENCE];
+static int current_sequence_len = -1;
+
+/* single line typed by user goes here */
+static char line_buf[LINE_BUF_MAX];
+/* index of cursor in input line */
+static int line_buf_ix = 0;
+/* current length of input line */
+static int line_len = 0;
+
+/*
+ * Moves cursor to right or left
+ *
+ * n - positive - moves cursor right
+ * n - negative - moves cursor left
+ */
+static void terminal_move_cursor(int n)
+{
+ if (n < 0) {
+ for (; n < 0; n++)
+ putchar('\b');
+ } else if (n > 0) {
+ printf("%*s", n, line_buf + line_buf_ix);
+ }
+}
+
+/* Draw command line */
+void terminal_draw_command_line(void)
+{
+ /*
+ * this needs to be checked here since line_buf is not cleard
+ * before parsing event though line_len and line_buf_ix are
+ */
+ if (line_len > 0)
+ printf(">%s", line_buf);
+ else
+ putchar('>');
+
+ /* move cursor to it's place */
+ terminal_move_cursor(line_len - line_buf_ix);
+}
+
+/* inserts string into command line at cursor position */
+void terminal_insert_into_command_line(const char *p)
+{
+ int len = strlen(p);
+
+ if (line_len == line_buf_ix) {
+ strcat(line_buf, p);
+ printf("%s", p);
+ line_len = line_len + len;
+ line_buf_ix = line_len;
+ } else {
+ memmove(line_buf + line_buf_ix + len,
+ line_buf + line_buf_ix, line_len - line_buf_ix + 1);
+ memmove(line_buf + line_buf_ix, p, len);
+ printf("%s", line_buf + line_buf_ix);
+ line_buf_ix += len;
+ line_len += len;
+ terminal_move_cursor(line_buf_ix - line_len);
+ }
+}
+
+/* Prints string and redraws command line */
+int terminal_print(const char *format, ...)
+{
+ va_list args;
+ int ret;
+
+ va_start(args, format);
+
+ ret = terminal_vprint(format, args);
+
+ va_end(args);
+ return ret;
+}
+
+/* Prints string and redraws command line */
+int terminal_vprint(const char *format, va_list args)
+{
+ int ret;
+
+ printf("\r%*s\r", (int) line_len + 1, " ");
+
+ ret = vprintf(format, args);
+
+ terminal_draw_command_line();
+
+ return ret;
+}
+
+/*
+ * Converts terminal character sequences to single value representing
+ * keyboard keys
+ */
+static int terminal_convert_sequence(int c)
+{
+ int i;
+
+ /* Not in sequence yet? */
+ if (current_sequence_len == -1) {
+ /* Is ansii sequence detected by 0x1B ? */
+ if (isseqence(c)) {
+ current_sequence_len++;
+ return 0;
+ }
+ return c;
+ }
+ /* Inside sequence */
+ current_sequence[current_sequence_len++] = c;
+ current_sequence[current_sequence_len] = '\0';
+ for (i = 0; ansii_sequnces[i].code; ++i) {
+ /* Matches so far? */
+ if (0 != strncmp(current_sequence, ansii_sequnces[i].sequence,
+ current_sequence_len))
+ continue;
+
+ /* Matches as a whole? */
+ if (ansii_sequnces[i].sequence[current_sequence_len] == 0) {
+ current_sequence_len = -1;
+ return ansii_sequnces[i].code;
+ }
+ /* partial match (not whole sequence yet) */
+ return 0;
+ }
+ terminal_print("ansii char 0x%X %c\n", c);
+ /*
+ * Sequence does not match
+ * mark that no in sequence any more, return char
+ */
+ current_sequence_len = -1;
+ return c;
+}
+
+void terminal_process_char(int c, void (*process_line)(char *line))
+{
+ int refresh_from = -1;
+ int old_pos;
+
+ c = terminal_convert_sequence(c);
+
+ switch (c) {
+ case 0:
+ break;
+ case KEY_LEFT:
+ /* if not at the beginning move to previous character */
+ if (line_buf_ix <= 0)
+ break;
+ line_buf_ix--;
+ terminal_move_cursor(-1);
+ break;
+ case KEY_RIGHT:
+ /*
+ * If not at the end, just print current character
+ * and modify position
+ */
+ if (line_buf_ix < line_len)
+ putchar(line_buf[line_buf_ix++]);
+ break;
+ case KEY_HOME:
+ /* move to beginning of line and update position */
+ putchar('\r');
+ putchar('>');
+ line_buf_ix = 0;
+ break;
+ case KEY_END:
+ /* if not at the end of line */
+ if (line_buf_ix < line_len) {
+ /* print everything from cursor */
+ printf("%s", line_buf + line_buf_ix);
+ /* just modify current position */
+ line_buf_ix = line_len;
+ }
+ break;
+ case KEY_DELETE:
+ /* delete character under cursor if not at the very end */
+ if (line_buf_ix >= line_len)
+ break;
+ /*
+ * Prepare buffer with one character missing
+ * trailing 0 is moved
+ */
+ line_len--;
+ memmove(line_buf + line_buf_ix,
+ line_buf + line_buf_ix + 1,
+ line_len - line_buf_ix + 1);
+ /* print rest of line from current cursor position */
+ printf("%s \b", line_buf + line_buf_ix);
+ /* move back cursor */
+ terminal_move_cursor(line_buf_ix - line_len);
+ break;
+ case KEY_CLEFT:
+ /*
+ * Move by word left
+ *
+ * Are we at the beginning of line?
+ */
+ if (line_buf_ix <= 0)
+ break;
+
+ old_pos = line_buf_ix;
+ line_buf_ix--;
+ /* skip spaces left */
+ while (line_buf_ix && isspace(line_buf[line_buf_ix]))
+ line_buf_ix--;
+ /* skip all non spaces to the left */
+ while (line_buf_ix > 0 &&
+ !isspace(line_buf[line_buf_ix - 1]))
+ line_buf_ix--;
+ /* move cursor to new position */
+ terminal_move_cursor(line_buf_ix - old_pos);
+ break;
+ case KEY_CRIGHT:
+ /*
+ * Move by word right
+ *
+ * are we at the end of line?
+ */
+ if (line_buf_ix >= line_len)
+ break;
+
+ old_pos = line_buf_ix;
+ /* skip all spaces */
+ while (line_buf_ix < line_len &&
+ isspace(line_buf[line_buf_ix]))
+ line_buf_ix++;
+ /* skip all non spaces */
+ while (line_buf_ix < line_len &&
+ !isspace(line_buf[line_buf_ix]))
+ line_buf_ix++;
+ /*
+ * Move cursor to right by printing text
+ * between old cursor and new
+ */
+ if (line_buf_ix > old_pos)
+ printf("%.*s", (int) (line_buf_ix - old_pos),
+ line_buf + old_pos);
+ break;
+ case KEY_UP:
+ case KEY_DOWN:
+ break;
+ case '\n':
+ case '\r':
+ line_len = 0;
+ line_buf_ix = 0;
+ /* print new line */
+ putchar(c);
+ process_line(line_buf);
+ /* clear current line */
+ line_buf[0] = '\0';
+ putchar('>');
+ break;
+ case '\t':
+ /* tab processing */
+ /* TODO Add completion here */
+ break;
+ case KEY_BACKSPACE:
+ if (line_buf_ix <= 0)
+ break;
+
+ if (line_buf_ix == line_len) {
+ printf("\b \b");
+ line_len = --line_buf_ix;
+ line_buf[line_len] = 0;
+ } else {
+ putchar('\b');
+ refresh_from = --line_buf_ix;
+ line_len--;
+ memmove(line_buf + line_buf_ix,
+ line_buf + line_buf_ix + 1,
+ line_len - line_buf_ix + 1);
+ }
+ break;
+ case KEY_INSERT:
+ case KEY_PGUP:
+ case KEY_PGDOWN:
+ case KEY_CUP:
+ case KEY_CDOWN:
+ case KEY_SLEFT:
+ case KEY_SRIGHT:
+ case KEY_MLEFT:
+ case KEY_MRIGHT:
+ case KEY_MUP:
+ case KEY_MDOWN:
+ case KEY_STAB:
+ case KEY_M_n:
+ case KEY_M_p:
+ break;
+ default:
+ if (!isprint(c)) {
+ /*
+ * TODO: remove this print once all meaningful sequences
+ * are identified
+ */
+ printf("char-0x%02x\n", c);
+ break;
+ }
+ if (line_buf_ix < LINE_BUF_MAX - 1) {
+ if (line_len == line_buf_ix) {
+ putchar(c);
+ line_buf[line_buf_ix++] = (char) c;
+ line_len++;
+ line_buf[line_len] = '\0';
+ } else {
+ memmove(line_buf + line_buf_ix + 1,
+ line_buf + line_buf_ix,
+ line_len - line_buf_ix + 1);
+ line_buf[line_buf_ix] = c;
+ refresh_from = line_buf_ix++;
+ line_len++;
+ }
+ }
+ break;
+ }
+
+ if (refresh_from >= 0) {
+ printf("%s \b", line_buf + refresh_from);
+ terminal_move_cursor(line_buf_ix - line_len);
+ }
+}
+
+void terminal_setup(void)
+{
+ struct termios tios;
+
+ /* Turn off echo since all editing is done by hand */
+ tcgetattr(0, &tios);
+ tios.c_lflag &= ~(ICANON | ECHO);
+ tcsetattr(0, TCSANOW, &tios);
+ putchar('>');
+}
+
diff --git a/android/client/terminal.h b/android/client/terminal.h
new file mode 100644
index 0000000..e53750f
--- /dev/null
+++ b/android/client/terminal.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2013 Intel Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <stdarg.h>
+
+/* size of supported line */
+#define LINE_BUF_MAX 1024
+
+enum key_codes {
+ KEY_BACKSPACE = 0x7F,
+ KEY_INSERT = 1000, /* arbitrary value */
+ KEY_DELETE,
+ KEY_HOME,
+ KEY_END,
+ KEY_PGUP,
+ KEY_PGDOWN,
+ KEY_LEFT,
+ KEY_RIGHT,
+ KEY_UP,
+ KEY_DOWN,
+ KEY_CLEFT,
+ KEY_CRIGHT,
+ KEY_CUP,
+ KEY_CDOWN,
+ KEY_SLEFT,
+ KEY_SRIGHT,
+ KEY_SUP,
+ KEY_SDOWN,
+ KEY_MLEFT,
+ KEY_MRIGHT,
+ KEY_MUP,
+ KEY_MDOWN,
+ KEY_STAB,
+ KEY_M_p,
+ KEY_M_n
+};
+
+void terminal_setup(void);
+int terminal_print(const char *format, ...);
+int terminal_vprint(const char *format, va_list args);
+void terminal_process_char(int c, void (*process_line)(char *line));
+void terminal_insert_into_command_line(const char *p);
+void terminal_draw_command_line(void);
+
+void process_tab(const char *line, int len);
--
1.7.9.5
^ permalink raw reply related
* [PATCH v3 3/5] android: Add history to line editor in haltest
From: Jerzy Kasenberg @ 2013-10-16 14:00 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Jerzy Kasenberg
In-Reply-To: <1381932012-29641-1-git-send-email-jerzy.kasenberg@tieto.com>
Added simple history to editor to save time.
---
android/Android.mk | 1 +
android/client/history.c | 98 +++++++++++++++++++++++++++++++++++++++++
android/client/history.h | 21 +++++++++
android/client/terminal.c | 107 +++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 227 insertions(+)
create mode 100644 android/client/history.c
create mode 100644 android/client/history.h
diff --git a/android/Android.mk b/android/Android.mk
index 2eac3ec..d49056c 100644
--- a/android/Android.mk
+++ b/android/Android.mk
@@ -60,6 +60,7 @@ LOCAL_SRC_FILES := \
client/haltest.c \
client/pollhandler.c \
client/terminal.c \
+ client/history.c \
LOCAL_SHARED_LIBRARIES := libhardware
diff --git a/android/client/history.c b/android/client/history.c
new file mode 100644
index 0000000..90d9952
--- /dev/null
+++ b/android/client/history.c
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2013 Intel Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+
+#include "history.h"
+
+/*
+ * Very simple history storage for easy usage of tool
+ */
+
+#define HISTORY_DEPTH 20
+#define LINE_SIZE 100
+static char lines[HISTORY_DEPTH][LINE_SIZE];
+static int last_line = 0;
+static int history_size = 0;
+
+/* TODO: Storing history not implemented yet */
+void history_store(const char *filename)
+{
+}
+
+/* Restoring history from file */
+void history_restore(const char *filename)
+{
+ char line[1000];
+ FILE *f = fopen(filename, "rt");
+
+ if (f == NULL)
+ return;
+
+ for (;;) {
+ if (fgets(line, 1000, f) != NULL) {
+ int l = strlen(line);
+ while (l > 0 && isspace(line[--l]))
+ line[l] = 0;
+ if (l > 0)
+ history_add_line(line);
+ } else
+ break;
+ }
+ fclose(f);
+}
+
+/* Add new line to history buffer */
+void history_add_line(const char *line)
+{
+ if (line == NULL || strlen(line) == 0)
+ return;
+
+ if (strcmp(line, lines[last_line]) == 0)
+ return;
+
+ last_line = (last_line + 1) % HISTORY_DEPTH;
+ strncpy(&lines[last_line][0], line, LINE_SIZE - 1);
+ if (history_size < HISTORY_DEPTH)
+ history_size++;
+}
+
+/*
+ * Get n-th line from history
+ * 0 - means latest
+ * -1 - means oldest
+ * return -1 if there is no such line
+ */
+int history_get_line(int n, char *buf, int buf_size)
+{
+ if (n == -1)
+ n = history_size - 1;
+
+ if (n >= history_size || buf_size == 0 || n < 0)
+ return -1;
+
+ strncpy(buf,
+ &lines[(HISTORY_DEPTH + last_line - n) % HISTORY_DEPTH][0],
+ buf_size - 1);
+ buf[buf_size - 1] = 0;
+
+ return n;
+}
+
diff --git a/android/client/history.h b/android/client/history.h
new file mode 100644
index 0000000..26085b5
--- /dev/null
+++ b/android/client/history.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2013 Intel Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+void history_store(const char *filename);
+void history_restore(const char *filename);
+void history_add_line(const char *line);
+int history_get_line(int n, char *buf, int buf_size);
diff --git a/android/client/terminal.c b/android/client/terminal.c
index 95108a0..9352328 100644
--- a/android/client/terminal.c
+++ b/android/client/terminal.c
@@ -22,6 +22,7 @@
#include <termios.h>
#include "terminal.h"
+#include "history.h"
/*
* Character sequences recognized by code in this file
@@ -107,6 +108,9 @@ static int line_buf_ix = 0;
/* current length of input line */
static int line_len = 0;
+/* line index used for fetching lines from history */
+static int line_index = 0;
+
/*
* Moves cursor to right or left
*
@@ -189,6 +193,87 @@ int terminal_vprint(const char *format, va_list args)
}
/*
+ * Call this when text in line_buf was changed
+ * and line needs to be redrawn
+ */
+static void terminal_line_replaced(void)
+{
+ int len = strlen(line_buf);
+
+ /* line is shorter that previous */
+ if (len < line_len) {
+ /* if new line is shorter move cursor to end of new end */
+ while (line_buf_ix > len) {
+ putchar('\b');
+ line_buf_ix--;
+ }
+ /* If cursor was not at the end, move it to the end */
+ if (line_buf_ix < line_len)
+ printf("%.*s", line_len - line_buf_ix,
+ line_buf + line_buf_ix);
+ /* over write end of previous line */
+ while (line_len >= len++)
+ putchar(' ');
+ }
+ /* draw new line */
+ printf("\r>%s", line_buf);
+ /* set up indexes to new line */
+ line_len = strlen(line_buf);
+ line_buf_ix = line_len;
+}
+
+/*
+ * Function tries to replace current line with specified line in history
+ * new_line_index - new line to show, -1 to show oldest
+ */
+static void terminal_get_line_from_history(int new_line_index)
+{
+ new_line_index = history_get_line(new_line_index,
+ line_buf, LINE_BUF_MAX);
+
+ if (new_line_index >= 0) {
+ terminal_line_replaced();
+ line_index = new_line_index;
+ }
+}
+
+/*
+ * Function searches history back or forward for command line that starts
+ * with characters up to cursor position
+ *
+ * back - true - searches backward
+ * back - false - searches forward (more recent commands)
+ */
+static void terminal_match_hitory(bool back)
+{
+ char buf[line_buf_ix + 1];
+ int line;
+ int matching_line = -1;
+ int dir = back ? 1 : -1;
+
+ line = line_index + dir;
+ while (matching_line == -1 && line >= 0) {
+ int new_line_index;
+
+ new_line_index = history_get_line(line, buf, line_buf_ix + 1);
+ if (new_line_index < 0)
+ break;
+
+ if (0 == strncmp(line_buf, buf, line_buf_ix))
+ matching_line = line;
+ line += dir;
+ }
+
+ if (matching_line >= 0) {
+ int pos = line_buf_ix;
+ terminal_get_line_from_history(matching_line);
+ /* move back to cursor position to origianl place */
+ line_buf_ix = pos;
+ terminal_move_cursor(pos - line_len);
+ }
+}
+
+/*
* Converts terminal character sequences to single value representing
* keyboard keys
*/
@@ -335,13 +420,30 @@ void terminal_process_char(int c, void (*process_line)(char *line))
printf("%.*s", (int) (line_buf_ix - old_pos),
line_buf + old_pos);
break;
+ case KEY_SUP:
+ terminal_get_line_from_history(-1);
+ break;
+ case KEY_SDOWN:
+ if (line_index > 0)
+ terminal_get_line_from_history(0);
+ break;
case KEY_UP:
+ terminal_get_line_from_history(line_index + 1);
+ break;
case KEY_DOWN:
+ if (line_index > 0)
+ terminal_get_line_from_history(line_index - 1);
break;
case '\n':
case '\r':
+ /*
+ * On new line add line to history
+ * forget history position
+ */
+ history_add_line(line_buf);
line_len = 0;
line_buf_ix = 0;
+ line_index = -1;
/* print new line */
putchar(c);
process_line(line_buf);
@@ -383,7 +485,12 @@ void terminal_process_char(int c, void (*process_line)(char *line))
case KEY_MDOWN:
case KEY_STAB:
case KEY_M_n:
+ /* Search history forward */
+ terminal_match_hitory(false);
+ break;
case KEY_M_p:
+ /* Search history backward */
+ terminal_match_hitory(true);
break;
default:
if (!isprint(c)) {
--
1.7.9.5
^ permalink raw reply related
* [PATCH v3 4/5] android: Add text conversion helpers to haltest
From: Jerzy Kasenberg @ 2013-10-16 14:00 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Jerzy Kasenberg
In-Reply-To: <1381932012-29641-1-git-send-email-jerzy.kasenberg@tieto.com>
Application uses a lot of text in the form of defines found in header
files to represent arguments and output.
Conversion helpers keep functionality of converting string as
bt_status_t or uuid in one place.
---
android/Android.mk | 1 +
android/client/textconv.c | 205 +++++++++++++++++++++++++++++++++++++++++++++
android/client/textconv.h | 113 +++++++++++++++++++++++++
3 files changed, 319 insertions(+)
create mode 100644 android/client/textconv.c
create mode 100644 android/client/textconv.h
diff --git a/android/Android.mk b/android/Android.mk
index d49056c..6931c9c 100644
--- a/android/Android.mk
+++ b/android/Android.mk
@@ -61,6 +61,7 @@ LOCAL_SRC_FILES := \
client/pollhandler.c \
client/terminal.c \
client/history.c \
+ client/textconv.c \
LOCAL_SHARED_LIBRARIES := libhardware
diff --git a/android/client/textconv.c b/android/client/textconv.c
new file mode 100644
index 0000000..eebad70
--- /dev/null
+++ b/android/client/textconv.c
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2013 Intel Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <hardware/bluetooth.h>
+
+#include "textconv.h"
+
+/*
+ * Following are maps of defines found in bluetooth header files to strings
+ *
+ * Those mappings are used to accurately use defines as input parameters in
+ * command line as well as for printing of statuses
+ */
+
+INTMAP(bt_status_t, -1, "(unknown)")
+ DELEMENT(BT_STATUS_SUCCESS),
+ DELEMENT(BT_STATUS_FAIL),
+ DELEMENT(BT_STATUS_NOT_READY),
+ DELEMENT(BT_STATUS_NOMEM),
+ DELEMENT(BT_STATUS_BUSY),
+ DELEMENT(BT_STATUS_DONE),
+ DELEMENT(BT_STATUS_UNSUPPORTED),
+ DELEMENT(BT_STATUS_PARM_INVALID),
+ DELEMENT(BT_STATUS_UNHANDLED),
+ DELEMENT(BT_STATUS_AUTH_FAILURE),
+ DELEMENT(BT_STATUS_RMT_DEV_DOWN),
+ENDMAP
+
+INTMAP(bt_state_t, -1, "(unknown)")
+ DELEMENT(BT_STATE_OFF),
+ DELEMENT(BT_STATE_ON),
+ENDMAP
+
+INTMAP(bt_device_type_t, -1, "(unknown)")
+ DELEMENT(BT_DEVICE_DEVTYPE_BREDR),
+ DELEMENT(BT_DEVICE_DEVTYPE_BLE),
+ DELEMENT(BT_DEVICE_DEVTYPE_DUAL),
+ENDMAP
+
+INTMAP(bt_scan_mode_t, -1, "(unknown)")
+ DELEMENT(BT_SCAN_MODE_NONE),
+ DELEMENT(BT_SCAN_MODE_CONNECTABLE),
+ DELEMENT(BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE),
+ENDMAP
+
+INTMAP(bt_discovery_state_t, -1, "(unknown)")
+ DELEMENT(BT_DISCOVERY_STOPPED),
+ DELEMENT(BT_DISCOVERY_STARTED),
+ENDMAP
+
+INTMAP(bt_acl_state_t, -1, "(unknown)")
+ DELEMENT(BT_ACL_STATE_CONNECTED),
+ DELEMENT(BT_ACL_STATE_DISCONNECTED),
+ENDMAP
+
+INTMAP(bt_bond_state_t, -1, "(unknown)")
+ DELEMENT(BT_BOND_STATE_NONE),
+ DELEMENT(BT_BOND_STATE_BONDING),
+ DELEMENT(BT_BOND_STATE_BONDED),
+ENDMAP
+
+INTMAP(bt_ssp_variant_t, -1, "(unknown)")
+ DELEMENT(BT_SSP_VARIANT_PASSKEY_CONFIRMATION),
+ DELEMENT(BT_SSP_VARIANT_PASSKEY_ENTRY),
+ DELEMENT(BT_SSP_VARIANT_CONSENT),
+ DELEMENT(BT_SSP_VARIANT_PASSKEY_NOTIFICATION),
+ENDMAP
+
+INTMAP(bt_property_type_t, -1, "(unknown)")
+ DELEMENT(BT_PROPERTY_BDNAME),
+ DELEMENT(BT_PROPERTY_BDADDR),
+ DELEMENT(BT_PROPERTY_UUIDS),
+ DELEMENT(BT_PROPERTY_CLASS_OF_DEVICE),
+ DELEMENT(BT_PROPERTY_TYPE_OF_DEVICE),
+ DELEMENT(BT_PROPERTY_SERVICE_RECORD),
+ DELEMENT(BT_PROPERTY_ADAPTER_SCAN_MODE),
+ DELEMENT(BT_PROPERTY_ADAPTER_BONDED_DEVICES),
+ DELEMENT(BT_PROPERTY_ADAPTER_DISCOVERY_TIMEOUT),
+ DELEMENT(BT_PROPERTY_REMOTE_FRIENDLY_NAME),
+ DELEMENT(BT_PROPERTY_REMOTE_RSSI),
+ DELEMENT(BT_PROPERTY_REMOTE_VERSION_INFO),
+ DELEMENT(BT_PROPERTY_REMOTE_DEVICE_TIMESTAMP),
+ENDMAP
+
+INTMAP(bt_cb_thread_evt, -1, "(unknown)")
+ DELEMENT(ASSOCIATE_JVM),
+ DELEMENT(DISASSOCIATE_JVM),
+ENDMAP
+
+/* Find first index of given value in table m */
+int int2str_findint(int v, const struct int2str m[])
+{
+ int i;
+
+ for (i = 0; m[i].str; ++i) {
+ if (m[i].val == v)
+ return i;
+ }
+ return -1;
+}
+
+/* Find first index of given string in table m */
+int int2str_findstr(const char *str, const struct int2str m[])
+{
+ int i;
+
+ for (i = 0; m[i].str; ++i) {
+ if (strcmp(m[i].str, str) == 0)
+ return i;
+ }
+ return -1;
+}
+
+/*
+ * convert bd_addr to string
+ * buf must be at least 18 char long
+ *
+ * returns buf
+ */
+char *bt_bdaddr_t2str(const bt_bdaddr_t *bd_addr, char *buf)
+{
+ const char *p = (const char *) bd_addr;
+
+ snprintf(buf, 18, "%02x:%02x:%02x:%02x:%02x:%02x",
+ p[0], p[1], p[2], p[3], p[4], p[5]);
+
+ return buf;
+}
+
+/* converts string to bt_bdaddr_t */
+void str2bt_bdaddr_t(const char *str, bt_bdaddr_t *bd_addr)
+{
+ char *p = (char *) bd_addr;
+
+ sscanf(str, "%02hhx:%02hhx:%02hhx:%02hhx:%02hhx:%02hhx",
+ &p[0], &p[1], &p[2], &p[3], &p[4], &p[5]);
+}
+
+static const char BT_BASE_UUID[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
+ 0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb
+};
+
+/*
+ * converts uuid to string
+ * buf should be at least 39 bytes
+ *
+ * returns string representation of uuid
+ */
+char *bt_uuid_t2str(const bt_uuid_t *uuid, char *buf)
+{
+ int shift = 0;
+ int i;
+ int is_bt;
+
+ is_bt = !memcmp(&uuid->uu[4], &BT_BASE_UUID[4], sizeof(bt_uuid_t) - 4);
+
+ for (i = 0; i < (int) sizeof(bt_uuid_t); i++) {
+ if (i == 4 && is_bt)
+ break;
+
+ if (i == 4 || i == 6 || i == 8 || i == 10) {
+ buf[i * 2 + shift] = '-';
+ shift++;
+ }
+ sprintf(buf + i * 2 + shift, "%02x", uuid->uu[i]);
+ }
+
+ return buf;
+}
+
+/* converts string to uuid */
+void str2bt_uuid_t(const char *str, bt_uuid_t *uuid)
+{
+ int i = 0;
+
+ memcpy(uuid, BT_BASE_UUID, sizeof(bt_uuid_t));
+
+ while (*str && i < (int) sizeof(bt_uuid_t)) {
+ while (*str == '-')
+ str++;
+
+ if (sscanf(str, "%02hhx", &uuid->uu[i]) != 1)
+ break;
+
+ i++;
+ str += 2;
+ }
+}
diff --git a/android/client/textconv.h b/android/client/textconv.h
new file mode 100644
index 0000000..8fe976c
--- /dev/null
+++ b/android/client/textconv.h
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2013 Intel Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+/**
+ * Begin mapping section
+ *
+ * There are some mappings between integer values (enums) and strings
+ * to be presented to user. To make it easier to convert between those two
+ * set of macros is given. It is specially useful when we want to have
+ * strings that match constants from header files like:
+ * BT_STATUS_SUCCESS (0) and corresponding "BT_STATUS_SUCCESS"
+ * Example of usage:
+ *
+ * INTMAP(int, -1, "invalid")
+ * DELEMENT(BT_STATUS_SUCCESS)
+ * DELEMENT(BT_STATUS_FAIL)
+ * MELEMENT(123, "Some strange value")
+ * ENDMAP
+ *
+ * Just by doing this we have mapping table plus two functions:
+ * int str2int(const char *str);
+ * const char *int2str(int v);
+ *
+ * second argument to INTMAP specifies value to be returned from
+ * str2int function when there is not mapping for such number
+ * third argument specifies default value to be returned from int2str
+ *
+ * If same mapping is to be used in several source files put
+ * INTMAP in c file and DECINTMAP in h file.
+ *
+ * For mappings that are to be used in single file only
+ * use SINTMAP which will create the same but everything will be marked
+ * as static.
+ */
+
+struct int2str {
+ int val; /* int value */
+ const char *str; /* corresponding string */
+};
+
+int int2str_findint(int v, const struct int2str m[]);
+int int2str_findstr(const char *str, const struct int2str m[]);
+
+#define DECINTMAP(type) \
+extern struct int2str __##type##2str[]; \
+const char *type##2##str(type v); \
+type str##2##type(const char *str); \
+
+#define INTMAP(type, deft, defs) \
+const char *type##2##str(type v) \
+{ \
+ int i = int2str_findint((int) v, __##type##2str); \
+ return (i < 0) ? defs : __##type##2str[i].str; \
+} \
+type str##2##type(const char *str) \
+{ \
+ int i = int2str_findstr(str, __##type##2str); \
+ return (i < 0) ? (type) deft : (type) (__##type##2str[i].val); \
+} \
+struct int2str __##type##2str[] = {
+
+#define SINTMAP(type, deft, defs) \
+static struct int2str __##type##2str[]; \
+static inline const char *type##2##str(type v) \
+{ \
+ int i = int2str_findint((int) v, __##type##2str); \
+ return (i < 0) ? defs : __##type##2str[i].str; \
+} \
+static inline type str##2##type(const char *str) \
+{ \
+ int i = int2str_findstr(str, __##type##2str); \
+ return (i < 0) ? (type) deft : (type) (__##type##2str[i].val); \
+} \
+static struct int2str __##type##2str[] = {
+
+#define ENDMAP {0, NULL} };
+
+/* use this to generate string from header file constant */
+#define MELEMENT(v, s) {v, s}
+/* use this to have arbitrary mapping from int to string */
+#define DELEMENT(s) {s, #s}
+/* End of mapping section */
+
+char *bt_bdaddr_t2str(const bt_bdaddr_t *bd_addr, char *buf);
+void str2bt_bdaddr_t(const char *str, bt_bdaddr_t *bd_addr);
+
+char *bt_uuid_t2str(const bt_uuid_t *uuid, char *buf);
+void str2bt_uuid_t(const char *str, bt_uuid_t *uuid);
+
+DECINTMAP(bt_status_t);
+DECINTMAP(bt_state_t);
+DECINTMAP(bt_device_type_t);
+DECINTMAP(bt_scan_mode_t);
+DECINTMAP(bt_discovery_state_t);
+DECINTMAP(bt_acl_state_t);
+DECINTMAP(bt_bond_state_t);
+DECINTMAP(bt_ssp_variant_t);
+DECINTMAP(bt_property_type_t);
+DECINTMAP(bt_cb_thread_evt);
--
1.7.9.5
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox