Linux bluetooth development
 help / color / mirror / Atom feed
* Re: [PATCH 14/14] android: Add support for handling SSP reply command
From: Johan Hedberg @ 2013-10-31  8:52 UTC (permalink / raw)
  To: Szymon Janc; +Cc: linux-bluetooth, Szymon Janc
In-Reply-To: <1383188154-22905-15-git-send-email-szymon.janc@tieto.com>

Hi Szymon,

On Thu, Oct 31, 2013, Szymon Janc wrote:
> ---
>  android/adapter.c | 94 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 94 insertions(+)

Patches 9-14 have been applied. Thanks.

Johan

^ permalink raw reply

* Re: [PATCH 1/2] android/haltest: Use Android system headers instead of local
From: Johan Hedberg @ 2013-10-31  8:53 UTC (permalink / raw)
  To: Andrei Emeltchenko; +Cc: linux-bluetooth
In-Reply-To: <1383208640-6644-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>

Hi Andrei,

On Thu, Oct 31, 2013, Andrei Emeltchenko wrote:
> ---
>  android/Android.mk |    4 ++++
>  1 file changed, 4 insertions(+)

Both patches have been applied. Thanks.

Johan

^ permalink raw reply

* Re: [RFC] android/hal: Add support for repacking received IPC data to HAL data
From: Johan Hedberg @ 2013-10-31  9:01 UTC (permalink / raw)
  To: Szymon Janc; +Cc: linux-bluetooth
In-Reply-To: <1383147054-16528-1-git-send-email-szymon.janc@tieto.com>

Hi Szymon,

On Wed, Oct 30, 2013, Szymon Janc wrote:
> Some HAL defined types that are passed as type-len-value in properties
> callback needs to be repacked at runtime to match defined types.
> 
> This is due to HAL using data types without strict refined sizes like
> enums or unpacked structures. This is needed only if data is passed as
> TLV. With data passed to callbacks as parameters compiler will handle
> types convertion.
> 
> Currently only enum types are supported.
> ---
> 
> This is only for received events. Same needs to be done when sending props
> from HAL lib to daemon.
> 
>  android/hal-bluetooth.c | 104 ++++++++++++++++++++++++++++++++++++++++++++----
>  1 file changed, 96 insertions(+), 8 deletions(-)

Patch looks good enough to me so it's now applied. Thanks.

Johan

^ permalink raw reply

* Re: Intel 7260 bluetooth malfunction when it is connected to EHCI bus
From: Marcel Holtmann @ 2013-10-31  9:49 UTC (permalink / raw)
  To: Hui Wang
  Cc: Tedd An, Johan Hedberg, xiong.y.zhang, Gustavo F. Padovan,
	linux-bluetooth@vger.kernel.org development
In-Reply-To: <5271EAA2.1030705@canonical.com>

Hi Hui,

>>>>> The problem is:
>>>>> On the machine which has Intel 7260 BT module, i use it to connect a bluetooth headset,
>>>>> it can successfully scan and connect to the headset, when i play sound to the bt headset,
>>>>> the problem comes, if the bt module is connected to the XHCI, it can work very well.
>>>>> 
>>>>> u@u-Lenovo-B4400:~$ lsusb -t
>>>>> 1-7:1.0: No such file or directory
>>>>> /: Bus 02.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/4p, 5000M
>>>>> /: Bus 01.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/14p, 480M
>>>>>    |__ Port 6: Dev 8, If 0, Class=HID, Driver=usbhid, 1.5M
>>>>>    |__ Port 7: Dev 2, If 0, Class=vend., Driver=, 12M
>>>>>    |__ Port 11: Dev 3, If 0, Class='bInterfaceClass 0xe0 not yet handled', Driver=btusb, 12M
>>>>>    |__ Port 11: Dev 3, If 1, Class='bInterfaceClass 0xe0 not yet handled', Driver=btusb, 12M
>>>>> 
>>>>> But if the bt module is connected to the EHCI, it always fails to play sound.
>>>>> 
>>>>> u@u-Lenovo-B4400:~$ lsusb -t
>>>>> /: Bus 04.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/4p, 5000M
>>>>> /: Bus 03.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/14p, 480M
>>>>> /: Bus 02.Port 1: Dev 1, Class=root_hub, Driver=ehci_hcd/3p, 480M
>>>>>    |__ Port 1: Dev 2, If 0, Class=hub, Driver=hub/8p, 480M
>>>>> /: Bus 01.Port 1: Dev 1, Class=root_hub, Driver=ehci_hcd/3p, 480M
>>>>>    |__ Port 1: Dev 2, If 0, Class=hub, Driver=hub/6p, 480M
>>>>>        |__ Port 5: Dev 3, If 0, Class='bInterfaceClass 0xe0 not yet handled', Driver=btusb, 12M
>>>>>        |__ Port 5: Dev 3, If 1, Class='bInterfaceClass 0xe0 not yet handled', Driver=btusb, 12M
>>>>>        |__ Port 6: Dev 4, If 0, Class='bInterfaceClass 0x0e not yet handled', Driver=uvcvideo, 480M
>>>>>        |__ Port 6: Dev 4, If 1, Class='bInterfaceClass 0x0e not yet handled', Driver=uvcvideo, 480M
>>>> can you paste /sys/kernel/debug/usb/devices here.
>>>> 
>>>> If the uvcvideo driver is also using ISOC URBs, we might have just exhausted the bandwidth of the USB bus here or these two devices just do not play nice with each other.
>>>> 
>>>> Try to unload the uvcvideo driver and try it again.
>>> Thanks for your reply, follow your instruction, i totally disabled the camera from the BIOS, then the usb tree like this,
>>> u@u-Lenovo-B4400:~$ lsusb -t
>>> 1-1.3:1.0: No such file or directory
>>> /:  Bus 04.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/4p, 5000M
>>> /:  Bus 03.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/14p, 480M
>>> /:  Bus 02.Port 1: Dev 1, Class=root_hub, Driver=ehci-pci/3p, 480M
>>>    |__ Port 1: Dev 2, If 0, Class=hub, Driver=hub/8p, 480M
>>> /:  Bus 01.Port 1: Dev 1, Class=root_hub, Driver=ehci-pci/3p, 480M
>>>    |__ Port 1: Dev 2, If 0, Class=hub, Driver=hub/6p, 480M
>>>        |__ Port 2: Dev 3, If 0, Class=HID, Driver=usbhid, 1.5M
>>>        |__ Port 3: Dev 4, If 0, Class=vend., Driver=, 12M
>>>        |__ Port 5: Dev 5, If 0, Class='bInterfaceClass 0xe0 not yet handled', Driver=btusb, 12M
>>>        |__ Port 5: Dev 5, If 1, Class='bInterfaceClass 0xe0 not yet handled', Driver=btusb, 12M
>>> u@u-Lenovo-B4400:~$ uname -a
>>> Linux u-Lenovo-B4400 3.12.0-031200rc6-generic #201310191635 SMP Sat Oct 19 20:36:43 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux
>>> 
>>> I re-did the test, the result is same as before, after the headset is connected and i play audio, no sound is heard from the headset.
>>> And hciconfig output shows still no SCO packets received by BT driver.
>>> u@u-Lenovo-B4400:~$ hciconfig
>>> hci0:    Type: BR/EDR  Bus: USB
>>>    BD Address: 00:15:00:CC:2D:D2  ACL MTU: 1021:5  SCO MTU: 96:5
>>>    UP RUNNING PSCAN
>>>    RX bytes:5853 acl:61 sco:0 events:298 errors:0
>>>    TX bytes:19212 acl:68 sco:1 commands:179 errors:0
>> this is strange. The only reason I can think of is that you do not have the firmware installed and or it is not loaded correctly. Does dmesg give any indication that something failed here.
> I can confirm the firmware file is the /lib/firmware/intel/ibt-hw-37.7.10-fw-1.80.2.3.d.bseq, and it is in the filesystem. And from the dmesg, the firmware was successfully loaded.
> 
> [    8.600217] Bluetooth: hci0: Intel Bluetooth firmware file: intel/ibt-hw-37.7.10-fw-1.80.2.3.d.bseq
> [    8.653635] kvm: disabled by bios
> [    8.672981] psmouse serio1: synaptics: Touchpad model: 1, fw: 8.1, id: 0x1e2b1, caps: 0xd00123/0x840300/0x126c00
> [    8.707034] input: SynPS/2 Synaptics TouchPad as /devices/platform/i8042/serio1/input/input13
> [    8.717725] Registered led device: phy0-led
> [    8.722730] ieee80211 phy0: Selected rate control algorithm 'iwl-mvm-rs'
> [    8.752626] Bluetooth: hci0: Intel Bluetooth firmware patch completed and activated
> 
>> Since this is a 3.12 kernel it should have native support for Intel specific setup routing. Any chance you can run btmon -w <file> before plugging the device into the bus. Maybe something goes wrong with the setup routine on EHCI.
> Do you mean the hcidump file i just sent in my previous email.

I do not get this. I specifically asked to run “btmon -w <file>” before plugging in the device. I want to see the early setup process here. What would I do with a hcidump trace.

Regards

Marcel


^ permalink raw reply

* [PATCH v2] android: Add support for handling remove bond command
From: Szymon Janc @ 2013-10-31 10:23 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc

From: Szymon Janc <szymon.janc@gmail.com>

Bond state change is send when command complete for unpair device is
received and status was success.
---
 android/adapter.c | 33 +++++++++++++++++++++++++++++++++
 1 file changed, 33 insertions(+)

diff --git a/android/adapter.c b/android/adapter.c
index 60c62f4..a3f9aa6 100644
--- a/android/adapter.c
+++ b/android/adapter.c
@@ -751,6 +751,34 @@ static bool cancel_bond(void *buf, uint16_t len)
 				NULL) > 0;
 }
 
+static void unpair_device_complete(uint8_t status, uint16_t length,
+					const void *param, void *user_data)
+{
+	const struct mgmt_rp_unpair_device *rp = param;
+
+	DBG("status %u", status);
+
+	if (status != MGMT_STATUS_SUCCESS)
+		return;
+
+	send_bond_state_change(&rp->addr.bdaddr, HAL_STATUS_SUCCESS,
+							HAL_BOND_STATE_NONE);
+}
+
+static bool remove_bond(void *buf, uint16_t len)
+{
+	struct hal_cmd_remove_bond *cmd = buf;
+	struct mgmt_cp_unpair_device cp;
+
+	cp.disconnect = 1;
+	cp.addr.type = BDADDR_BREDR;
+	android2bdaddr(cmd->bdaddr, &cp.addr.bdaddr);
+
+	return mgmt_send(adapter->mgmt, MGMT_OP_UNPAIR_DEVICE,
+				adapter->index, sizeof(cp), &cp,
+				unpair_device_complete, NULL, NULL) > 0;
+}
+
 static uint8_t pin_reply(void *buf, uint16_t len)
 {
 	struct hal_cmd_pin_reply *cmd = buf;
@@ -929,6 +957,11 @@ void bt_adapter_handle_cmd(GIOChannel *io, uint8_t opcode, void *buf,
 			goto error;
 
 		break;
+	case HAL_OP_REMOVE_BOND:
+		if (!remove_bond(buf, len))
+			goto error;
+
+		break;
 	case HAL_OP_PIN_REPLY:
 		status = pin_reply(buf, len);
 		if (status != HAL_STATUS_SUCCESS)
-- 
1.8.4.1


^ permalink raw reply related

* Re: [PATCH v2] android: Add support for handling remove bond command
From: Johan Hedberg @ 2013-10-31 10:33 UTC (permalink / raw)
  To: Szymon Janc; +Cc: linux-bluetooth, Szymon Janc
In-Reply-To: <1383215013-24490-1-git-send-email-szymon.janc@tieto.com>

Hi Szymon,

On Thu, Oct 31, 2013, Szymon Janc wrote:
> Bond state change is send when command complete for unpair device is
> received and status was success.
> ---
>  android/adapter.c | 33 +++++++++++++++++++++++++++++++++
>  1 file changed, 33 insertions(+)

Applied. Thanks.

Johan

^ permalink raw reply

* [PATCH 00/10] Add GATT support to haltest
From: Jerzy Kasenberg @ 2013-10-31 10:45 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Jerzy Kasenberg

This patachset adds code to call GATT hal methods.
Compiles on Android 4.3 and host.
On 4.2 it's source code is not included.

Status that is used in callbacks is currently printed as number.
This number corresponds to series of defines from file:
external/bluedroid/stack/include/gatt_api.h
This file looks like implementation detail for bluedroid.
It's to be decided it defines should be copied to bluez source code.
Until that status is printed as numbers.
Same applies to tGATT_WRITE_TYPE which is used as argument in
write_characteristic and write_descriptor.

Jerzy Kasenberg (10):
  android/client: Add skeleton for GATT interface
  android/client: Add GATT client callbacks code
  android/client: Add complex GATT type formating
  android/client: Add init/cleanup for GATT
  android/client: Add helper macros to verify args
  android/client: Add GATT client method calls
  android/client: Add GATT complex type parsing
  android/client: Add tab completion to GATT client
  android/client: Add GATT server callbacks code
  android/client: Add GATT server methods

 android/Android.mk       |    7 +
 android/Makefile.am      |    2 +
 android/client/haltest.c |    5 +
 android/client/if-bt.c   |    2 +
 android/client/if-gatt.c | 1733 ++++++++++++++++++++++++++++++++++++++++++++++
 android/client/if-main.h |   14 +
 6 files changed, 1763 insertions(+)
 create mode 100644 android/client/if-gatt.c

-- 
1.7.9.5


^ permalink raw reply

* [PATCH 01/10] android/client: Add skeleton for GATT interface
From: Jerzy Kasenberg @ 2013-10-31 10:45 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Jerzy Kasenberg
In-Reply-To: <1383216315-30627-1-git-send-email-jerzy.kasenberg@tieto.com>

This patch adds empty functions for all gatt methods
and callbacks.
---
 android/Android.mk       |    7 +
 android/Makefile.am      |    2 +
 android/client/haltest.c |    5 +
 android/client/if-bt.c   |    2 +
 android/client/if-gatt.c |  561 ++++++++++++++++++++++++++++++++++++++++++++++
 android/client/if-main.h |   14 ++
 6 files changed, 591 insertions(+)
 create mode 100644 android/client/if-gatt.c

diff --git a/android/Android.mk b/android/Android.mk
index e47f4a9..72ea8b8 100644
--- a/android/Android.mk
+++ b/android/Android.mk
@@ -121,6 +121,13 @@ LOCAL_SRC_FILES := \
 	client/if-pan.c \
 	client/if-sock.c \
 
+ANDROID_4_3_OR_ABOVE := $(shell echo 0 | awk -v v=$(PLATFORM_SDK_VERSION) 'END {print (v > 17) ? 1 : 0}')
+
+ifeq ($(ANDROID_4_3_OR_ABOVE), 1)
+LOCAL_SRC_FILES += \
+	client/if-gatt.c
+endif
+
 LOCAL_C_INCLUDES += \
 	$(call include-path-for, system-core) \
 	$(call include-path-for, libhardware) \
diff --git a/android/Makefile.am b/android/Makefile.am
index 05a124e..c5b70ab 100644
--- a/android/Makefile.am
+++ b/android/Makefile.am
@@ -53,6 +53,7 @@ android_haltest_SOURCES = android/client/haltest.c \
 				android/client/tabcompletion.c \
 				android/client/if-av.c \
 				android/client/if-bt.c \
+				android/client/if-gatt.c \
 				android/client/if-hf.c \
 				android/client/if-hh.c \
 				android/client/if-pan.c \
@@ -85,6 +86,7 @@ EXTRA_DIST += android/client/terminal.c \
 		android/client/history.c \
 		android/client/if-av.c \
 		android/client/if-bt.c \
+		android/client/if-gatt.c \
 		android/client/if-hf.c \
 		android/client/if-hh.c \
 		android/client/if-pan.c \
diff --git a/android/client/haltest.c b/android/client/haltest.c
index 7fe0436..bbe8693 100644
--- a/android/client/haltest.c
+++ b/android/client/haltest.c
@@ -32,6 +32,11 @@
 const struct interface *interfaces[] = {
 	&bluetooth_if,
 	&av_if,
+#if PLATFORM_SDK_VERSION > 17
+	&gatt_if,
+	&gatt_client_if,
+	&gatt_server_if,
+#endif
 	&hf_if,
 	&hh_if,
 	&pan_if,
diff --git a/android/client/if-bt.c b/android/client/if-bt.c
index 680738e..a3d6286 100644
--- a/android/client/if-bt.c
+++ b/android/client/if-bt.c
@@ -825,6 +825,8 @@ static void get_profile_interface_p(int argc, const char **argv)
 #if PLATFORM_SDK_VERSION > 17
 	else if (strcmp(BT_PROFILE_AV_RC_ID, id) == 0)
 		pif = &dummy; /* TODO: change when if_rc is there */
+	else if (strcmp(BT_PROFILE_GATT_ID, id) == 0)
+		pif = (const void **) &if_gatt;
 #endif
 	else
 		haltest_error("%s is not correct for get_profile_interface\n",
diff --git a/android/client/if-gatt.c b/android/client/if-gatt.c
new file mode 100644
index 0000000..09e2a49
--- /dev/null
+++ b/android/client/if-gatt.c
@@ -0,0 +1,561 @@
+/*
+ * 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 <hardware/bluetooth.h>
+
+#include "if-main.h"
+
+const btgatt_interface_t *if_gatt = NULL;
+
+/* BT-GATT Client callbacks. */
+
+/* Callback invoked in response to register_client */
+static void gattc_register_client_cb(int status, int client_if,
+							bt_uuid_t *app_uuid)
+{
+}
+
+/* Callback for scan results */
+static void gattc_scan_result_cb(bt_bdaddr_t *bda, int rssi, uint8_t *adv_data)
+{
+}
+
+/* GATT open callback invoked in response to open */
+static void gattc_connect_cb(int conn_id, int status, int client_if,
+							bt_bdaddr_t *bda)
+{
+}
+
+/* Callback invoked in response to close */
+static void gattc_disconnect_cb(int conn_id, int status, int client_if,
+							bt_bdaddr_t *bda)
+{
+}
+
+/*
+ * Invoked in response to search_service when the GATT service search
+ * has been completed.
+ */
+static void gattc_search_complete_cb(int conn_id, int status)
+{
+}
+
+/* Reports GATT services on a remote device */
+static void gattc_search_result_cb(int conn_id, btgatt_srvc_id_t *srvc_id)
+{
+}
+
+/* GATT characteristic enumeration result callback */
+static void gattc_get_characteristic_cb(int conn_id, int status,
+					btgatt_srvc_id_t *srvc_id,
+					btgatt_char_id_t *char_id,
+					int char_prop)
+{
+}
+
+/* GATT descriptor enumeration result callback */
+static void gattc_get_descriptor_cb(int conn_id, int status,
+		btgatt_srvc_id_t *srvc_id, btgatt_char_id_t *char_id,
+		bt_uuid_t *descr_id)
+{
+}
+
+/* GATT included service enumeration result callback */
+static void gattc_get_included_service_cb(int conn_id, int status,
+						btgatt_srvc_id_t *srvc_id,
+						btgatt_srvc_id_t *incl_srvc_id)
+{
+}
+
+/* Callback invoked in response to [de]register_for_notification */
+static void gattc_register_for_notification_cb(int conn_id, int registered,
+						int status,
+						btgatt_srvc_id_t *srvc_id,
+						btgatt_char_id_t *char_id)
+{
+}
+
+/*
+ * Remote device notification callback, invoked when a remote device sends
+ * a notification or indication that a client has registered for.
+ */
+static void gattc_notify_cb(int conn_id, btgatt_notify_params_t *p_data)
+{
+}
+
+/* Reports result of a GATT read operation */
+static void gattc_read_characteristic_cb(int conn_id, int status,
+						btgatt_read_params_t *p_data)
+{
+}
+
+/* GATT write characteristic operation callback */
+static void gattc_write_characteristic_cb(int conn_id, int status,
+						btgatt_write_params_t *p_data)
+{
+}
+
+/* GATT execute prepared write callback */
+static void gattc_execute_write_cb(int conn_id, int status)
+{
+}
+
+/* Callback invoked in response to read_descriptor */
+static void gattc_read_descriptor_cb(int conn_id, int status,
+						btgatt_read_params_t *p_data)
+{
+}
+
+/* Callback invoked in response to write_descriptor */
+static void gattc_write_descriptor_cb(int conn_id, int status,
+						btgatt_write_params_t *p_data)
+{
+}
+
+/* Callback triggered in response to read_remote_rssi */
+static void gattc_read_remote_rssi_cb(int client_if, bt_bdaddr_t *bda, int rssi,
+								int status)
+{
+}
+
+static const btgatt_client_callbacks_t btgatt_client_callbacks = {
+	.register_client_cb = gattc_register_client_cb,
+	.scan_result_cb = gattc_scan_result_cb,
+	.open_cb = gattc_connect_cb,
+	.close_cb = gattc_disconnect_cb,
+	.search_complete_cb = gattc_search_complete_cb,
+	.search_result_cb = gattc_search_result_cb,
+	.get_characteristic_cb = gattc_get_characteristic_cb,
+	.get_descriptor_cb = gattc_get_descriptor_cb,
+	.get_included_service_cb = gattc_get_included_service_cb,
+	.register_for_notification_cb = gattc_register_for_notification_cb,
+	.notify_cb = gattc_notify_cb,
+	.read_characteristic_cb = gattc_read_characteristic_cb,
+	.write_characteristic_cb = gattc_write_characteristic_cb,
+	.read_descriptor_cb = gattc_read_descriptor_cb,
+	.write_descriptor_cb = gattc_write_descriptor_cb,
+	.execute_write_cb = gattc_execute_write_cb,
+	.read_remote_rssi_cb = gattc_read_remote_rssi_cb
+};
+
+/* BT-GATT Server callbacks */
+
+/* Callback invoked in response to register_server */
+static void gatts_register_server_cb(int status, int server_if,
+							bt_uuid_t *app_uuid)
+{
+}
+
+/*
+ * Callback indicating that a remote device has connected
+ * or been disconnected
+ */
+static void gatts_connection_cb(int conn_id, int server_if, int connected,
+							bt_bdaddr_t *bda)
+{
+}
+
+/* Callback invoked in response to create_service */
+static void gatts_service_added_cb(int status, int server_if,
+				btgatt_srvc_id_t *srvc_id, int srvc_handle)
+{
+}
+
+/* Callback indicating that an included service has been added to a service */
+static void gatts_included_service_added_cb(int status, int server_if,
+							int srvc_handle,
+							int incl_srvc_handle)
+{
+}
+
+/* Callback invoked when a characteristic has been added to a service */
+static void gatts_characteristic_added_cb(int status, int server_if,
+								bt_uuid_t *uuid,
+								int srvc_handle,
+								int char_handle)
+{
+}
+
+/* Callback invoked when a descriptor has been added to a characteristic */
+static void gatts_descriptor_added_cb(int status, int server_if,
+					bt_uuid_t *uuid, int srvc_handle,
+							int descr_handle)
+{
+}
+
+/* Callback invoked in response to start_service */
+static void gatts_service_started_cb(int status, int server_if, int srvc_handle)
+{
+}
+
+/* Callback invoked in response to stop_service */
+static void gatts_service_stopped_cb(int status, int server_if, int srvc_handle)
+{
+}
+
+/* Callback triggered when a service has been deleted */
+static void gatts_service_deleted_cb(int status, int server_if, int srvc_handle)
+{
+}
+
+/*
+ * Callback invoked when a remote device has requested to read a characteristic
+ * or descriptor. The application must respond by calling send_response
+ */
+static void gatts_request_read_cb(int conn_id, int trans_id, bt_bdaddr_t *bda,
+						int attr_handle, int offset,
+						bool is_long)
+{
+}
+
+/*
+ * Callback invoked when a remote device has requested to write to a
+ * characteristic or descriptor.
+ */
+static void gatts_request_write_cb(int conn_id, int trans_id, bt_bdaddr_t *bda,
+					int attr_handle, int offset, int length,
+					bool need_rsp, bool is_prep,
+					uint8_t *value)
+{
+}
+
+/* Callback invoked when a previously prepared write is to be executed */
+static void gatts_request_exec_write_cb(int conn_id, int trans_id,
+					bt_bdaddr_t *bda, int exec_write)
+{
+}
+
+/*
+ * Callback triggered in response to send_response if the remote device
+ * sends a confirmation.
+ */
+static void gatts_response_confirmation_cb(int status, int handle)
+{
+}
+
+static const btgatt_server_callbacks_t btgatt_server_callbacks = {
+	.register_server_cb = gatts_register_server_cb,
+	.connection_cb = gatts_connection_cb,
+	.service_added_cb = gatts_service_added_cb,
+	.included_service_added_cb = gatts_included_service_added_cb,
+	.characteristic_added_cb = gatts_characteristic_added_cb,
+	.descriptor_added_cb = gatts_descriptor_added_cb,
+	.service_started_cb = gatts_service_started_cb,
+	.service_stopped_cb = gatts_service_stopped_cb,
+	.service_deleted_cb = gatts_service_deleted_cb,
+	.request_read_cb = gatts_request_read_cb,
+	.request_write_cb = gatts_request_write_cb,
+	.request_exec_write_cb = gatts_request_exec_write_cb,
+	.response_confirmation_cb = gatts_response_confirmation_cb
+};
+
+static const btgatt_callbacks_t gatt_cbacks = {
+	.size = sizeof(gatt_cbacks),
+	.client = &btgatt_client_callbacks,
+	.server = &btgatt_server_callbacks
+};
+
+/* gatt client methods */
+
+/* init */
+
+static void init_p(int argc, const char **argv)
+{
+}
+
+/* cleanup */
+
+static void cleanup_p(int argc, const char **argv)
+{
+}
+
+static struct method methods[] = {
+	STD_METHOD(init),
+	STD_METHOD(cleanup),
+	END_METHOD
+};
+
+const struct interface gatt_if = {
+	.name = "gatt",
+	.methods = methods
+};
+
+/* register_client */
+
+static void register_client_p(int argc, const char **argv)
+{
+}
+
+/* unregister_client */
+
+static void unregister_client_p(int argc, const char **argv)
+{
+}
+
+/* scan */
+
+static void scan_p(int argc, const char **argv)
+{
+}
+
+/* connect */
+
+static void connect_p(int argc, const char **argv)
+{
+}
+
+/* disconnect */
+
+static void disconnect_p(int argc, const char **argv)
+{
+}
+
+/* refresh */
+
+static void refresh_p(int argc, const char **argv)
+{
+}
+
+/* search_service */
+
+static void search_service_p(int argc, const char **argv)
+{
+}
+
+/* get_included_service */
+
+static void get_included_service_p(int argc, const char **argv)
+{
+}
+
+/* get_characteristic */
+
+static void get_characteristic_p(int argc, const char **argv)
+{
+}
+
+/* get_descriptor */
+
+static void get_descriptor_p(int argc, const char **argv)
+{
+}
+
+/* read_characteristic */
+
+static void read_characteristic_p(int argc, const char **argv)
+{
+}
+
+/* write_characteristic */
+
+static void write_characteristic_p(int argc, const char **argv)
+{
+}
+
+/* read_descriptor */
+
+static void read_descriptor_p(int argc, const char **argv)
+{
+}
+
+/* write_descriptor */
+
+static void write_descriptor_p(int argc, const char **argv)
+{
+}
+
+/* execute_write */
+
+static void execute_write_p(int argc, const char **argv)
+{
+}
+
+/* register_for_notification */
+
+static void register_for_notification_p(int argc, const char **argv)
+{
+}
+
+/* deregister_for_notification */
+
+static void deregister_for_notification_p(int argc, const char **argv)
+{
+}
+
+/* read_remote_rssi */
+
+static void read_remote_rssi_p(int argc, const char **argv)
+{
+}
+
+/* get_device_type */
+
+static void get_device_type_p(int argc, const char **argv)
+{
+}
+
+/* test_command */
+
+static void test_command_p(int argc, const char **argv)
+{
+}
+
+static struct method client_methods[] = {
+	STD_METHODH(register_client, "[<uuid>]"),
+	STD_METHODH(unregister_client, "<client_if>"),
+	STD_METHODH(scan, "<client_if> [1|0]"),
+	STD_METHODH(connect, "<client_if> <addr> [<is_direct>]"),
+	STD_METHODH(disconnect, "<client_if> <addr> <conn_id>"),
+	STD_METHODH(refresh, "<client_if> <addr>"),
+	STD_METHODH(search_service, "<conn_id> [<uuid>]"),
+	STD_METHODH(get_included_service, "<conn_id> <srvc_id>"),
+	STD_METHODH(get_characteristic, "<conn_id> <srvc_id>"),
+	STD_METHODH(get_descriptor, "<conn_id> <srvc_id> <char_id>"),
+	STD_METHODH(read_characteristic,
+			"<conn_id> <srvc_id> <char_id> [<auth_req>]"),
+	STD_METHODH(write_characteristic,
+			"<conn_id> <srvc_id> <char_id> <write_type> <hex_value> [<auth_req>]"),
+	STD_METHODH(read_descriptor,
+			"<conn_id> <srvc_id> <char_id> <descr_id> [<auth_req>]"),
+	STD_METHODH(write_descriptor,
+			"<conn_id> <srvc_id> <char_id> <descr_id> <write_type> <hex_value> [<auth_req>]"),
+	STD_METHODH(execute_write, "<conn_id> <execute>"),
+	STD_METHODH(register_for_notification,
+			"<client_if> <addr> <srvc_id> <char_id>"),
+	STD_METHODH(deregister_for_notification,
+			"<client_if> <addr> <srvc_id> <char_id>"),
+	STD_METHODH(read_remote_rssi, "<client_if> <addr>"),
+	STD_METHODH(get_device_type, "<addr>"),
+	STD_METHODH(test_command,
+			"<cmd> <addr> <uuid> [u1] [u2] [u3] [u4] [u5]"),
+	END_METHOD
+};
+
+const struct interface gatt_client_if = {
+	.name = "gattc",
+	.methods = client_methods
+};
+
+/* gatt server methods */
+
+/* register_server */
+
+static void gatts_register_server_p(int argc, const char *argv[])
+{
+}
+
+/* unregister_server */
+
+static void gatts_unregister_server_p(int argc, const char *argv[])
+{
+}
+
+/* connect */
+
+static void gatts_connect_p(int argc, const char *argv[])
+{
+}
+
+/* disconnect */
+
+static void gatts_disconnect_p(int argc, const char *argv[])
+{
+}
+
+/* add_service */
+
+static void gatts_add_service_p(int argc, const char *argv[])
+{
+}
+
+/* add_included_service */
+
+static void gatts_add_included_service_p(int argc, const char *argv[])
+{
+}
+
+/* add_characteristic */
+
+static void gatts_add_characteristic_p(int argc, const char *argv[])
+{
+}
+
+/* add_descriptor */
+
+static void gatts_add_descriptor_p(int argc, const char *argv[])
+{
+}
+
+/* start_service */
+
+static void gatts_start_service_p(int argc, const char *argv[])
+{
+}
+
+/* stop_service */
+
+static void gatts_stop_service_p(int argc, const char *argv[])
+{
+}
+
+/* delete_service */
+
+static void gatts_delete_service_p(int argc, const char *argv[])
+{
+}
+
+/* send_indication */
+
+static void gatts_send_indication_p(int argc, const char *argv[])
+{
+}
+
+/* send_response */
+
+static void gatts_send_response_p(int argc, const char *argv[])
+{
+}
+
+#define GATTS_METHODH(n, h) METHOD(#n, gatts_##n##_p, NULL, h)
+#define GATTS_METHODCH(n, h) METHOD(#n, gatts_##n##_p, gatts_##n##_c, h)
+
+static struct method server_methods[] = {
+	GATTS_METHODH(register_server, "[<uuid>]"),
+	GATTS_METHODH(unregister_server, "<server_if>"),
+	GATTS_METHODH(connect, "<server_if> <addr> [<is_direct>]"),
+	GATTS_METHODH(disconnect, "<server_if> <addr> <conn_id>"),
+	GATTS_METHODH(add_service, "<server_if> <srvc_id> <num_handles>"),
+	GATTS_METHODH(add_included_service,
+			"<server_if> <service_handle> <included_handle>"),
+	GATTS_METHODH(add_characteristic,
+		"<server_if> <service_handle> <uuid> <properites> <permissions>"),
+	GATTS_METHODH(add_descriptor, "<server_if> <uuid> <permissions>"),
+	GATTS_METHODH(start_service,
+				"<server_if> <service_handle> <transport>"),
+	GATTS_METHODH(stop_service, "<server_if> <service_handle>"),
+	GATTS_METHODH(delete_service, "<server_if> <service_handle>"),
+	GATTS_METHODH(send_indication,
+			"<server_if> <attr_handle> <conn_id> <confirm> [<data>]"),
+	GATTS_METHODH(send_response, "<conn_id> <trans_id> <status>"),
+	END_METHOD
+};
+
+const struct interface gatt_server_if = {
+	.name = "gatts",
+	.methods = server_methods
+};
+
diff --git a/android/client/if-main.h b/android/client/if-main.h
index 37086dd..0c59054 100644
--- a/android/client/if-main.h
+++ b/android/client/if-main.h
@@ -38,6 +38,10 @@
 
 #if PLATFORM_SDK_VERSION > 17
 #include <hardware/bt_rc.h>
+#include <hardware/bt_gatt.h>
+#include <hardware/bt_gatt_types.h>
+#include <hardware/bt_gatt_client.h>
+#include <hardware/bt_gatt_server.h>
 #endif
 
 #include "textconv.h"
@@ -49,6 +53,11 @@ extern const bthf_interface_t *if_hf;
 extern const bthh_interface_t *if_hh;
 extern const btpan_interface_t *if_pan;
 extern const btsock_interface_t *if_sock;
+#if PLATFORM_SDK_VERSION > 17
+extern const btgatt_interface_t *if_gatt;
+extern const btgatt_server_interface_t *if_gatt_server;
+extern const btgatt_client_interface_t *if_gatt_client;
+#endif
 
 /*
  * Structure defines top level interfaces that can be used in test tool
@@ -61,6 +70,11 @@ struct interface {
 
 extern const struct interface bluetooth_if;
 extern const struct interface av_if;
+#if PLATFORM_SDK_VERSION > 17
+extern const struct interface gatt_if;
+extern const struct interface gatt_client_if;
+extern const struct interface gatt_server_if;
+#endif
 extern const struct interface pan_if;
 extern const struct interface sock_if;
 extern const struct interface hf_if;
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH 02/10] android/client: Add GATT client callbacks code
From: Jerzy Kasenberg @ 2013-10-31 10:45 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Jerzy Kasenberg
In-Reply-To: <1383216315-30627-1-git-send-email-jerzy.kasenberg@tieto.com>

This adds callbacks code, mostly printing.
Complex formating function not implemented yet.
---
 android/client/if-gatt.c |  122 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 122 insertions(+)

diff --git a/android/client/if-gatt.c b/android/client/if-gatt.c
index 09e2a49..8f3dc3c 100644
--- a/android/client/if-gatt.c
+++ b/android/client/if-gatt.c
@@ -21,29 +21,84 @@
 
 const btgatt_interface_t *if_gatt = NULL;
 
+#define MAX_CHAR_ID_STR_LEN (MAX_UUID_STR_LEN + 3 + 11)
+#define MAX_SRVC_ID_STR_LEN (MAX_UUID_STR_LEN + 3 + 11 + 1 + 11)
+/* How man characters print from binary objects (arbitrary) */
+#define MAX_HEX_VAL_STR_LEN 100
+#define MAX_NOTIFY_PARAMS_STR_LEN (MAX_SRVC_ID_STR_LEN + MAX_CHAR_ID_STR_LEN \
+		+ MAX_ADDR_STR_LEN + MAX_HEX_VAL_STR_LEN + 60)
+#define MAX_READ_PARAMS_STR_LEN (MAX_SRVC_ID_STR_LEN + MAX_CHAR_ID_STR_LEN \
+		+ MAX_UUID_STR_LEN + MAX_HEX_VAL_STR_LEN + 80)
+
+static char *gatt_uuid_t2str(const bt_uuid_t *uuid, char *buf)
+{
+	return buf;
+}
+
+static char *btgatt_char_id_t2str(const btgatt_char_id_t *char_id, char *buf)
+{
+	return buf;
+}
+
+static char *btgatt_srvc_id_t2str(const btgatt_srvc_id_t *srvc_id, char *buf)
+{
+	return buf;
+}
+
+static char *btgatt_notify_params_t2str(const btgatt_notify_params_t *data,
+								char *buf)
+{
+	return buf;
+}
+
+static char *btgatt_read_params_t2str(const btgatt_read_params_t *data,
+								char *buf)
+{
+	return buf;
+}
+
 /* BT-GATT Client callbacks. */
 
 /* Callback invoked in response to register_client */
 static void gattc_register_client_cb(int status, int client_if,
 							bt_uuid_t *app_uuid)
 {
+	char buf[MAX_UUID_STR_LEN];
+
+	haltest_info("%s: status=%d client_if=%d app_uuid=%s\n", __func__,
+						status, client_if,
+						gatt_uuid_t2str(app_uuid, buf));
 }
 
 /* Callback for scan results */
 static void gattc_scan_result_cb(bt_bdaddr_t *bda, int rssi, uint8_t *adv_data)
 {
+	char buf[MAX_ADDR_STR_LEN];
+
+	haltest_info("%s: bda=%s rssi=%d adv_data=%p\n", __func__,
+				bt_bdaddr_t2str(bda, buf), rssi, adv_data);
 }
 
 /* GATT open callback invoked in response to open */
 static void gattc_connect_cb(int conn_id, int status, int client_if,
 							bt_bdaddr_t *bda)
 {
+	char buf[MAX_ADDR_STR_LEN];
+
+	haltest_info("%s: conn_id=%d status=%d, client_if=%d bda=%s\n",
+					__func__, conn_id, status, client_if,
+					bt_bdaddr_t2str(bda, buf));
 }
 
 /* Callback invoked in response to close */
 static void gattc_disconnect_cb(int conn_id, int status, int client_if,
 							bt_bdaddr_t *bda)
 {
+	char buf[MAX_ADDR_STR_LEN];
+
+	haltest_info("%s: conn_id=%d status=%d, client_if=%d bda=%s\n",
+					__func__, conn_id, status, client_if,
+					bt_bdaddr_t2str(bda, buf));
 }
 
 /*
@@ -52,11 +107,16 @@ static void gattc_disconnect_cb(int conn_id, int status, int client_if,
  */
 static void gattc_search_complete_cb(int conn_id, int status)
 {
+	haltest_info("%s: conn_id=%d status=%s\n", __func__, conn_id, status);
 }
 
 /* Reports GATT services on a remote device */
 static void gattc_search_result_cb(int conn_id, btgatt_srvc_id_t *srvc_id)
 {
+	char srvc_id_buf[MAX_SRVC_ID_STR_LEN];
+
+	haltest_info("%s: conn_id=%d srvc_id=%s\n", __func__, conn_id,
+				btgatt_srvc_id_t2str(srvc_id, srvc_id_buf));
 }
 
 /* GATT characteristic enumeration result callback */
@@ -65,6 +125,18 @@ static void gattc_get_characteristic_cb(int conn_id, int status,
 					btgatt_char_id_t *char_id,
 					int char_prop)
 {
+	char srvc_id_buf[MAX_SRVC_ID_STR_LEN];
+	char char_id_buf[MAX_CHAR_ID_STR_LEN];
+
+	haltest_info("%s: conn_id=%d status=%d srvc_id=%s char_id=%s, char_prop=%x\n",
+			__func__, conn_id, status,
+			btgatt_srvc_id_t2str(srvc_id, srvc_id_buf),
+			btgatt_char_id_t2str(char_id, char_id_buf), char_prop);
+
+	/* enumerate next characteristic */
+	if (status == 0)
+		EXEC(if_gatt->client->get_characteristic, conn_id, srvc_id,
+								char_id);
 }
 
 /* GATT descriptor enumeration result callback */
@@ -72,6 +144,19 @@ static void gattc_get_descriptor_cb(int conn_id, int status,
 		btgatt_srvc_id_t *srvc_id, btgatt_char_id_t *char_id,
 		bt_uuid_t *descr_id)
 {
+	char buf[MAX_UUID_STR_LEN];
+	char srvc_id_buf[MAX_SRVC_ID_STR_LEN];
+	char char_id_buf[MAX_CHAR_ID_STR_LEN];
+
+	haltest_info("%s: conn_id=%d status=%d srvc_id=%s char_id=%s, descr_id=%s\n",
+				__func__, conn_id, status,
+				btgatt_srvc_id_t2str(srvc_id, srvc_id_buf),
+				btgatt_char_id_t2str(char_id, char_id_buf),
+				gatt_uuid_t2str(descr_id, buf));
+
+	if (status == 0)
+		EXEC(if_gatt->client->get_descriptor, conn_id, srvc_id, char_id,
+								descr_id);
 }
 
 /* GATT included service enumeration result callback */
@@ -79,6 +164,17 @@ static void gattc_get_included_service_cb(int conn_id, int status,
 						btgatt_srvc_id_t *srvc_id,
 						btgatt_srvc_id_t *incl_srvc_id)
 {
+	char srvc_id_buf[MAX_SRVC_ID_STR_LEN];
+	char incl_srvc_id_buf[MAX_SRVC_ID_STR_LEN];
+
+	haltest_info("%s: conn_id=%d status=%d srvc_id=%s incl_srvc_id=%s)\n",
+			__func__, conn_id, status,
+			btgatt_srvc_id_t2str(srvc_id, srvc_id_buf),
+			btgatt_srvc_id_t2str(incl_srvc_id, incl_srvc_id_buf));
+
+	if (status == 0)
+		EXEC(if_gatt->client->get_included_service, conn_id, srvc_id,
+								incl_srvc_id);
 }
 
 /* Callback invoked in response to [de]register_for_notification */
@@ -87,6 +183,13 @@ static void gattc_register_for_notification_cb(int conn_id, int registered,
 						btgatt_srvc_id_t *srvc_id,
 						btgatt_char_id_t *char_id)
 {
+	char srvc_id_buf[MAX_SRVC_ID_STR_LEN];
+	char char_id_buf[MAX_CHAR_ID_STR_LEN];
+
+	haltest_info("%s: conn_id=%d registered=%d status=%d srvc_id=%s char_id=%s\n",
+				__func__, conn_id, registered, status,
+				btgatt_srvc_id_t2str(srvc_id, srvc_id_buf),
+				btgatt_char_id_t2str(char_id, char_id_buf));
 }
 
 /*
@@ -95,41 +198,60 @@ static void gattc_register_for_notification_cb(int conn_id, int registered,
  */
 static void gattc_notify_cb(int conn_id, btgatt_notify_params_t *p_data)
 {
+	char buf[MAX_NOTIFY_PARAMS_STR_LEN];
+
+	haltest_info("%s: conn_id=%d data=%s\n", __func__, conn_id,
+				btgatt_notify_params_t2str(p_data, buf));
 }
 
 /* Reports result of a GATT read operation */
 static void gattc_read_characteristic_cb(int conn_id, int status,
 						btgatt_read_params_t *p_data)
 {
+	char buf[MAX_READ_PARAMS_STR_LEN];
+
+	haltest_info("%s: conn_id=%d status=%d data=%s\n", __func__, conn_id,
+				status, btgatt_read_params_t2str(p_data, buf));
 }
 
 /* GATT write characteristic operation callback */
 static void gattc_write_characteristic_cb(int conn_id, int status,
 						btgatt_write_params_t *p_data)
 {
+	haltest_info("%s: conn_id=%d status=%d\n", __func__, conn_id, status);
 }
 
 /* GATT execute prepared write callback */
 static void gattc_execute_write_cb(int conn_id, int status)
 {
+	haltest_info("%s: conn_id=%d status=%d\n", __func__, conn_id, status);
 }
 
 /* Callback invoked in response to read_descriptor */
 static void gattc_read_descriptor_cb(int conn_id, int status,
 						btgatt_read_params_t *p_data)
 {
+	char buf[MAX_READ_PARAMS_STR_LEN];
+
+	haltest_info("%s: conn_id=%d status=%d data=%s\n", __func__, conn_id,
+				status, btgatt_read_params_t2str(p_data, buf));
 }
 
 /* Callback invoked in response to write_descriptor */
 static void gattc_write_descriptor_cb(int conn_id, int status,
 						btgatt_write_params_t *p_data)
 {
+	haltest_info("%s: conn_id=%d status=%d\n", __func__, conn_id, status);
 }
 
 /* Callback triggered in response to read_remote_rssi */
 static void gattc_read_remote_rssi_cb(int client_if, bt_bdaddr_t *bda, int rssi,
 								int status)
 {
+	char buf[MAX_ADDR_STR_LEN];
+
+	haltest_info("%s: client_if=%d bda=%s rssi=%d satus=%d\n", __func__,
+			client_if, bt_bdaddr_t2str(bda, buf), rssi, status);
 }
 
 static const btgatt_client_callbacks_t btgatt_client_callbacks = {
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH 03/10] android/client: Add complex GATT type formating
From: Jerzy Kasenberg @ 2013-10-31 10:45 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Jerzy Kasenberg
In-Reply-To: <1383216315-30627-1-git-send-email-jerzy.kasenberg@tieto.com>

This adds formating for complex types in GATT.
---
 android/client/if-gatt.c |   99 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 99 insertions(+)

diff --git a/android/client/if-gatt.c b/android/client/if-gatt.c
index 8f3dc3c..db5494c 100644
--- a/android/client/if-gatt.c
+++ b/android/client/if-gatt.c
@@ -30,30 +30,129 @@ const btgatt_interface_t *if_gatt = NULL;
 #define MAX_READ_PARAMS_STR_LEN (MAX_SRVC_ID_STR_LEN + MAX_CHAR_ID_STR_LEN \
 		+ MAX_UUID_STR_LEN + MAX_HEX_VAL_STR_LEN + 80)
 
+/* Gatt uses little endian uuid */
+static const char GATT_BASE_UUID[] = {
+	0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
+	0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+/*
+ * converts gatt uuid to string
+ * buf should be at least 39 bytes
+ *
+ * This function formats 16, 32 and 128 bits uuid
+ *
+ * returns string representation of uuid
+ */
 static char *gatt_uuid_t2str(const bt_uuid_t *uuid, char *buf)
 {
+	int shift = 0;
+	int i = 16;
+	int limit = 0;
+	int j = 0;
+
+	/* for bluetooth uuid only 32 bits */
+	if (0 == memcmp(&uuid->uu, &GATT_BASE_UUID,
+						sizeof(bt_uuid_t) - 4)) {
+		limit = 12;
+		/* make it 16 bits */
+		if (uuid->uu[15] == 0 && uuid->uu[14] == 0)
+			i = 14;
+	}
+
+	while (i-- > limit) {
+		if (i == 11 || i == 9 || i == 7 || i == 5) {
+			buf[j * 2 + shift] = '-';
+			shift++;
+		}
+
+		sprintf(buf + j * 2 + shift, "%02x", uuid->uu[i]);
+		++j;
+	}
+
 	return buf;
 }
 
+/* char_id formating function */
 static char *btgatt_char_id_t2str(const btgatt_char_id_t *char_id, char *buf)
 {
+	char uuid_buf[MAX_UUID_STR_LEN];
+
+	sprintf(buf, "{%s,%d}", gatt_uuid_t2str(&char_id->uuid, uuid_buf),
+							char_id->inst_id);
 	return buf;
 }
 
+/* service_id formating function */
 static char *btgatt_srvc_id_t2str(const btgatt_srvc_id_t *srvc_id, char *buf)
 {
+	char uuid_buf[MAX_UUID_STR_LEN];
+
+	sprintf(buf, "{%s,%d,%d}", gatt_uuid_t2str(&srvc_id->id.uuid, uuid_buf),
+				srvc_id->id.inst_id, srvc_id->is_primary);
+	return buf;
+}
+
+/* Converts array of uint8_t to string representation */
+static char *array2str(const uint8_t *v, int size, char *buf, int out_size)
+{
+	int limit = size;
+	int i;
+
+	if (out_size > 0) {
+		*buf = '\0';
+		if (size >= 2 * out_size)
+			limit = (out_size - 2) / 2;
+
+		for (i = 0; i < limit; ++i)
+			sprintf(buf + 2 * i, "%02x", v[i]);
+
+		/* output buffer not enough to hold whole field fill with ...*/
+		if (limit < size)
+			sprintf(buf + 2 * i, "...");
+	}
+
 	return buf;
 }
 
+/* Converts btgatt_notify_params_t to string */
 static char *btgatt_notify_params_t2str(const btgatt_notify_params_t *data,
 								char *buf)
 {
+	char addr[MAX_ADDR_STR_LEN];
+	char srvc_id[MAX_SRVC_ID_STR_LEN];
+	char char_id[MAX_CHAR_ID_STR_LEN];
+	char value[MAX_HEX_VAL_STR_LEN];
+
+	sprintf(buf, "{bda=%s, srvc_id=%s, char_id=%s, val=%s, is_notify=%u}",
+		bt_bdaddr_t2str(&data->bda, addr),
+		btgatt_srvc_id_t2str(&data->srvc_id, srvc_id),
+		btgatt_char_id_t2str(&data->char_id, char_id),
+		array2str(data->value, data->len, value, sizeof(value)),
+							data->is_notify);
 	return buf;
 }
 
+static char *btgatt_unformatted_value_t2str(const btgatt_unformatted_value_t *v,
+							char *buf, int size)
+{
+	return array2str(v->value, v->len, buf, size);
+}
+
 static char *btgatt_read_params_t2str(const btgatt_read_params_t *data,
 								char *buf)
 {
+	char srvc_id[MAX_SRVC_ID_STR_LEN];
+	char char_id[MAX_CHAR_ID_STR_LEN];
+	char descr_id[MAX_UUID_STR_LEN];
+	char value[MAX_HEX_VAL_STR_LEN];
+
+	sprintf(buf, "{srvc_id=%s, char_id=%s, descr_id=%s, val=%s value_type=%d, status=%d}",
+		btgatt_srvc_id_t2str(&data->srvc_id, srvc_id),
+		btgatt_char_id_t2str(&data->char_id, char_id),
+		gatt_uuid_t2str(&data->descr_id, descr_id),
+		btgatt_unformatted_value_t2str(&data->value, value, 100),
+		data->value_type, data->status);
 	return buf;
 }
 
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH 04/10] android/client: Add init/cleanup for GATT
From: Jerzy Kasenberg @ 2013-10-31 10:45 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Jerzy Kasenberg
In-Reply-To: <1383216315-30627-1-git-send-email-jerzy.kasenberg@tieto.com>

This patch adds gatt functions code.
---
 android/client/if-gatt.c |    8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/android/client/if-gatt.c b/android/client/if-gatt.c
index db5494c..90cc805 100644
--- a/android/client/if-gatt.c
+++ b/android/client/if-gatt.c
@@ -496,12 +496,20 @@ static const btgatt_callbacks_t gatt_cbacks = {
 
 static void init_p(int argc, const char **argv)
 {
+	RETURN_IF_NULL(if_gatt);
+
+	EXEC(if_gatt->init, &gatt_cbacks);
 }
 
 /* cleanup */
 
 static void cleanup_p(int argc, const char **argv)
 {
+	RETURN_IF_NULL(if_gatt);
+
+	EXECV(if_gatt->cleanup);
+
+	if_gatt = NULL;
 }
 
 static struct method methods[] = {
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH 05/10] android/client: Add helper macros to verify args
From: Jerzy Kasenberg @ 2013-10-31 10:45 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Jerzy Kasenberg
In-Reply-To: <1383216315-30627-1-git-send-email-jerzy.kasenberg@tieto.com>

This patch adds bunch of macros that will simplify
common arguments checking for methods.
---
 android/client/if-gatt.c |   57 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 57 insertions(+)

diff --git a/android/client/if-gatt.c b/android/client/if-gatt.c
index 90cc805..60b1ec5 100644
--- a/android/client/if-gatt.c
+++ b/android/client/if-gatt.c
@@ -30,6 +30,63 @@ const btgatt_interface_t *if_gatt = NULL;
 #define MAX_READ_PARAMS_STR_LEN (MAX_SRVC_ID_STR_LEN + MAX_CHAR_ID_STR_LEN \
 		+ MAX_UUID_STR_LEN + MAX_HEX_VAL_STR_LEN + 80)
 
+#define VERIFY_INT_ARG(n, v, err) \
+	do { \
+		if (n < argc) \
+			v = atoi(argv[n]); \
+		else { \
+			haltest_error(err); \
+			return;\
+		} \
+	} while (0)
+
+#define VERIFY_HEX_ARG(n, v, err) \
+	do { \
+		if (n < argc) \
+			v = strtol(argv[n], NULL, 16); \
+		else { \
+			haltest_error(err); \
+			return;\
+		} \
+	} while (0)
+
+/* Helper macros to verify arguments of methods */
+#define VERIFY_CLIENT_IF(n, v) VERIFY_INT_ARG(n, v, "No client_if specified\n")
+#define VERIFY_SERVER_IF(n, v) VERIFY_INT_ARG(n, v, "No server_if specified\n")
+#define VERIFY_CONN_ID(n, v) VERIFY_INT_ARG(n, v, "No conn_if specified\n")
+#define VERIFY_HANDLE(n, v) VERIFY_HEX_ARG(n, v, "No "#v" specified\n")
+#define VERIFY_SERVICE_HANDLE(n, v) VERIFY_HANDLE(n, v)
+
+#define VERIFY_UUID(n, v) \
+	do { \
+		if (n < argc) \
+			gatt_str2bt_uuid_t(argv[n], -1, v); \
+		else { \
+			haltest_error("No uuid specified\n"); \
+			return;\
+		} \
+	} while (0)
+
+#define VERIFY_SRVC_ID(n, v) \
+	do { \
+		if (n < argc) \
+			str2btgatt_srvc_id_t(argv[n], v); \
+		else { \
+			haltest_error("No srvc_id specified\n"); \
+			return;\
+		} \
+	} while (0)
+
+#define VERIFY_CHAR_ID(n, v) \
+	do { \
+		if (n < argc) \
+			str2btgatt_char_id_t(argv[n], v); \
+		else { \
+			haltest_error("No char_id specified\n"); \
+			return;\
+		} \
+	} while (0)
+
 /* Gatt uses little endian uuid */
 static const char GATT_BASE_UUID[] = {
 	0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH 06/10] android/client: Add GATT client method calls
From: Jerzy Kasenberg @ 2013-10-31 10:45 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Jerzy Kasenberg
In-Reply-To: <1383216315-30627-1-git-send-email-jerzy.kasenberg@tieto.com>

This patch adds code for all GATT client methods.
---
 android/client/if-gatt.c |  317 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 317 insertions(+)

diff --git a/android/client/if-gatt.c b/android/client/if-gatt.c
index 60b1ec5..70dbb24 100644
--- a/android/client/if-gatt.c
+++ b/android/client/if-gatt.c
@@ -130,6 +130,18 @@ static char *gatt_uuid_t2str(const bt_uuid_t *uuid, char *buf)
 	return buf;
 }
 
+/*
+ * Tries to convert hex string of given size into out buffer.
+ * Output buffer is little endian.
+ */
+static void scan_field(const char *str, int len, uint8_t *out, int out_size)
+{
+}
+
+static void gatt_str2bt_uuid_t(const char *str, int len, bt_uuid_t *uuid)
+{
+}
+
 /* char_id formating function */
 static char *btgatt_char_id_t2str(const btgatt_char_id_t *char_id, char *buf)
 {
@@ -140,6 +152,11 @@ static char *btgatt_char_id_t2str(const btgatt_char_id_t *char_id, char *buf)
 	return buf;
 }
 
+/* Parse btgatt_char_id_t */
+static void str2btgatt_char_id_t(const char *buf, btgatt_char_id_t *char_id)
+{
+}
+
 /* service_id formating function */
 static char *btgatt_srvc_id_t2str(const btgatt_srvc_id_t *srvc_id, char *buf)
 {
@@ -150,6 +167,11 @@ static char *btgatt_srvc_id_t2str(const btgatt_srvc_id_t *srvc_id, char *buf)
 	return buf;
 }
 
+/* Parse btgatt_srvc_id_t */
+static void str2btgatt_srvc_id_t(const char *buf, btgatt_srvc_id_t *srvc_id)
+{
+}
+
 /* Converts array of uint8_t to string representation */
 static char *array2str(const uint8_t *v, int size, char *buf, int out_size)
 {
@@ -584,120 +606,415 @@ const struct interface gatt_if = {
 
 static void register_client_p(int argc, const char **argv)
 {
+	bt_uuid_t uuid;
+
+	RETURN_IF_NULL(if_gatt);
+
+	/* uuid */
+	if (argc <= 2)
+		gatt_str2bt_uuid_t("babe4bed", -1, &uuid);
+	else
+		gatt_str2bt_uuid_t(argv[2], -1, &uuid);
+
+	EXEC(if_gatt->client->register_client, &uuid);
 }
 
 /* unregister_client */
 
 static void unregister_client_p(int argc, const char **argv)
 {
+	int client_if;
+
+	RETURN_IF_NULL(if_gatt);
+	VERIFY_CLIENT_IF(2, client_if);
+
+	EXEC(if_gatt->client->unregister_client, client_if);
 }
 
 /* scan */
 
 static void scan_p(int argc, const char **argv)
 {
+	int client_if;
+	int start = 1;
+
+	RETURN_IF_NULL(if_gatt);
+
+	VERIFY_CLIENT_IF(2, client_if);
+
+	/* start */
+	if (argc >= 3)
+		start = atoi(argv[3]);
+
+	EXEC(if_gatt->client->scan, client_if, start);
 }
 
 /* connect */
 
 static void connect_p(int argc, const char **argv)
 {
+	int client_if;
+	bt_bdaddr_t bd_addr;
+	int is_direct = 1;
+
+	RETURN_IF_NULL(if_gatt);
+	VERIFY_CLIENT_IF(2, client_if);
+	VERIFY_ADDR_ARG(3, &bd_addr);
+
+	/* is_direct */
+	if (argc > 4)
+		is_direct = atoi(argv[4]);
+
+	EXEC(if_gatt->client->connect, client_if, &bd_addr, is_direct);
 }
 
 /* disconnect */
 
 static void disconnect_p(int argc, const char **argv)
 {
+	int client_if;
+	bt_bdaddr_t bd_addr;
+	int conn_id;
+
+	RETURN_IF_NULL(if_gatt);
+	VERIFY_CLIENT_IF(2, client_if);
+	VERIFY_ADDR_ARG(3, &bd_addr);
+	VERIFY_CONN_ID(4, conn_id);
+
+	EXEC(if_gatt->client->disconnect, client_if, &bd_addr, conn_id);
 }
 
 /* refresh */
 
 static void refresh_p(int argc, const char **argv)
 {
+	int client_if;
+	bt_bdaddr_t bd_addr;
+
+	RETURN_IF_NULL(if_gatt);
+	VERIFY_CLIENT_IF(2, client_if);
+	VERIFY_ADDR_ARG(3, &bd_addr);
+
+	EXEC(if_gatt->client->refresh, client_if, &bd_addr);
 }
 
 /* search_service */
 
 static void search_service_p(int argc, const char **argv)
 {
+	int conn_id;
+	bt_uuid_t filter_uuid;
+
+	RETURN_IF_NULL(if_gatt);
+
+	VERIFY_CONN_ID(2, conn_id);
+
+	/* uuid */
+	if (argc <= 3)
+		memset(&filter_uuid, 0, sizeof(bt_uuid_t));
+	else
+		gatt_str2bt_uuid_t(argv[3], -1, &filter_uuid);
+
+	EXEC(if_gatt->client->search_service, conn_id, &filter_uuid);
 }
 
 /* get_included_service */
 
 static void get_included_service_p(int argc, const char **argv)
 {
+	int conn_id;
+	btgatt_srvc_id_t srvc_id;
+
+	RETURN_IF_NULL(if_gatt);
+	VERIFY_CONN_ID(2, conn_id);
+	VERIFY_SRVC_ID(3, &srvc_id);
+
+	EXEC(if_gatt->client->get_included_service, conn_id, &srvc_id, NULL);
 }
 
 /* get_characteristic */
 
 static void get_characteristic_p(int argc, const char **argv)
 {
+	int conn_id;
+	btgatt_srvc_id_t srvc_id;
+
+	RETURN_IF_NULL(if_gatt);
+	VERIFY_CONN_ID(2, conn_id);
+	VERIFY_SRVC_ID(3, &srvc_id);
+
+	EXEC(if_gatt->client->get_characteristic, conn_id, &srvc_id, NULL);
 }
 
 /* get_descriptor */
 
 static void get_descriptor_p(int argc, const char **argv)
 {
+	int conn_id;
+	btgatt_srvc_id_t srvc_id;
+	btgatt_char_id_t char_id;
+
+	RETURN_IF_NULL(if_gatt);
+	VERIFY_CONN_ID(2, conn_id);
+	VERIFY_SRVC_ID(3, &srvc_id);
+	VERIFY_CHAR_ID(4, &char_id);
+
+	EXEC(if_gatt->client->get_descriptor, conn_id, &srvc_id, &char_id,
+									NULL);
 }
 
 /* read_characteristic */
 
 static void read_characteristic_p(int argc, const char **argv)
 {
+	int conn_id;
+	btgatt_srvc_id_t srvc_id;
+	btgatt_char_id_t char_id;
+	int auth_req = 0;
+
+	RETURN_IF_NULL(if_gatt);
+	VERIFY_CONN_ID(2, conn_id);
+	VERIFY_SRVC_ID(3, &srvc_id);
+	VERIFY_CHAR_ID(4, &char_id);
+
+	/* auth_req */
+	if (argc > 5)
+		auth_req = atoi(argv[5]);
+
+	EXEC(if_gatt->client->read_characteristic, conn_id, &srvc_id, &char_id,
+								auth_req);
 }
 
 /* write_characteristic */
 
 static void write_characteristic_p(int argc, const char **argv)
 {
+	int conn_id;
+	btgatt_srvc_id_t srvc_id;
+	btgatt_char_id_t char_id;
+	int write_type;
+	int len;
+	int auth_req = 0;
+	uint8_t value[100];
+
+	RETURN_IF_NULL(if_gatt);
+	VERIFY_CONN_ID(2, conn_id);
+	VERIFY_SRVC_ID(3, &srvc_id);
+	VERIFY_CHAR_ID(4, &char_id);
+
+	/* write type */
+	if (argc <= 5) {
+		haltest_error("No write type specified\n");
+		return;
+	}
+	write_type = atoi(argv[5]);
+
+	/* value */
+	if (argc <= 6) {
+		haltest_error("No value specified\n");
+		return;
+	}
+
+	/* len in chars */
+	len = strlen(argv[6]);
+	scan_field(argv[6], len, value, sizeof(value));
+	/* len in bytes converted from ascii chars */
+	len = (len + 1) / 2;
+
+	/* auth_req */
+	if (argc > 7)
+		auth_req = atoi(argv[7]);
+
+	EXEC(if_gatt->client->write_characteristic, conn_id, &srvc_id, &char_id,
+				write_type, len, auth_req, (char *) value);
 }
 
 /* read_descriptor */
 
 static void read_descriptor_p(int argc, const char **argv)
 {
+	int conn_id;
+	btgatt_srvc_id_t srvc_id;
+	btgatt_char_id_t char_id;
+	bt_uuid_t descr_id;
+	int auth_req = 0;
+
+	RETURN_IF_NULL(if_gatt);
+	VERIFY_CONN_ID(2, conn_id);
+	VERIFY_SRVC_ID(3, &srvc_id);
+	VERIFY_CHAR_ID(4, &char_id);
+	VERIFY_UUID(5, &descr_id);
+
+	/* auth_req */
+	if (argc > 6)
+		auth_req = atoi(argv[6]);
+
+	EXEC(if_gatt->client->read_descriptor, conn_id, &srvc_id, &char_id,
+							&descr_id, auth_req);
 }
 
 /* write_descriptor */
 
 static void write_descriptor_p(int argc, const char **argv)
 {
+	int conn_id;
+	btgatt_srvc_id_t srvc_id;
+	btgatt_char_id_t char_id;
+	bt_uuid_t descr_id;
+	int write_type;
+	int len;
+	int auth_req = 0;
+	uint8_t value[200] = {0};
+
+	RETURN_IF_NULL(if_gatt);
+	VERIFY_CONN_ID(2, conn_id);
+	VERIFY_SRVC_ID(3, &srvc_id);
+	VERIFY_CHAR_ID(4, &char_id);
+	VERIFY_UUID(5, &descr_id);
+
+	/* write type */
+	if (argc <= 6) {
+		haltest_error("No write type specified\n");
+		return;
+	}
+	write_type = atoi(argv[6]);
+
+	/* value */
+	if (argc <= 7) {
+		haltest_error("No value specified\n");
+		return;
+	}
+
+	/* len in chars */
+	len = strlen(argv[7]);
+	scan_field(argv[7], len, value, sizeof(value));
+	/* len in bytes converted from ascii chars */
+	len = (len + 1) / 2;
+
+	/* auth_req */
+	if (argc > 8)
+		auth_req = atoi(argv[8]);
+
+	EXEC(if_gatt->client->write_descriptor, conn_id, &srvc_id, &char_id,
+			&descr_id, write_type, len, auth_req, (char *) value);
 }
 
 /* execute_write */
 
 static void execute_write_p(int argc, const char **argv)
 {
+	int conn_id;
+	int execute;
+
+	RETURN_IF_NULL(if_gatt);
+	VERIFY_CONN_ID(2, conn_id);
+
+	/* execute */
+	if (argc <= 3) {
+		haltest_error("No execute specified\n");
+		return;
+	}
+	execute = atoi(argv[3]);
+
+	EXEC(if_gatt->client->execute_write, conn_id, execute);
 }
 
 /* register_for_notification */
 
 static void register_for_notification_p(int argc, const char **argv)
 {
+	int client_if;
+	bt_bdaddr_t bd_addr;
+	btgatt_srvc_id_t srvc_id;
+	btgatt_char_id_t char_id;
+
+	RETURN_IF_NULL(if_gatt);
+	VERIFY_CLIENT_IF(2, client_if);
+	VERIFY_ADDR_ARG(3, &bd_addr);
+	VERIFY_SRVC_ID(4, &srvc_id);
+	VERIFY_CHAR_ID(5, &char_id);
+
+	EXEC(if_gatt->client->register_for_notification, client_if, &bd_addr,
+							&srvc_id, &char_id);
 }
 
 /* deregister_for_notification */
 
 static void deregister_for_notification_p(int argc, const char **argv)
 {
+	int client_if;
+	bt_bdaddr_t bd_addr;
+	btgatt_srvc_id_t srvc_id;
+	btgatt_char_id_t char_id;
+
+	RETURN_IF_NULL(if_gatt);
+	VERIFY_CLIENT_IF(2, client_if);
+	VERIFY_ADDR_ARG(3, &bd_addr);
+	VERIFY_SRVC_ID(4, &srvc_id);
+	VERIFY_CHAR_ID(5, &char_id);
+
+	EXEC(if_gatt->client->deregister_for_notification, client_if, &bd_addr,
+							&srvc_id, &char_id);
 }
 
 /* read_remote_rssi */
 
 static void read_remote_rssi_p(int argc, const char **argv)
 {
+	int client_if;
+	bt_bdaddr_t bd_addr;
+
+	RETURN_IF_NULL(if_gatt);
+	VERIFY_CLIENT_IF(2, client_if);
+	VERIFY_ADDR_ARG(3, &bd_addr);
+
+	EXEC(if_gatt->client->read_remote_rssi, client_if, &bd_addr);
 }
 
 /* get_device_type */
 
 static void get_device_type_p(int argc, const char **argv)
 {
+	bt_bdaddr_t bd_addr;
+	int dev_type;
+
+	RETURN_IF_NULL(if_gatt);
+	VERIFY_ADDR_ARG(2, &bd_addr);
+
+	dev_type = if_gatt->client->get_device_type(&bd_addr);
+	haltest_info("%s: %d\n", "get_device_type", dev_type);
 }
 
 /* test_command */
 
 static void test_command_p(int argc, const char **argv)
 {
+	int command;
+	int i;
+	bt_bdaddr_t bd_addr;
+	bt_uuid_t uuid;
+	btgatt_test_params_t params = {
+		.bda1 = &bd_addr,
+		.uuid1 = &uuid
+	};
+	uint16_t *u = &params.u1;
+
+	RETURN_IF_NULL(if_gatt);
+
+	/* command */
+	if (argc <= 2) {
+		haltest_error("No command specified\n");
+		return;
+	}
+	command = atoi(argv[2]);
+
+	VERIFY_ADDR_ARG(3, &bd_addr);
+	VERIFY_UUID(4, &uuid);
+
+	for (i = 5; i < argc; i++)
+		*u++ = atoi(argv[i]);
+
+	EXEC(if_gatt->client->test_command, command, &params);
 }
 
 static struct method client_methods[] = {
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH 07/10] android/client: Add GATT complex type parsing
From: Jerzy Kasenberg @ 2013-10-31 10:45 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Jerzy Kasenberg
In-Reply-To: <1383216315-30627-1-git-send-email-jerzy.kasenberg@tieto.com>

This patch adds code to parse: UUID, service ID, characteristic ID,
and general hex string filed.
---
 android/client/if-gatt.c |  119 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 119 insertions(+)

diff --git a/android/client/if-gatt.c b/android/client/if-gatt.c
index 70dbb24..62e0a81 100644
--- a/android/client/if-gatt.c
+++ b/android/client/if-gatt.c
@@ -136,10 +136,79 @@ static char *gatt_uuid_t2str(const bt_uuid_t *uuid, char *buf)
  */
 static void scan_field(const char *str, int len, uint8_t *out, int out_size)
 {
+	int i;
+
+	memset(out, 0, out_size);
+	if (out_size * 2 > len + 1)
+		out_size = (len + 1) / 2;
+
+	for (i = 0; i < out_size && len > 0; ++i) {
+		len -= 2;
+		if (len >= 0)
+			sscanf(str + len, "%02hhx", &out[i]);
+		else
+			sscanf(str, "%1hhx", &out[i]);
+	}
 }
 
+/* Like strchr but with upper limit instead of 0 terminated string */
+static const char *strchrlimit(const char *p, const char *e, int c)
+{
+	while (p < e && *p != (char) c)
+		++p;
+
+	return p < e ? p : NULL;
+}
+
+/*
+ * converts string to uuid
+ * it accepts uuid in following forms:
+ *	123
+ *	0000123
+ *	0000123-0014-1234-0000-000056789abc
+ *	0000123001412340000000056789abc
+ *	123-14-1234-0-56789abc
+ */
 static void gatt_str2bt_uuid_t(const char *str, int len, bt_uuid_t *uuid)
 {
+	int dash_cnt = 0;
+	int dashes[6] = {-1}; /* indexes of '-' or \0 */
+	static uint8_t filed_offset[] = { 16, 12, 10, 8, 6, 0 };
+	const char *p = str;
+	const char *e;
+	int i;
+
+	e = str + ((len >= 0) ? len : (int) strlen(str));
+
+	while (p != NULL && dash_cnt < 5) {
+		const char *f = strchrlimit(p, e, '-');
+
+		if (f != NULL)
+			dashes[++dash_cnt] = f++ - str;
+		p = f;
+	}
+
+	/* get index of \0 to dashes table */
+	if (dash_cnt < 5)
+		dashes[++dash_cnt] = e - str;
+
+	memcpy(uuid, GATT_BASE_UUID, sizeof(bt_uuid_t));
+
+	/* whole uuid in one string without dashes */
+	if (dash_cnt == 1 && dashes[1] > 8) {
+		if (dashes[1] > 32)
+			dashes[1] = 32;
+		scan_field(str, dashes[1],
+				&uuid->uu[16 - (dashes[1] + 1) / 2],
+				(dashes[1] + 1) / 2);
+	} else {
+		for (i = 0; i < dash_cnt; ++i) {
+			scan_field(str + dashes[i] + 1,
+					dashes[i + 1] - dashes[i] - 1,
+					&uuid->uu[filed_offset[i + 1]],
+					filed_offset[i] - filed_offset[i + 1]);
+		}
+	}
 }
 
 /* char_id formating function */
@@ -155,6 +224,26 @@ static char *btgatt_char_id_t2str(const btgatt_char_id_t *char_id, char *buf)
 /* Parse btgatt_char_id_t */
 static void str2btgatt_char_id_t(const char *buf, btgatt_char_id_t *char_id)
 {
+	const char *e;
+
+	memcpy(&char_id->uuid, &GATT_BASE_UUID, sizeof(bt_uuid_t));
+	char_id->inst_id = 0;
+
+	if (*buf == '{')
+		buf++;
+	e = strpbrk(buf, " ,}");
+	if (e == NULL)
+		e = buf + strlen(buf);
+
+	gatt_str2bt_uuid_t(buf, e - buf, &char_id->uuid);
+	if (*e == ',') {
+		buf = e + 1;
+		e = strpbrk(buf, " ,}");
+		if (e == NULL)
+			e = buf + strlen(buf);
+		if (buf < e)
+			char_id->inst_id = atoi(buf);
+	}
 }
 
 /* service_id formating function */
@@ -170,6 +259,36 @@ static char *btgatt_srvc_id_t2str(const btgatt_srvc_id_t *srvc_id, char *buf)
 /* Parse btgatt_srvc_id_t */
 static void str2btgatt_srvc_id_t(const char *buf, btgatt_srvc_id_t *srvc_id)
 {
+	const char *e;
+
+	memcpy(&srvc_id->id.uuid, &GATT_BASE_UUID, sizeof(bt_uuid_t));
+	srvc_id->id.inst_id = 0;
+	srvc_id->is_primary = 1;
+
+	if (*buf == '{')
+		buf++;
+	e = strpbrk(buf, " ,}");
+	if (e == NULL)
+		e = buf + strlen(buf);
+
+	gatt_str2bt_uuid_t(buf, e - buf, &srvc_id->id.uuid);
+	if (*e == ',') {
+		buf = e + 1;
+		e = strpbrk(buf, " ,}");
+		if (e == NULL)
+			e = buf + strlen(buf);
+		if (buf < e)
+			srvc_id->id.inst_id = atoi(buf);
+	}
+
+	if (*e == ',') {
+		buf = e + 1;
+		e = strpbrk(buf, " ,}");
+		if (e == NULL)
+			e = buf + strlen(buf);
+		if (buf < e)
+			srvc_id->is_primary = atoi(buf);
+	}
 }
 
 /* Converts array of uint8_t to string representation */
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH 08/10] android/client: Add tab completion to GATT client
From: Jerzy Kasenberg @ 2013-10-31 10:45 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Jerzy Kasenberg
In-Reply-To: <1383216315-30627-1-git-send-email-jerzy.kasenberg@tieto.com>

This patch adds tab completion to GATT client methods.
---
 android/client/if-gatt.c |  209 +++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 187 insertions(+), 22 deletions(-)

diff --git a/android/client/if-gatt.c b/android/client/if-gatt.c
index 62e0a81..3fe55e8 100644
--- a/android/client/if-gatt.c
+++ b/android/client/if-gatt.c
@@ -356,12 +356,20 @@ static char *btgatt_read_params_t2str(const btgatt_read_params_t *data,
 
 /* BT-GATT Client callbacks. */
 
+/* Cache client_if and conn_id for tab completion */
+static char client_if_str[20];
+static char conn_id_str[20];
+/* Cache address for tab completion */
+static char last_addr[MAX_ADDR_STR_LEN];
+
 /* Callback invoked in response to register_client */
 static void gattc_register_client_cb(int status, int client_if,
 							bt_uuid_t *app_uuid)
 {
 	char buf[MAX_UUID_STR_LEN];
 
+	snprintf(client_if_str, sizeof(client_if_str), "%d", client_if);
+
 	haltest_info("%s: status=%d client_if=%d app_uuid=%s\n", __func__,
 						status, client_if,
 						gatt_uuid_t2str(app_uuid, buf));
@@ -380,11 +388,9 @@ static void gattc_scan_result_cb(bt_bdaddr_t *bda, int rssi, uint8_t *adv_data)
 static void gattc_connect_cb(int conn_id, int status, int client_if,
 							bt_bdaddr_t *bda)
 {
-	char buf[MAX_ADDR_STR_LEN];
-
 	haltest_info("%s: conn_id=%d status=%d, client_if=%d bda=%s\n",
 					__func__, conn_id, status, client_if,
-					bt_bdaddr_t2str(bda, buf));
+					bt_bdaddr_t2str(bda, last_addr));
 }
 
 /* Callback invoked in response to close */
@@ -740,6 +746,15 @@ static void register_client_p(int argc, const char **argv)
 
 /* unregister_client */
 
+static void unregister_client_c(int argc, const char **argv,
+					enum_func *enum_func, void **user)
+{
+	if (argc == 3) {
+		*user = client_if_str;
+		*enum_func = enum_one_string;
+	}
+}
+
 static void unregister_client_p(int argc, const char **argv)
 {
 	int client_if;
@@ -752,6 +767,9 @@ static void unregister_client_p(int argc, const char **argv)
 
 /* scan */
 
+/* Same completion as unregister for now, start stop is not auto completed */
+#define scan_c unregister_client_c
+
 static void scan_p(int argc, const char **argv)
 {
 	int client_if;
@@ -770,6 +788,18 @@ static void scan_p(int argc, const char **argv)
 
 /* connect */
 
+static void connect_c(int argc, const char **argv, enum_func *enum_func,
+								void **user)
+{
+	if (argc == 3) {
+		*user = client_if_str;
+		*enum_func = enum_one_string;
+	} else if (argc == 4) {
+		*user = NULL;
+		*enum_func = enum_devices;
+	}
+}
+
 static void connect_p(int argc, const char **argv)
 {
 	int client_if;
@@ -789,6 +819,21 @@ static void connect_p(int argc, const char **argv)
 
 /* disconnect */
 
+static void disconnect_c(int argc, const char **argv, enum_func *enum_func,
+								void **user)
+{
+	if (argc == 3) {
+		*user = client_if_str;
+		*enum_func = enum_one_string;
+	} else if (argc == 4) {
+		*user = last_addr;
+		*enum_func = enum_one_string;
+	} else if (argc == 5) {
+		*user = conn_id_str;
+		*enum_func = enum_one_string;
+	}
+}
+
 static void disconnect_p(int argc, const char **argv)
 {
 	int client_if;
@@ -805,6 +850,17 @@ static void disconnect_p(int argc, const char **argv)
 
 /* refresh */
 
+static void refresh_c(int argc, const char **argv, enum_func *enum_func,
+								void **user)
+{
+	if (argc == 3) {
+		*user = client_if_str;
+		*enum_func = enum_one_string;
+	} else if (argc == 4) {
+		*enum_func = enum_devices;
+	}
+}
+
 static void refresh_p(int argc, const char **argv)
 {
 	int client_if;
@@ -819,6 +875,15 @@ static void refresh_p(int argc, const char **argv)
 
 /* search_service */
 
+static void search_service_c(int argc, const char **argv, enum_func *enum_func,
+								void **user)
+{
+	if (argc == 3) {
+		*user = conn_id_str;
+		*enum_func = enum_one_string;
+	}
+}
+
 static void search_service_p(int argc, const char **argv)
 {
 	int conn_id;
@@ -839,6 +904,15 @@ static void search_service_p(int argc, const char **argv)
 
 /* get_included_service */
 
+static void get_included_service_c(int argc, const char **argv,
+					enum_func *enum_func, void **user)
+{
+	if (argc == 3) {
+		*user = conn_id_str;
+		*enum_func = enum_one_string;
+	}
+}
+
 static void get_included_service_p(int argc, const char **argv)
 {
 	int conn_id;
@@ -853,6 +927,9 @@ static void get_included_service_p(int argc, const char **argv)
 
 /* get_characteristic */
 
+/* Same completion as get_included_service_c */
+#define get_characteristic_c get_included_service_c
+
 static void get_characteristic_p(int argc, const char **argv)
 {
 	int conn_id;
@@ -867,6 +944,9 @@ static void get_characteristic_p(int argc, const char **argv)
 
 /* get_descriptor */
 
+/* Same completion as get_included_service_c */
+#define get_descriptor_c get_included_service_c
+
 static void get_descriptor_p(int argc, const char **argv)
 {
 	int conn_id;
@@ -884,6 +964,9 @@ static void get_descriptor_p(int argc, const char **argv)
 
 /* read_characteristic */
 
+/* Same completion as get_included_service_c */
+#define read_characteristic_c get_included_service_c
+
 static void read_characteristic_p(int argc, const char **argv)
 {
 	int conn_id;
@@ -906,6 +989,24 @@ static void read_characteristic_p(int argc, const char **argv)
 
 /* write_characteristic */
 
+static void write_characteristic_c(int argc, const char **argv,
+					enum_func *enum_func, void **user)
+{
+	/*
+	 * This should be from tGATT_WRITE_TYPE but it's burried
+	 * inside bluedroid guts
+	 */
+	static const char *wrtypes[] = { "1", "2", "3", NULL };
+
+	if (argc == 3) {
+		*user = conn_id_str;
+		*enum_func = enum_one_string;
+	} else if (argc == 6) {
+		*user = wrtypes;
+		*enum_func = enum_strings;
+	}
+}
+
 static void write_characteristic_p(int argc, const char **argv)
 {
 	int conn_id;
@@ -950,6 +1051,9 @@ static void write_characteristic_p(int argc, const char **argv)
 
 /* read_descriptor */
 
+/* Same completion as get_included_service_c */
+#define read_descriptor_c get_included_service_c
+
 static void read_descriptor_p(int argc, const char **argv)
 {
 	int conn_id;
@@ -974,6 +1078,24 @@ static void read_descriptor_p(int argc, const char **argv)
 
 /* write_descriptor */
 
+static void write_descriptor_c(int argc, const char **argv,
+					enum_func *enum_func, void **user)
+{
+	/*
+	 * This should be from tGATT_WRITE_TYPE but it's burried
+	 * inside bluedroid guts
+	 */
+	static const char *wrtypes[] = { "1", "2", "3", NULL };
+
+	if (argc == 3) {
+		*user = conn_id_str;
+		*enum_func = enum_one_string;
+	} else if (argc == 7) {
+		*user = wrtypes;
+		*enum_func = enum_strings;
+	}
+}
+
 static void write_descriptor_p(int argc, const char **argv)
 {
 	int conn_id;
@@ -1020,6 +1142,9 @@ static void write_descriptor_p(int argc, const char **argv)
 
 /* execute_write */
 
+/* Same completion as search_service */
+#define execute_write_c search_service_c
+
 static void execute_write_p(int argc, const char **argv)
 {
 	int conn_id;
@@ -1040,6 +1165,18 @@ static void execute_write_p(int argc, const char **argv)
 
 /* register_for_notification */
 
+static void register_for_notification_c(int argc, const char **argv,
+					enum_func *enum_func, void **user)
+{
+	if (argc == 3) {
+		*user = client_if_str;
+		*enum_func = enum_one_string;
+	} else if (argc == 4) {
+		*user = last_addr;
+		*enum_func = enum_one_string;
+	}
+}
+
 static void register_for_notification_p(int argc, const char **argv)
 {
 	int client_if;
@@ -1059,6 +1196,9 @@ static void register_for_notification_p(int argc, const char **argv)
 
 /* deregister_for_notification */
 
+/* Same completion as search_service */
+#define deregister_for_notification_c register_for_notification_c
+
 static void deregister_for_notification_p(int argc, const char **argv)
 {
 	int client_if;
@@ -1078,6 +1218,17 @@ static void deregister_for_notification_p(int argc, const char **argv)
 
 /* read_remote_rssi */
 
+static void read_remote_rssi_c(int argc, const char **argv,
+					enum_func *enum_func, void **user)
+{
+	if (argc == 3) {
+		*user = client_if_str;
+		*enum_func = enum_one_string;
+	} else if (argc == 4) {
+		*enum_func = enum_devices;
+	}
+}
+
 static void read_remote_rssi_p(int argc, const char **argv)
 {
 	int client_if;
@@ -1092,6 +1243,13 @@ static void read_remote_rssi_p(int argc, const char **argv)
 
 /* get_device_type */
 
+static void get_device_type_c(int argc, const char **argv, enum_func *enum_func,
+								void **user)
+{
+	if (argc == 3)
+		*enum_func = enum_devices;
+}
+
 static void get_device_type_p(int argc, const char **argv)
 {
 	bt_bdaddr_t bd_addr;
@@ -1106,6 +1264,13 @@ static void get_device_type_p(int argc, const char **argv)
 
 /* test_command */
 
+static void test_command_c(int argc, const char **argv, enum_func *enum_func,
+								void **user)
+{
+	if (argc == 4)
+		*enum_func = enum_devices;
+}
+
 static void test_command_p(int argc, const char **argv)
 {
 	int command;
@@ -1138,31 +1303,31 @@ static void test_command_p(int argc, const char **argv)
 
 static struct method client_methods[] = {
 	STD_METHODH(register_client, "[<uuid>]"),
-	STD_METHODH(unregister_client, "<client_if>"),
-	STD_METHODH(scan, "<client_if> [1|0]"),
-	STD_METHODH(connect, "<client_if> <addr> [<is_direct>]"),
-	STD_METHODH(disconnect, "<client_if> <addr> <conn_id>"),
-	STD_METHODH(refresh, "<client_if> <addr>"),
-	STD_METHODH(search_service, "<conn_id> [<uuid>]"),
-	STD_METHODH(get_included_service, "<conn_id> <srvc_id>"),
-	STD_METHODH(get_characteristic, "<conn_id> <srvc_id>"),
-	STD_METHODH(get_descriptor, "<conn_id> <srvc_id> <char_id>"),
-	STD_METHODH(read_characteristic,
+	STD_METHODCH(unregister_client, "<client_if>"),
+	STD_METHODCH(scan, "<client_if> [1|0]"),
+	STD_METHODCH(connect, "<client_if> <addr> [<is_direct>]"),
+	STD_METHODCH(disconnect, "<client_if> <addr> <conn_id>"),
+	STD_METHODCH(refresh, "<client_if> <addr>"),
+	STD_METHODCH(search_service, "<conn_id> [<uuid>]"),
+	STD_METHODCH(get_included_service, "<conn_id> <srvc_id>"),
+	STD_METHODCH(get_characteristic, "<conn_id> <srvc_id>"),
+	STD_METHODCH(get_descriptor, "<conn_id> <srvc_id> <char_id>"),
+	STD_METHODCH(read_characteristic,
 			"<conn_id> <srvc_id> <char_id> [<auth_req>]"),
-	STD_METHODH(write_characteristic,
+	STD_METHODCH(write_characteristic,
 			"<conn_id> <srvc_id> <char_id> <write_type> <hex_value> [<auth_req>]"),
-	STD_METHODH(read_descriptor,
+	STD_METHODCH(read_descriptor,
 			"<conn_id> <srvc_id> <char_id> <descr_id> [<auth_req>]"),
-	STD_METHODH(write_descriptor,
+	STD_METHODCH(write_descriptor,
 			"<conn_id> <srvc_id> <char_id> <descr_id> <write_type> <hex_value> [<auth_req>]"),
-	STD_METHODH(execute_write, "<conn_id> <execute>"),
-	STD_METHODH(register_for_notification,
+	STD_METHODCH(execute_write, "<conn_id> <execute>"),
+	STD_METHODCH(register_for_notification,
 			"<client_if> <addr> <srvc_id> <char_id>"),
-	STD_METHODH(deregister_for_notification,
+	STD_METHODCH(deregister_for_notification,
 			"<client_if> <addr> <srvc_id> <char_id>"),
-	STD_METHODH(read_remote_rssi, "<client_if> <addr>"),
-	STD_METHODH(get_device_type, "<addr>"),
-	STD_METHODH(test_command,
+	STD_METHODCH(read_remote_rssi, "<client_if> <addr>"),
+	STD_METHODCH(get_device_type, "<addr>"),
+	STD_METHODCH(test_command,
 			"<cmd> <addr> <uuid> [u1] [u2] [u3] [u4] [u5]"),
 	END_METHOD
 };
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH 09/10] android/client: Add GATT server callbacks code
From: Jerzy Kasenberg @ 2013-10-31 10:45 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Jerzy Kasenberg
In-Reply-To: <1383216315-30627-1-git-send-email-jerzy.kasenberg@tieto.com>

This patch adds callbacks code for GATT server interface.
---
 android/client/if-gatt.c |   49 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 49 insertions(+)

diff --git a/android/client/if-gatt.c b/android/client/if-gatt.c
index 3fe55e8..a262b90 100644
--- a/android/client/if-gatt.c
+++ b/android/client/if-gatt.c
@@ -583,6 +583,10 @@ static const btgatt_client_callbacks_t btgatt_client_callbacks = {
 static void gatts_register_server_cb(int status, int server_if,
 							bt_uuid_t *app_uuid)
 {
+	char buf[MAX_UUID_STR_LEN];
+
+	haltest_info("%s: status=%d server_if=%d app_uuid=%s\n", __func__,
+			status, server_if, gatt_uuid_t2str(app_uuid, buf));
 }
 
 /*
@@ -592,12 +596,20 @@ static void gatts_register_server_cb(int status, int server_if,
 static void gatts_connection_cb(int conn_id, int server_if, int connected,
 							bt_bdaddr_t *bda)
 {
+	haltest_info("%s: conn_id=%d server_if=%d connected=%d bda=%s\n",
+					__func__, conn_id, server_if, connected,
+					bt_bdaddr_t2str(bda, last_addr));
 }
 
 /* Callback invoked in response to create_service */
 static void gatts_service_added_cb(int status, int server_if,
 				btgatt_srvc_id_t *srvc_id, int srvc_handle)
 {
+	char buf[MAX_SRVC_ID_STR_LEN];
+
+	haltest_info("%s: status=%d server_if=%d srvc_id=%s handle=%x\n",
+			__func__, status, server_if,
+			btgatt_srvc_id_t2str(srvc_id, buf), srvc_handle);
 }
 
 /* Callback indicating that an included service has been added to a service */
@@ -605,6 +617,9 @@ static void gatts_included_service_added_cb(int status, int server_if,
 							int srvc_handle,
 							int incl_srvc_handle)
 {
+	haltest_info("%s: status=%d server_if=%d srvc_handle=%x inc_srvc_handle=%x\n",
+						__func__, status, server_if,
+						srvc_handle, incl_srvc_handle);
 }
 
 /* Callback invoked when a characteristic has been added to a service */
@@ -613,6 +628,11 @@ static void gatts_characteristic_added_cb(int status, int server_if,
 								int srvc_handle,
 								int char_handle)
 {
+	char buf[MAX_SRVC_ID_STR_LEN];
+
+	haltest_info("%s: status=%d server_if=%d uuid=%s srvc_handle=%x char_handle=%x\n",
+			__func__, status, server_if, gatt_uuid_t2str(uuid, buf),
+			srvc_handle, char_handle);
 }
 
 /* Callback invoked when a descriptor has been added to a characteristic */
@@ -620,21 +640,32 @@ static void gatts_descriptor_added_cb(int status, int server_if,
 					bt_uuid_t *uuid, int srvc_handle,
 							int descr_handle)
 {
+	char buf[MAX_SRVC_ID_STR_LEN];
+
+	haltest_info("%s: status=%d server_if=%d uuid=%s srvc_handle=%x descr_handle=%x\n",
+			__func__, status, server_if, gatt_uuid_t2str(uuid, buf),
+			srvc_handle, descr_handle);
 }
 
 /* Callback invoked in response to start_service */
 static void gatts_service_started_cb(int status, int server_if, int srvc_handle)
 {
+	haltest_info("%s: status=%d server_if=%d srvc_handle=%x\n",
+				__func__, status, server_if, srvc_handle);
 }
 
 /* Callback invoked in response to stop_service */
 static void gatts_service_stopped_cb(int status, int server_if, int srvc_handle)
 {
+	haltest_info("%s: status=%d server_if=%d srvc_handle=%x\n",
+				__func__, status, server_if, srvc_handle);
 }
 
 /* Callback triggered when a service has been deleted */
 static void gatts_service_deleted_cb(int status, int server_if, int srvc_handle)
 {
+	haltest_info("%s: status=%d server_if=%d srvc_handle=%x\n",
+				__func__, status, server_if, srvc_handle);
 }
 
 /*
@@ -645,6 +676,11 @@ static void gatts_request_read_cb(int conn_id, int trans_id, bt_bdaddr_t *bda,
 						int attr_handle, int offset,
 						bool is_long)
 {
+	char buf[MAX_ADDR_STR_LEN];
+
+	haltest_info("%s: conn_id=%d trans_id=%d bda=%s attr_handle=%x offset=%d is_long=%d\n",
+			__func__, conn_id, trans_id, bt_bdaddr_t2str(bda, buf),
+			attr_handle, offset, is_long);
 }
 
 /*
@@ -656,12 +692,24 @@ static void gatts_request_write_cb(int conn_id, int trans_id, bt_bdaddr_t *bda,
 					bool need_rsp, bool is_prep,
 					uint8_t *value)
 {
+	char buf[MAX_ADDR_STR_LEN];
+	char valbuf[100];
+
+	haltest_info("%s: conn_id=%d trans_id=%d bda=%s attr_handle=%x offset=%d length=%d need_rsp=%d is_prep=%d value=%s\n",
+			__func__, conn_id, trans_id, bt_bdaddr_t2str(bda, buf),
+			attr_handle, offset, length, need_rsp, is_prep,
+			array2str(value, length, valbuf, sizeof(valbuf)));
 }
 
 /* Callback invoked when a previously prepared write is to be executed */
 static void gatts_request_exec_write_cb(int conn_id, int trans_id,
 					bt_bdaddr_t *bda, int exec_write)
 {
+	char buf[MAX_ADDR_STR_LEN];
+
+	haltest_info("%s: conn_id=%d trans_id=%d bda=%s exec_write=%d\n",
+			__func__, conn_id, trans_id, bt_bdaddr_t2str(bda, buf),
+			exec_write);
 }
 
 /*
@@ -670,6 +718,7 @@ static void gatts_request_exec_write_cb(int conn_id, int trans_id,
  */
 static void gatts_response_confirmation_cb(int status, int handle)
 {
+	haltest_info("%s: status=%d handle=%x\n", __func__, status, handle);
 }
 
 static const btgatt_server_callbacks_t btgatt_server_callbacks = {
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH 10/10] android/client: Add GATT server methods
From: Jerzy Kasenberg @ 2013-10-31 10:45 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Jerzy Kasenberg
In-Reply-To: <1383216315-30627-1-git-send-email-jerzy.kasenberg@tieto.com>

This patch implements GATT server method calls.
---
 android/client/if-gatt.c |  256 ++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 246 insertions(+), 10 deletions(-)

diff --git a/android/client/if-gatt.c b/android/client/if-gatt.c
index a262b90..e90e58b 100644
--- a/android/client/if-gatt.c
+++ b/android/client/if-gatt.c
@@ -579,6 +579,9 @@ static const btgatt_client_callbacks_t btgatt_client_callbacks = {
 
 /* BT-GATT Server callbacks */
 
+/* Cache server_if and conn_id for tab completion */
+static char server_if_str[20];
+
 /* Callback invoked in response to register_server */
 static void gatts_register_server_cb(int status, int server_if,
 							bt_uuid_t *app_uuid)
@@ -599,6 +602,7 @@ static void gatts_connection_cb(int conn_id, int server_if, int connected,
 	haltest_info("%s: conn_id=%d server_if=%d connected=%d bda=%s\n",
 					__func__, conn_id, server_if, connected,
 					bt_bdaddr_t2str(bda, last_addr));
+	snprintf(conn_id_str, sizeof(conn_id_str), "%d", conn_id);
 }
 
 /* Callback invoked in response to create_service */
@@ -607,6 +611,8 @@ static void gatts_service_added_cb(int status, int server_if,
 {
 	char buf[MAX_SRVC_ID_STR_LEN];
 
+	snprintf(server_if_str, sizeof(server_if_str), "%d", server_if);
+
 	haltest_info("%s: status=%d server_if=%d srvc_id=%s handle=%x\n",
 			__func__, status, server_if,
 			btgatt_srvc_id_t2str(srvc_id, buf), srvc_handle);
@@ -1392,78 +1398,308 @@ const struct interface gatt_client_if = {
 
 static void gatts_register_server_p(int argc, const char *argv[])
 {
+	bt_uuid_t uuid;
+
+	RETURN_IF_NULL(if_gatt);
+
+	/* uuid */
+	if (argc <= 2)
+		gatt_str2bt_uuid_t("bed4babe", -1, &uuid);
+	else
+		gatt_str2bt_uuid_t(argv[2], -1, &uuid);
+
+	EXEC(if_gatt->server->register_server, &uuid);
 }
 
 /* unregister_server */
 
+static void gatts_unregister_server_c(int argc, const char **argv,
+					enum_func *enum_func, void **user)
+{
+	if (argc == 3) {
+		*user = server_if_str;
+		*enum_func = enum_one_string;
+	}
+}
+
 static void gatts_unregister_server_p(int argc, const char *argv[])
 {
+	int server_if;
+
+	RETURN_IF_NULL(if_gatt);
+	VERIFY_SERVER_IF(2, server_if);
+
+	EXEC(if_gatt->server->unregister_server, server_if);
 }
 
 /* connect */
 
+static void gatts_connect_c(int argc, const char **argv, enum_func *enum_func,
+								void **user)
+{
+	if (argc == 3) {
+		*user = server_if_str;
+		*enum_func = enum_one_string;
+	} else if (argc == 4) {
+		*user = NULL;
+		*enum_func = enum_devices;
+	}
+}
+
 static void gatts_connect_p(int argc, const char *argv[])
 {
+	int server_if;
+	bt_bdaddr_t bd_addr;
+	int is_direct = 1;
+
+	RETURN_IF_NULL(if_gatt);
+	VERIFY_SERVER_IF(2, server_if);
+	VERIFY_ADDR_ARG(3, &bd_addr);
+
+	/* is_direct */
+	if (argc > 4)
+		is_direct = atoi(argv[4]);
+
+	EXEC(if_gatt->server->connect, server_if, &bd_addr, is_direct);
 }
 
 /* disconnect */
 
+static void gatts_disconnect_c(int argc, const char **argv,
+					enum_func *enum_func, void **user)
+{
+	if (argc == 3) {
+		*user = server_if_str;
+		*enum_func = enum_one_string;
+	} else if (argc == 4) {
+		*user = last_addr;
+		*enum_func = enum_one_string;
+	} else if (argc == 5) {
+		*user = conn_id_str;
+		*enum_func = enum_one_string;
+	}
+}
+
 static void gatts_disconnect_p(int argc, const char *argv[])
 {
+	int server_if;
+	bt_bdaddr_t bd_addr;
+	int conn_id;
+
+	RETURN_IF_NULL(if_gatt);
+	VERIFY_SERVER_IF(2, server_if);
+	VERIFY_ADDR_ARG(3, &bd_addr);
+	VERIFY_CONN_ID(4, conn_id);
+
+	EXEC(if_gatt->server->disconnect, server_if, &bd_addr, conn_id);
 }
 
 /* add_service */
 
+/* Same completion as gatts_unregister_server_c */
+#define gatts_add_service_c gatts_unregister_server_c
+
 static void gatts_add_service_p(int argc, const char *argv[])
 {
+	int server_if;
+	btgatt_srvc_id_t srvc_id;
+	int num_handles;
+
+	RETURN_IF_NULL(if_gatt);
+	VERIFY_SERVER_IF(2, server_if);
+	VERIFY_SRVC_ID(3, &srvc_id);
+
+	/* num handles */
+	if (argc <= 4) {
+		haltest_error("No num_handles specified\n");
+		return;
+	}
+	num_handles = atoi(argv[4]);
+
+	EXEC(if_gatt->server->add_service, server_if, &srvc_id, num_handles);
 }
 
 /* add_included_service */
 
+/* Same completion as gatts_unregister_server_c */
+#define gatts_add_included_service_c gatts_unregister_server_c
+
 static void gatts_add_included_service_p(int argc, const char *argv[])
 {
+	int server_if;
+	int service_handle;
+	int included_handle;
+
+	RETURN_IF_NULL(if_gatt);
+	VERIFY_SERVER_IF(2, server_if);
+	VERIFY_SERVICE_HANDLE(3, service_handle);
+	VERIFY_HANDLE(4, included_handle);
+
+	EXEC(if_gatt->server->add_included_service, server_if, service_handle,
+							included_handle);
 }
 
 /* add_characteristic */
 
+/* Same completion as gatts_unregister_server_c */
+#define gatts_add_characteristic_c gatts_unregister_server_c
+
 static void gatts_add_characteristic_p(int argc, const char *argv[])
 {
+	int server_if;
+	int service_handle;
+	int properties;
+	int permissions;
+	bt_uuid_t uuid;
+
+	RETURN_IF_NULL(if_gatt);
+	VERIFY_SERVER_IF(2, server_if);
+	VERIFY_SERVICE_HANDLE(3, service_handle);
+	VERIFY_UUID(4, &uuid);
+
+	/* properties */
+	if (argc <= 5) {
+		haltest_error("No properties specified\n");
+		return;
+	}
+	properties = atoi(argv[5]);
+
+	/* permissions */
+	if (argc <= 6) {
+		haltest_error("No permissions specified\n");
+		return;
+	}
+	permissions = atoi(argv[6]);
+
+	EXEC(if_gatt->server->add_characteristic, server_if, service_handle,
+						&uuid, properties, permissions);
 }
 
 /* add_descriptor */
 
+/* Same completion as gatts_unregister_server_c */
+#define gatts_add_descriptor_c gatts_unregister_server_c
+
 static void gatts_add_descriptor_p(int argc, const char *argv[])
 {
+	int server_if;
+	int service_handle;
+	int permissions;
+	bt_uuid_t uuid;
+
+	RETURN_IF_NULL(if_gatt);
+	VERIFY_SERVER_IF(2, server_if);
+	VERIFY_SERVICE_HANDLE(3, service_handle);
+	VERIFY_UUID(4, &uuid);
+
+	/* permissions */
+	if (argc <= 5) {
+		haltest_error("No permissions specified\n");
+		return;
+	}
+	permissions = atoi(argv[5]);
+
+	EXEC(if_gatt->server->add_descriptor, server_if, service_handle, &uuid,
+								permissions);
 }
 
 /* start_service */
 
+/* Same completion as gatts_unregister_server_c */
+#define gatts_start_service_c gatts_unregister_server_c
+
 static void gatts_start_service_p(int argc, const char *argv[])
 {
+	int server_if;
+	int service_handle;
+	int transport;
+
+	RETURN_IF_NULL(if_gatt);
+	VERIFY_SERVER_IF(2, server_if);
+	VERIFY_SERVICE_HANDLE(3, service_handle);
+
+	/* transport */
+	if (argc <= 4) {
+		haltest_error("No transport specified\n");
+		return;
+	}
+	transport = atoi(argv[4]);
+
+	EXEC(if_gatt->server->start_service, server_if, service_handle,
+								transport);
 }
 
 /* stop_service */
 
+/* Same completion as gatts_unregister_server_c */
+#define gatts_stop_service_c gatts_unregister_server_c
+
 static void gatts_stop_service_p(int argc, const char *argv[])
 {
+	int server_if;
+	int service_handle;
+
+	RETURN_IF_NULL(if_gatt);
+	VERIFY_SERVER_IF(2, server_if);
+	VERIFY_SERVICE_HANDLE(3, service_handle);
+
+	EXEC(if_gatt->server->stop_service, server_if, service_handle);
 }
 
 /* delete_service */
 
+/* Same completion as gatts_unregister_server_c */
+#define gatts_delete_service_c gatts_unregister_server_c
+
 static void gatts_delete_service_p(int argc, const char *argv[])
 {
+	int server_if;
+	int service_handle;
+
+	RETURN_IF_NULL(if_gatt);
+	VERIFY_SERVER_IF(2, server_if);
+	VERIFY_SERVICE_HANDLE(3, service_handle);
+
+	EXEC(if_gatt->server->delete_service, server_if, service_handle);
 }
 
 /* send_indication */
 
 static void gatts_send_indication_p(int argc, const char *argv[])
 {
+	int server_if;
+	int attr_handle;
+	int conn_id;
+	int confirm;
+	char data[200];
+	int len = 0;
+
+	RETURN_IF_NULL(if_gatt);
+	VERIFY_SERVER_IF(2, server_if);
+	VERIFY_HANDLE(3, attr_handle);
+	VERIFY_CONN_ID(4, conn_id);
+
+	/* confirm */
+	if (argc <= 5) {
+		haltest_error("No transport specified\n");
+		return;
+	}
+	confirm = atoi(argv[5]);
+
+	if (argc > 6) {
+		len = strlen(argv[6]);
+		scan_field(argv[6], len, (uint8_t *) data, sizeof(data));
+	}
+
+	EXEC(if_gatt->server->send_indication, server_if, attr_handle, conn_id,
+							len, confirm, data);
 }
 
 /* send_response */
 
 static void gatts_send_response_p(int argc, const char *argv[])
 {
+	haltest_warn("%s is not implemented yet\n", __func__);
 }
 
 #define GATTS_METHODH(n, h) METHOD(#n, gatts_##n##_p, NULL, h)
@@ -1471,19 +1707,19 @@ static void gatts_send_response_p(int argc, const char *argv[])
 
 static struct method server_methods[] = {
 	GATTS_METHODH(register_server, "[<uuid>]"),
-	GATTS_METHODH(unregister_server, "<server_if>"),
-	GATTS_METHODH(connect, "<server_if> <addr> [<is_direct>]"),
-	GATTS_METHODH(disconnect, "<server_if> <addr> <conn_id>"),
-	GATTS_METHODH(add_service, "<server_if> <srvc_id> <num_handles>"),
-	GATTS_METHODH(add_included_service,
+	GATTS_METHODCH(unregister_server, "<server_if>"),
+	GATTS_METHODCH(connect, "<server_if> <addr> [<is_direct>]"),
+	GATTS_METHODCH(disconnect, "<server_if> <addr> <conn_id>"),
+	GATTS_METHODCH(add_service, "<server_if> <srvc_id> <num_handles>"),
+	GATTS_METHODCH(add_included_service,
 			"<server_if> <service_handle> <included_handle>"),
-	GATTS_METHODH(add_characteristic,
+	GATTS_METHODCH(add_characteristic,
 		"<server_if> <service_handle> <uuid> <properites> <permissions>"),
-	GATTS_METHODH(add_descriptor, "<server_if> <uuid> <permissions>"),
-	GATTS_METHODH(start_service,
+	GATTS_METHODCH(add_descriptor, "<server_if> <uuid> <permissions>"),
+	GATTS_METHODCH(start_service,
 				"<server_if> <service_handle> <transport>"),
-	GATTS_METHODH(stop_service, "<server_if> <service_handle>"),
-	GATTS_METHODH(delete_service, "<server_if> <service_handle>"),
+	GATTS_METHODCH(stop_service, "<server_if> <service_handle>"),
+	GATTS_METHODCH(delete_service, "<server_if> <service_handle>"),
 	GATTS_METHODH(send_indication,
 			"<server_if> <attr_handle> <conn_id> <confirm> [<data>]"),
 	GATTS_METHODH(send_response, "<conn_id> <trans_id> <status>"),
-- 
1.7.9.5


^ permalink raw reply related

* [PATCH] android: Always enable SSP if supported by controller
From: Szymon Janc @ 2013-10-31 10:50 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Szymon Janc

There is no HAL function to enable/disable SSP so always enable it if
supported by controller.
---
 android/adapter.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/android/adapter.c b/android/adapter.c
index a3f9aa6..9f2e019 100644
--- a/android/adapter.c
+++ b/android/adapter.c
@@ -528,6 +528,11 @@ static void read_info_complete(uint8_t status, uint16_t length, const void *para
 	load_link_keys(NULL);
 
 	set_io_capability();
+
+	if ((adapter->supported_settings & MGMT_SETTING_SSP) &&
+			!(adapter->current_settings & MGMT_SETTING_SSP))
+		set_mode(MGMT_OP_SET_SSP, 0x01);
+
 	set_mode(MGMT_OP_SET_PAIRABLE, 0x01);
 
 	return;
-- 
1.8.4.1


^ permalink raw reply related

* [PATCH] android/client: Fix crash in get_profile_interface
From: Jerzy Kasenberg @ 2013-10-31 10:56 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Jerzy Kasenberg

This fixes crash due to uncheck input from user.
---
 android/client/if-bt.c |    7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/android/client/if-bt.c b/android/client/if-bt.c
index a3d6286..9e01d65 100644
--- a/android/client/if-bt.c
+++ b/android/client/if-bt.c
@@ -804,11 +804,16 @@ static void get_profile_interface_c(int argc, const char **argv,
 
 static void get_profile_interface_p(int argc, const char **argv)
 {
-	const char *id = argv[2];
+	const char *id;
 	const void **pif = NULL;
 	const void *dummy = NULL;
 
 	RETURN_IF_NULL(if_bluetooth);
+	if (argc <= 2) {
+		haltest_error("No interface specified\n");
+		return;
+	}
+	id = argv[2];
 
 	if (strcmp(BT_PROFILE_HANDSFREE_ID, id) == 0)
 		pif = (const void **) &if_hf;
-- 
1.7.9.5


^ permalink raw reply related

* Re: [PATCH] android: Always enable SSP if supported by controller
From: Marcel Holtmann @ 2013-10-31 11:35 UTC (permalink / raw)
  To: Szymon Janc; +Cc: linux-bluetooth@vger.kernel.org development
In-Reply-To: <1383216631-28187-1-git-send-email-szymon.janc@tieto.com>

Hi Szymon,

> There is no HAL function to enable/disable SSP so always enable it if
> supported by controller.
> ---
> android/adapter.c | 5 +++++
> 1 file changed, 5 insertions(+)
> 
> diff --git a/android/adapter.c b/android/adapter.c
> index a3f9aa6..9f2e019 100644
> --- a/android/adapter.c
> +++ b/android/adapter.c
> @@ -528,6 +528,11 @@ static void read_info_complete(uint8_t status, uint16_t length, const void *para
> 	load_link_keys(NULL);
> 
> 	set_io_capability();
> +
> +	if ((adapter->supported_settings & MGMT_SETTING_SSP) &&
> +			!(adapter->current_settings & MGMT_SETTING_SSP))
> +		set_mode(MGMT_OP_SET_SSP, 0x01);
> +

	missing_settings = current_settings ^ supported_settings;

	if (missing_setting & MGMT_SETTING_SSP)
		..

Regards

Marcel


^ permalink raw reply

* [PATCH] android/daemon: Fix error setting property
From: Andrei Emeltchenko @ 2013-10-31 11:52 UTC (permalink / raw)
  To: linux-bluetooth

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

Do not return error setting property which is already set. This fixes
bug with set_scan_mode which might return HAL_STATUS_DONE.
---
 android/adapter.c |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/android/adapter.c b/android/adapter.c
index 98b2764..9d4da4e 100644
--- a/android/adapter.c
+++ b/android/adapter.c
@@ -917,7 +917,7 @@ void bt_adapter_handle_cmd(GIOChannel *io, uint8_t opcode, void *buf,
 		break;
 	case HAL_OP_SET_ADAPTER_PROP:
 		status = set_property(buf, len);
-		if (status != HAL_STATUS_SUCCESS)
+		if (status != HAL_STATUS_SUCCESS && status != HAL_STATUS_DONE)
 			goto error;
 
 		break;
-- 
1.7.10.4


^ permalink raw reply related

* Re: [PATCH] android/client: Fix crash in get_profile_interface
From: Johan Hedberg @ 2013-10-31 11:52 UTC (permalink / raw)
  To: Jerzy Kasenberg; +Cc: linux-bluetooth
In-Reply-To: <1383216986-302-1-git-send-email-jerzy.kasenberg@tieto.com>

Hi Jerzy,

On Thu, Oct 31, 2013, Jerzy Kasenberg wrote:
> This fixes crash due to uncheck input from user.
> ---
>  android/client/if-bt.c |    7 ++++++-
>  1 file changed, 6 insertions(+), 1 deletion(-)

Applied (after minor coding style fix to add an empty line after }).
Thanks.

Johan

^ permalink raw reply

* [PATCH 1/2] Bluetooth: Remove debug statement for features complete event
From: Marcel Holtmann @ 2013-10-31 11:54 UTC (permalink / raw)
  To: linux-bluetooth

The complete list of local features are available through debugfs and
so there is no need to add a debug print here.

Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
---
 net/bluetooth/hci_event.c | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 5935f748c0f9..d75d51ff4fdd 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -538,12 +538,6 @@ static void hci_cc_read_local_features(struct hci_dev *hdev,
 
 	if (hdev->features[0][5] & LMP_EDR_3S_ESCO)
 		hdev->esco_type |= (ESCO_2EV5 | ESCO_3EV5);
-
-	BT_DBG("%s features 0x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x", hdev->name,
-	       hdev->features[0][0], hdev->features[0][1],
-	       hdev->features[0][2], hdev->features[0][3],
-	       hdev->features[0][4], hdev->features[0][5],
-	       hdev->features[0][6], hdev->features[0][7]);
 }
 
 static void hci_cc_read_local_ext_features(struct hci_dev *hdev,
-- 
1.8.3.1


^ permalink raw reply related

* [PATCH 2/2] Bluetooth: Store supported commands only during setup procedure
From: Marcel Holtmann @ 2013-10-31 11:54 UTC (permalink / raw)
  To: linux-bluetooth

The list of supported commands of a controller can not change during
its lifetime. So store the list just once during the setup procedure
and not every time the HCI command is executed.

Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
---
 net/bluetooth/hci_event.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index d75d51ff4fdd..4d0f4018df18 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -486,7 +486,10 @@ static void hci_cc_read_local_commands(struct hci_dev *hdev,
 
 	BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
 
-	if (!rp->status)
+	if (rp->status)
+		return;
+
+	if (test_bit(HCI_SETUP, &hdev->dev_flags))
 		memcpy(hdev->commands, rp->commands, sizeof(hdev->commands));
 }
 
-- 
1.8.3.1


^ permalink raw reply related

* [PATCH BlueZ 1/3] android/hid: Add handling of incoming connections
From: Luiz Augusto von Dentz @ 2013-10-31 12:19 UTC (permalink / raw)
  To: linux-bluetooth

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

---
 android/hid.c | 90 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 90 insertions(+)

diff --git a/android/hid.c b/android/hid.c
index 49e9c52..92efd72 100644
--- a/android/hid.c
+++ b/android/hid.c
@@ -45,6 +45,8 @@
 #define MAX_READ_BUFFER		4096
 
 static GIOChannel *notification_io = NULL;
+static GIOChannel *ctrl_io = NULL;
+static GIOChannel *intr_io = NULL;
 static GSList *devices = NULL;
 
 struct hid_device {
@@ -313,12 +315,94 @@ void bt_hid_handle_cmd(GIOChannel *io, uint8_t opcode, void *buf, uint16_t len)
 	ipc_send_rsp(io, HAL_SERVICE_ID_HIDHOST, status);
 }
 
+static void connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
+{
+	struct hid_device *hdev;
+	bdaddr_t dst;
+	char address[18];
+	uint16_t psm;
+	GError *gerr = NULL;
+	GSList *l;
+
+	if (err) {
+		error("%s", err->message);
+		return;
+	}
+
+	bt_io_get(chan, &err,
+			BT_IO_OPT_DEST_BDADDR, &dst,
+			BT_IO_OPT_PSM, &psm,
+			BT_IO_OPT_INVALID);
+	if (err) {
+		error("%s", gerr->message);
+		g_io_channel_shutdown(chan, TRUE, NULL);
+		return;
+	}
+
+	ba2str(&dst, address);
+	DBG("Incoming connection from %s on PSM %d", address, psm);
+
+	switch (psm) {
+	case L2CAP_PSM_HIDP_CTRL:
+		l = g_slist_find_custom(devices, &dst, device_cmp);
+		if (l)
+			return;
+
+		hdev = g_new0(struct hid_device, 1);
+		bacpy(&hdev->dst, &dst);
+		hdev->ctrl_io = g_io_channel_ref(chan);
+
+		devices = g_slist_append(devices, hdev);
+
+		hdev->ctrl_watch = g_io_add_watch(hdev->ctrl_io,
+					G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+					ctrl_watch_cb, hdev);
+
+		break;
+
+	case L2CAP_PSM_HIDP_INTR:
+		l = g_slist_find_custom(devices, &dst, device_cmp);
+		if (!l)
+			return;
+
+		hdev = l->data;
+		hdev->intr_io = g_io_channel_ref(chan);
+		hdev->intr_watch = g_io_add_watch(hdev->intr_io,
+				G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+				intr_watch_cb, hdev);
+		break;
+	}
+}
+
 bool bt_hid_register(GIOChannel *io, const bdaddr_t *addr)
 {
+	GError *err = NULL;
+
 	DBG("");
 
 	notification_io = g_io_channel_ref(io);
 
+	ctrl_io = bt_io_listen(connect_cb, NULL, NULL, NULL, &err,
+				BT_IO_OPT_PSM, L2CAP_PSM_HIDP_CTRL,
+				BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
+				BT_IO_OPT_INVALID);
+	if (!ctrl_io) {
+		error("Failed to listen on control channel");
+		g_error_free(err);
+		return false;
+	}
+
+	intr_io = bt_io_listen(connect_cb, NULL, NULL, NULL, &err,
+				BT_IO_OPT_PSM, L2CAP_PSM_HIDP_INTR,
+				BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
+				BT_IO_OPT_INVALID);
+	if (!intr_io) {
+		error("Failed to listen on interrupt channel");
+		g_io_channel_unref(ctrl_io);
+		g_error_free(err);
+		return false;
+	}
+
 	return true;
 }
 
@@ -328,4 +412,10 @@ void bt_hid_unregister(void)
 
 	g_io_channel_unref(notification_io);
 	notification_io = NULL;
+
+	g_io_channel_unref(ctrl_io);
+	ctrl_io = NULL;
+
+	g_io_channel_unref(intr_io);
+	intr_io = NULL;
 }
-- 
1.8.3.1


^ permalink raw reply related


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