* Re: [PATCH BlueZ] shared/gatt-db: Expose gatt_db_attribute
From: Arman Uguray @ 2014-10-24 16:56 UTC (permalink / raw)
To: Luiz Augusto von Dentz; +Cc: BlueZ development
In-Reply-To: <1414158494-12020-1-git-send-email-luiz.dentz@gmail.com>
Hi Luiz,
On Fri, Oct 24, 2014 at 6:48 AM, Luiz Augusto von Dentz
<luiz.dentz@gmail.com> wrote:
> From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
>
> This is just a draft API to reduce the lookups in gatt_db and make it
> a little bit more convenient for batch operations, so the general idea
> is to be able to get a hold of it via gatt_db_get_attribute but also
> replace the handles in the queues with proper attributes so the server
> code don't have to lookup again when reading/writing, checking
> permissions, or any other operation that can be done directly.
> ---
> src/shared/gatt-db.h | 22 ++++++++++++++++++++++
> 1 file changed, 22 insertions(+)
>
> diff --git a/src/shared/gatt-db.h b/src/shared/gatt-db.h
> index 8d18434..ab7469a 100644
> --- a/src/shared/gatt-db.h
> +++ b/src/shared/gatt-db.h
> @@ -96,3 +96,25 @@ bool gatt_db_get_service_uuid(struct gatt_db *db, uint16_t handle,
>
> bool gatt_db_get_attribute_permissions(struct gatt_db *db, uint16_t handle,
> uint32_t *permissions);
> +
> +struct gatt_db_attribute;
> +
> +struct gatt_db_attribute *gatt_db_get_attribute(struct gatt_db *attrib,
> + uint16_t handle, uint16_t offset);
> +
What's the offset parameter here for? Why not just get the attribute by handle?
> +const bt_uuid_t *gatt_db_attribute_get_type(struct gatt_db_attribute *attrib);
> +
> +bool gatt_db_attribute_get_service_uuid(struct gatt_db_attribute *attrib,
> + bt_uuid_t *uuid);
> +
> +bool gatt_db_attribute_get_permissions(struct gatt_db_attribute *attrib,
> + uint32_t *permissions);
> +
> +bool gatt_db_attribute_read(struct gatt_db_attribute *attrib,
> + uint8_t opcode, bdaddr_t *bdaddr,
> + void *callback, void *user_data);
> +
> +bool gatt_db_attribute_write(struct gatt_db_attribute *attrib,
> + const uint8_t *value, size_t len,
> + uint8_t opcode, bdaddr_t *bdaddr,
> + void *callback, void *user_data);
> --
Are these functions meant to replace the existing gatt_db_read, etc?
We might as well just replace all of those with functions that accept
a struct gatt_db_attribute. So that all functions would be preceded by
a call to gatt_db_get_attribute, followed by one of these functions.
Unless you want to keep the other functions as helpers that accomplish
the same thing.
> 1.9.3
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
Cheers,
Arman
^ permalink raw reply
* [PATCH v2] android/pts: Interim PTS tests results for L2CAP
From: Sebastian Chlad @ 2014-10-24 15:45 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Sebastian Chlad
---
android/pts-l2cap.txt | 60 +++++++++++++++++++++++++++++++++++++--------------
1 file changed, 44 insertions(+), 16 deletions(-)
diff --git a/android/pts-l2cap.txt b/android/pts-l2cap.txt
index 0746ea7..9706d69 100644
--- a/android/pts-l2cap.txt
+++ b/android/pts-l2cap.txt
@@ -1,7 +1,7 @@
PTS test results for L2CAP
-PTS version: 5.2
-Tested: 14-August-2014
+PTS version: 5.3
+Tested: 24-October-2014
Android version: 4.4.4
Kernel version: 3.18
@@ -15,28 +15,37 @@ N/A test is disabled due to PICS setup
Test Name Result Notes
-------------------------------------------------------------------------------
TC_COS_CED_BV_01_C PASS l2test -n -P 4113 <bdaddr>
-TC_COS_CED_BV_03_C PASS l2test -w -N 1 -P 4113
-TC_COS_CED_BV_04_C PASS l2test -r -P 4113
-TC_COS_CED_BV_05_C PASS l2test -r -P 4113
-TC_COS_CED_BV_07_C PASS l2test -r -P 4113
-TC_COS_CED_BV_08_C PASS l2test -r -P 4113
+TC_COS_CED_BV_03_C PASS l2test -y -N 1 -P 4113 <bdaddr>
+TC_COS_CED_BV_04_C PASS l2test -n -P 4113 <bdaddr>
+TC_COS_CED_BV_05_C PASS PTS issue #12351
+ btmgmt ssp off
+ l2test -r -P 4113
+TC_COS_CED_BV_07_C PASS l2test -n -P 4113 <bdaddr>
+TC_COS_CED_BV_08_C PASS l2test -n -P 4113 <bdaddr>
TC_COS_CED_BV_09_C PASS l2test -n -P 4113 <bdaddr>
TC_COS_CED_BV_10_C N/A
-TC_COS_CED_BV_11_C PASS l2test -r -P 4113
+TC_COS_CED_BV_11_C PASS l2test -u -P 4113 <bdaddr>
TC_COS_CED_BI_01_C PASS
-TC_COS_CFD_BV_01_C PASS l2test -r -P 4113
-TC_COS_CFD_BV_02_C PASS l2test -r -P 4113
-TC_COS_CFD_BV_03_C PASS l2test -r -P 4113
+TC_COS_CFD_BV_01_C PASS PTS issue #12351
+ btmgmt ssp off
+ l2test -r -P 4113
+TC_COS_CFD_BV_02_C PASS l2test -n -P 4113 <bdaddr>
+TC_COS_CFD_BV_03_C PASS l2test -n -P 4113 <bdaddr>
TC_COS_CFD_BV_08_C PASS l2test -n -P 4113 <bdaddr>
TC_COS_CFD_BV_09_C PASS l2test -n -P 4113 <bdaddr>
TC_COS_CFD_BV_10_C N/A
-TC_COS_CFD_BI_11_C PASS l2test -r -P 4113
-TC_COS_CFD_BV_12_C PASS l2test -r -P 4113
+TC_COS_CFD_BV_11_C PASS l2test -n -P 4113 <bdaddr>
+TC_COS_CFD_BV_12_C PASS l2test -n -P 4113 <bdaddr>
TC_COS_CFD_BV_13_C N/A
TC_COS_IEX_BV_01_C PASS l2test -n -P 4113 <bdaddr>
TC_COS_IEX_BV_02_C PASS
TC_COS_ECH_BV_01_C PASS
TC_COS_ECH_BV_02_C PASS l2ping -c 1 <bdaddr>
+TC_COS_CFC_BV_01_C INC JIRA #BA-181
+TC_COS_CFC_BV_02_C INC JIRA #BA-181
+TC_COS_CFC_BV_03_C PASS l2test -u -V le_public <bdaddr>
+TC_COS_CFC_BV_04_C PASS l2test -u -V le_public <bdaddr>
+TC_COS_CFC_BV_05_C PASS l2test -m -V le_public <bdaddr>
TC_CLS_CLR_BV_01_C N/A
TC_CLS_UCD_BV_01_C PASS
TC_CLS_UCD_BV_02_C PASS l2test -s -G -N 1 -P 4113 <bdaddr>
@@ -75,10 +84,12 @@ TC_OFS_BV_01_C PASS l2test -x -X ertm -P 4113 -F 0 -N 1
TC_OFS_BV_02_C PASS l2test -r -X ertm -P 4113 -F 0
TC_OFS_BV_03_C PASS l2test -x -X streaming -P 4113 -F 0 -N 1
TC_OFS_BV_04_C PASS l2test -r -X streaming -P 4113 -F 0
+ JIRA issue #BA-180
TC_OFS_BV_05_C PASS l2test -x -X ertm -P 4113 -N 1
TC_OFS_BV_06_C PASS l2test -r -X ertm -P 4113
TC_OFS_BV_07_C PASS l2test -x -X streaming -P 4113 -F 0 -N 1
TC_OFS_BV_08_C PASS l2test -r -X streaming -P 4113
+ JIRA issue #BA-180
TC_ERM_BV_01_C PASS l2test -x -X ertm -P 4113 -N 3 -Y 3
TC_ERM_BV_02_C PASS l2test -r -X ertm -P 4113
TC_ERM_BV_03_C PASS l2test -r -X ertm -P 4113
@@ -92,7 +103,7 @@ TC_ERM_BV_11_C PASS l2test -x -X ertm -P 4113 -N 1 -Q 1
TC_ERM_BV_12_C PASS l2test -x -X ertm -P 4113 -R -N 1 -Q 1
TC_ERM_BV_13_C PASS l2test -x -X ertm -P 4113 -N 2
TC_ERM_BV_14_C PASS l2test -x -X ertm -P 4113 -N 4
-TC_ERM_BV_15_C PASS l2test -X ertm -P 4113 -N 4
+TC_ERM_BV_15_C PASS l2test -x -X ertm -P 4113 -N 4
TC_ERM_BV_16_C N/A
TC_ERM_BV_17_C PASS l2test -X ertm -P 4113
TC_ERM_BV_18_C PASS l2test -x -X ertm -P 4113 -N 1
@@ -147,6 +158,23 @@ TC_ECF_BV_08_C N/A
TC_LE_CPU_BV_01_C PASS l2test -r -V le_public -J 4
TC_LE_CPU_BV_02_C PASS l2test -n -V le_public -J 4 <braddr>
TC_LE_CPU_BI_01_C PASS l2test -n -V le_public -J 4 <braddr>
-TC_LE_CPU_BI_02_C INC PTS issue #12339
+TC_LE_CPU_BI_02_C PASS PTS issue #12339
+ Note: use Common.dll and ETS for L2CAP
+ from #12339
l2test -r -V le_public -J 4
-TC_LE_REJ_BV_01_C PASS l2test -n -V le_public -J 4 <braddr>
+TC_LE_REJ_BI_01_C PASS l2test -n -V le_public -J 4 <braddr>
+TC_LE_REJ_BI_02_C PASS l2test -n -V le_public -J 4 <braddr>
+TC_LE_CFC_BV_01_C PASS l2test -n -V le_public -P 37 <braddr>
+TC_LE_CFC_BV_02_C PASS l2test -n -V le_public -P 37 <braddr>
+TC_LE_CFC_BV_03_C INC PTS issue #12665
+TC_LE_CFC_BV_04_C PASS l2test -n -V le_public -P 241 <braddr>
+TC_LE_CFC_BV_05_C INC PTS issue #12665
+TC_LE_CFC_BV_06_C INC JIRA #BA-182
+TC_LE_CFC_BV_07_C INC JIRA #BA-183
+TC_LE_CFC_BI_01_C INC JIRA #BA-183
+TC_LE_CFC_BV_08_C PASS l2test -n -V le_public -P 37 <braddr>
+TC_LE_CFC_BV_09_C PASS l2test -n -V le_public -P 37 <braddr>
+TC_LE_CFC_BV_16_C PASS l2test -n -V le_public -P 37 <braddr>
+TC_LE_CFC_BV_17_C N/A
+TC_LE_CID_BV_01_C INC
+TC_LE_CID_BV_02_I INC
--
1.8.5.3
^ permalink raw reply related
* [PATCH] android/pts: Interim PTS tests results for L2CAP
From: Sebastian Chlad @ 2014-10-24 14:23 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Sebastian Chlad
---
android/pts-l2cap.txt | 60 +++++++++++++++++++++++++++++++++++++--------------
1 file changed, 44 insertions(+), 16 deletions(-)
diff --git a/android/pts-l2cap.txt b/android/pts-l2cap.txt
index 0746ea7..3c664f7 100644
--- a/android/pts-l2cap.txt
+++ b/android/pts-l2cap.txt
@@ -1,7 +1,7 @@
PTS test results for L2CAP
-PTS version: 5.2
-Tested: 14-August-2014
+PTS version: 5.3
+Tested: 24-October-2014
Android version: 4.4.4
Kernel version: 3.18
@@ -15,28 +15,37 @@ N/A test is disabled due to PICS setup
Test Name Result Notes
-------------------------------------------------------------------------------
TC_COS_CED_BV_01_C PASS l2test -n -P 4113 <bdaddr>
-TC_COS_CED_BV_03_C PASS l2test -w -N 1 -P 4113
-TC_COS_CED_BV_04_C PASS l2test -r -P 4113
-TC_COS_CED_BV_05_C PASS l2test -r -P 4113
-TC_COS_CED_BV_07_C PASS l2test -r -P 4113
-TC_COS_CED_BV_08_C PASS l2test -r -P 4113
+TC_COS_CED_BV_03_C PASS l2test -y -N 1 -P 4113 <bdaddr>
+TC_COS_CED_BV_04_C PASS l2test -n -P 4113 <bdaddr>
+TC_COS_CED_BV_05_C PASS PTS issue #12351
+ btmgmt ssp off
+ l2test -r -P 4113
+TC_COS_CED_BV_07_C PASS l2test -n -P 4113 <bdaddr>
+TC_COS_CED_BV_08_C PASS l2test -n -P 4113 <bdaddr>
TC_COS_CED_BV_09_C PASS l2test -n -P 4113 <bdaddr>
TC_COS_CED_BV_10_C N/A
-TC_COS_CED_BV_11_C PASS l2test -r -P 4113
+TC_COS_CED_BV_11_C PASS l2test -u -P 4113 <bdaddr>
TC_COS_CED_BI_01_C PASS
-TC_COS_CFD_BV_01_C PASS l2test -r -P 4113
-TC_COS_CFD_BV_02_C PASS l2test -r -P 4113
-TC_COS_CFD_BV_03_C PASS l2test -r -P 4113
+TC_COS_CFD_BV_01_C PASS PTS issue #12351
+ btmgmt ssp off
+ l2test -r -P 4113
+TC_COS_CFD_BV_02_C PASS l2test -n -P 4113 <bdaddr>
+TC_COS_CFD_BV_03_C PASS l2test -n -P 4113 <bdaddr>
TC_COS_CFD_BV_08_C PASS l2test -n -P 4113 <bdaddr>
TC_COS_CFD_BV_09_C PASS l2test -n -P 4113 <bdaddr>
TC_COS_CFD_BV_10_C N/A
-TC_COS_CFD_BI_11_C PASS l2test -r -P 4113
-TC_COS_CFD_BV_12_C PASS l2test -r -P 4113
+TC_COS_CFD_BV_11_C PASS l2test -n -P 4113 <bdaddr>
+TC_COS_CFD_BV_12_C PASS l2test -n -P 4113 <bdaddr>
TC_COS_CFD_BV_13_C N/A
TC_COS_IEX_BV_01_C PASS l2test -n -P 4113 <bdaddr>
TC_COS_IEX_BV_02_C PASS
TC_COS_ECH_BV_01_C PASS
TC_COS_ECH_BV_02_C PASS l2ping -c 1 <bdaddr>
+TC_COS_CFC_BV_01_C INC JIRA #BA-181
+TC_COS_CFC_BV_02_C INC JIRA #BA-181
+TC_COS_CFC_BV_03_C PASS l2test -u -V le_public 00:1B:dc:07:2f:f0
+TC_COS_CFC_BV_04_C PASS l2test -u -V le_public 00:1B:dc:07:2f:f0
+TC_COS_CFC_BV_05_C PASS l2test -m -V le_public 00:1B:dc:07:2f:f0
TC_CLS_CLR_BV_01_C N/A
TC_CLS_UCD_BV_01_C PASS
TC_CLS_UCD_BV_02_C PASS l2test -s -G -N 1 -P 4113 <bdaddr>
@@ -75,10 +84,12 @@ TC_OFS_BV_01_C PASS l2test -x -X ertm -P 4113 -F 0 -N 1
TC_OFS_BV_02_C PASS l2test -r -X ertm -P 4113 -F 0
TC_OFS_BV_03_C PASS l2test -x -X streaming -P 4113 -F 0 -N 1
TC_OFS_BV_04_C PASS l2test -r -X streaming -P 4113 -F 0
+ JIRA issue #BA-180
TC_OFS_BV_05_C PASS l2test -x -X ertm -P 4113 -N 1
TC_OFS_BV_06_C PASS l2test -r -X ertm -P 4113
TC_OFS_BV_07_C PASS l2test -x -X streaming -P 4113 -F 0 -N 1
TC_OFS_BV_08_C PASS l2test -r -X streaming -P 4113
+ JIRA issue #BA-180
TC_ERM_BV_01_C PASS l2test -x -X ertm -P 4113 -N 3 -Y 3
TC_ERM_BV_02_C PASS l2test -r -X ertm -P 4113
TC_ERM_BV_03_C PASS l2test -r -X ertm -P 4113
@@ -92,7 +103,7 @@ TC_ERM_BV_11_C PASS l2test -x -X ertm -P 4113 -N 1 -Q 1
TC_ERM_BV_12_C PASS l2test -x -X ertm -P 4113 -R -N 1 -Q 1
TC_ERM_BV_13_C PASS l2test -x -X ertm -P 4113 -N 2
TC_ERM_BV_14_C PASS l2test -x -X ertm -P 4113 -N 4
-TC_ERM_BV_15_C PASS l2test -X ertm -P 4113 -N 4
+TC_ERM_BV_15_C PASS l2test -x -X ertm -P 4113 -N 4
TC_ERM_BV_16_C N/A
TC_ERM_BV_17_C PASS l2test -X ertm -P 4113
TC_ERM_BV_18_C PASS l2test -x -X ertm -P 4113 -N 1
@@ -147,6 +158,23 @@ TC_ECF_BV_08_C N/A
TC_LE_CPU_BV_01_C PASS l2test -r -V le_public -J 4
TC_LE_CPU_BV_02_C PASS l2test -n -V le_public -J 4 <braddr>
TC_LE_CPU_BI_01_C PASS l2test -n -V le_public -J 4 <braddr>
-TC_LE_CPU_BI_02_C INC PTS issue #12339
+TC_LE_CPU_BI_02_C PASS PTS issue #12339
+ Note: use Common.dll and ETS for L2CAP
+ from #12339
l2test -r -V le_public -J 4
-TC_LE_REJ_BV_01_C PASS l2test -n -V le_public -J 4 <braddr>
+TC_LE_REJ_BI_01_C PASS l2test -n -V le_public -J 4 <braddr>
+TC_LE_REJ_BI_02_C PASS l2test -n -V le_public -J 4 <braddr>
+TC_LE_CFC_BV_01_C PASS l2test -n -V le_public -P 37 <braddr>
+TC_LE_CFC_BV_02_C PASS l2test -n -V le_public -P 37 <braddr>
+TC_LE_CFC_BV_03_C INC PTS issue #12665
+TC_LE_CFC_BV_04_C PASS l2test -n -V le_public -P 241 <braddr>
+TC_LE_CFC_BV_05_C INC PTS issue #12665
+TC_LE_CFC_BV_06_C INC JIRA #BA-182
+TC_LE_CFC_BV_07_C INC JIRA #BA-183
+TC_LE_CFC_BI_01_C INC JIRA #BA-183
+TC_LE_CFC_BV_08_C PASS l2test -n -V le_public -P 37 <braddr>
+TC_LE_CFC_BV_09_C PASS l2test -n -V le_public -P 37 <braddr>
+TC_LE_CFC_BV_16_C PASS l2test -n -V le_public -P 37 <braddr>
+TC_LE_CFC_BV_17_C N/A
+TC_LE_CID_BV_01_C INC
+TC_LE_CID_BV_02_I INC
--
1.8.5.3
^ permalink raw reply related
* [bluetooth] btusb duplicate filtering
From: Patrick Shirkey @ 2014-10-24 14:22 UTC (permalink / raw)
To: linux-bluetooth
Hi,
I am seeing the following behaviour with an android device running the
8723au chipset with bluez + backports + btusb.c (new branch).
Step 1:
1: enable BT via settings UI
2: open BLE scanner app
3: app finds all BLE devices
Step 2:
4: close BLE scanner app
5: open BLE scanner app
6: app cannot find any BLE device
- Szymon has suggested it is related to duplicate filtering and may be
handled at the driver or chipset firmware level.
- I found this post which might provide some useful background info.
http://stackoverflow.com/questions/19502853/android-4-3-ble-filtering-behaviour-of-startlescan
- My question is can I do anything at the driver/kernel/bluez level so
that BLE devices always show up?
LOGS
- I see the following output in logcat:
Step 1:
10-24 07:06:27.450 D/TAG (13289): ~ Starting Scan
10-24 07:06:27.450 D/BluetoothAdapter(13289): startLeScan(): null
10-24 07:06:27.450 D/BtGatt.GattService(13351): registerClient() -
UUID=3ed977cb-dddb-4518-af26-eb41adb97c38
10-24 07:06:27.450 I/bluetoothd(13365): bluetoothd[13366]:
external/bluetooth/bluez/android/gatt.c:handle_client_register()
10-24 07:06:27.460 D/BtGatt.GattService(13351): onClientRegistered() -
UUID=3ed977cb-dddb-4518-af26-eb41adb97c38, clientIf=1
10-24 07:06:27.460 D/BluetoothAdapter(13289): onClientRegistered() -
status=0 clientIf=1
10-24 07:06:27.460 D/BtGatt.GattService(13351): startScan() - queue=0
10-24 07:06:27.460 D/BtGatt.GattService(13351): startScan() - adding client=1
10-24 07:06:27.470 I/bluetoothd(13365): bluetoothd[13366]:
external/bluetooth/bluez/android/gatt.c:handle_client_scan() new state 1
10-24 07:06:27.470 I/bluetoothd(13365): bluetoothd[13366]:
external/bluetooth/bluez/android/bluetooth.c:start_discovery() type=0x6
10-24 07:06:27.470 I/bluetoothd(13365): bluetoothd[13366]:
external/bluetooth/bluez/android/bluetooth.c:mgmt_discovering_event() type
6 discovering 1
10-24 07:06:27.480 I/bluetoothd(13365): bluetoothd[13366]:
external/bluetooth/bluez/android/bluetooth.c:check_discovery_state() 6 0
10-24 07:06:27.510 W/InputMethodManagerService( 1612): Window already
focused, ignoring focus gain of:
com.android.internal.view.IInputMethodClient$Stub$Proxy@41a51080
attribute=null, token = android.os.BinderProxy@41aa49c0
10-24 07:06:27.530 I/bluetoothd(13365): bluetoothd[13366]:
external/bluetooth/bluez/android/bluetooth.c:mgmt_device_found_event()
hci0 addr BC:6A:29:AB:2C:AA, rssi -36 flags 0x0000 eir_len 25
10-24 07:06:27.530 I/bluetoothd(13365): bluetoothd[13366]:
external/bluetooth/bluez/android/gatt.c:le_device_found_handler() LE
Device found: BC:6A:29:AB:2C:AA, rssi: -36, adv_data: 1
10-24 07:06:27.540 D/BlueZ (13351):
external/bluetooth/bluez/android/hal-bluetooth.c:handle_device_found()
10-24 07:06:27.550 D/BlueZ (13351):
external/bluetooth/bluez/android/hal-bluetooth.c:device_props_to_hal()
prop[0]: type=BT_PROPERTY_BDADDR len=6 val=bc:6a:29:ab:2c:aa
10-24 07:06:27.550 D/BlueZ (13351):
external/bluetooth/bluez/android/hal-bluetooth.c:device_props_to_hal()
prop[1]: type=BT_PROPERTY_TYPE_OF_DEVICE len=4 val=BT_DEVICE_DEVTYPE_BLE
10-24 07:06:27.550 D/BlueZ (13351):
external/bluetooth/bluez/android/hal-bluetooth.c:device_props_to_hal()
prop[2]: type=BT_PROPERTY_REMOTE_RSSI len=4 val=220
10-24 07:06:27.550 D/BlueZ (13351):
external/bluetooth/bluez/android/hal-bluetooth.c:device_props_to_hal()
prop[3]: type=BT_PROPERTY_BDNAME len=17 val=BC:6A:29:AB:2C:AA
10-24 07:06:27.580 D/BtGatt.GattService(13351): onScanResult() -
address=BC:6A:29:AB:2C:AA, rssi=-36
10-24 07:06:27.580 D/BluetoothAdapter(13289): onScanResult() -
Device=BC:6A:29:AB:2C:AA RSSI=-36
10-24 07:06:27.690 D/BluetoothEventManager( 1767): DeviceFoundHandler
created new CachedBluetoothDevice: BC:6A:29:AB:2C:AA
10-24 07:06:27.730 D/android.widget.GridLayout(13289): horizontal
constraints: x2-x0>=376, x2-x1<=187, x1-x0<=81 are inconsistent;
permanently removing: x2-x1<=187.
10-24 07:06:37.720 I/bluetoothd(13365): bluetoothd[13366]:
external/bluetooth/bluez/android/bluetooth.c:mgmt_device_found_event()
hci0 addr BC:6A:29:AB:2D:17, rssi -48 flags 0x0000 eir_len 25
10-24 07:06:37.720 I/bluetoothd(13365): bluetoothd[13366]:
external/bluetooth/bluez/android/gatt.c:le_device_found_handler() LE
Device found: BC:6A:29:AB:2D:17, rssi: -48, adv_data: 1
10-24 07:06:37.730 I/bluetoothd(13365): bluetoothd[13366]:
external/bluetooth/bluez/android/bluetooth.c:mgmt_discovering_event() type
6 discovering 0
10-24 07:06:37.730 D/BlueZ (13351):
external/bluetooth/bluez/android/hal-bluetooth.c:handle_device_found()
10-24 07:06:37.730 I/bluetoothd(13365): bluetoothd[13366]:
external/bluetooth/bluez/android/bluetooth.c:check_discovery_state() 0 6
10-24 07:06:37.730 I/bluetoothd(13365): bluetoothd[13366]:
external/bluetooth/bluez/android/bluetooth.c:start_discovery() type=0x6
10-24 07:06:37.740 D/BlueZ (13351):
external/bluetooth/bluez/android/hal-bluetooth.c:device_props_to_hal()
prop[0]: type=BT_PROPERTY_BDADDR len=6 val=bc:6a:29:ab:2d:17
10-24 07:06:37.740 D/BlueZ (13351):
external/bluetooth/bluez/android/hal-bluetooth.c:device_props_to_hal()
prop[1]: type=BT_PROPERTY_TYPE_OF_DEVICE len=4 val=BT_DEVICE_DEVTYPE_BLE
10-24 07:06:37.740 D/BlueZ (13351):
external/bluetooth/bluez/android/hal-bluetooth.c:device_props_to_hal()
prop[2]: type=BT_PROPERTY_REMOTE_RSSI len=4 val=208
10-24 07:06:37.740 I/bluetoothd(13365): bluetoothd[13366]:
external/bluetooth/bluez/android/bluetooth.c:mgmt_discovering_event() type
6 discovering 1
10-24 07:06:37.740 I/bluetoothd(13365): bluetoothd[13366]:
external/bluetooth/bluez/android/bluetooth.c:check_discovery_state() 6 0
10-24 07:06:37.750 D/BlueZ (13351):
external/bluetooth/bluez/android/hal-bluetooth.c:device_props_to_hal()
prop[3]: type=BT_PROPERTY_BDNAME len=17 val=BC:6A:29:AB:2D:17
10-24 07:06:37.770 D/BtGatt.GattService(13351): onScanResult() -
address=BC:6A:29:AB:2D:17, rssi=-48
10-24 07:06:37.780 D/BluetoothAdapter(13289): onScanResult() -
Device=BC:6A:29:AB:2D:17 RSSI=-48
10-24 07:06:37.870 D/android.widget.GridLayout(13289): horizontal
constraints: x2-x0>=376, x2-x1<=187, x1-x0<=81 are inconsistent;
permanently removing: x2-x1<=187.
10-24 07:06:37.870 D/BluetoothEventManager( 1767): DeviceFoundHandler
created new CachedBluetoothDevice: BC:6A:29:AB:2D:17
Step 2:
10-24 07:15:09.150 D/TAG (13289): ~ Starting Scan
10-24 07:15:09.150 D/BluetoothAdapter(13289): startLeScan(): null
10-24 07:15:09.170 D/BtGatt.GattService(13351): registerClient() -
UUID=e423968e-1bfe-4822-a62b-83804fb6998d
10-24 07:15:09.170 I/bluetoothd(13365): bluetoothd[13366]:
external/bluetooth/bluez/android/gatt.c:handle_client_register()
10-24 07:15:09.170 D/BtGatt.GattService(13351): onClientRegistered() -
UUID=e423968e-1bfe-4822-a62b-83804fb6998d, clientIf=2
10-24 07:15:09.170 D/BluetoothAdapter(13289): onClientRegistered() -
status=0 clientIf=2
10-24 07:15:09.170 D/BtGatt.GattService(13351): startScan() - queue=0
10-24 07:15:09.180 D/BtGatt.GattService(13351): startScan() - adding client=2
10-24 07:15:09.180 I/bluetoothd(13365): bluetoothd[13366]:
external/bluetooth/bluez/android/gatt.c:handle_client_scan() new state 1
10-24 07:15:09.180 I/bluetoothd(13365): bluetoothd[13366]:
external/bluetooth/bluez/android/bluetooth.c:start_discovery() type=0x6
10-24 07:15:09.190 I/bluetoothd(13365): bluetoothd[13366]:
external/bluetooth/bluez/android/bluetooth.c:mgmt_discovering_event() type
6 discovering 1
10-24 07:15:09.190 I/bluetoothd(13365): bluetoothd[13366]:
external/bluetooth/bluez/android/bluetooth.c:check_discovery_state() 6 0
10-24 07:15:09.250 W/InputMethodManagerService( 1612): Window already
focused, ignoring focus gain of:
com.android.internal.view.IInputMethodClient$Stub$Proxy@41b85ab8
attribute=null, token = android.os.BinderProxy@41afac00
10-24 07:15:19.440 I/bluetoothd(13365): bluetoothd[13366]:
external/bluetooth/bluez/android/bluetooth.c:mgmt_discovering_event() type
6 discovering 0
10-24 07:15:19.440 I/bluetoothd(13365): bluetoothd[13366]:
external/bluetooth/bluez/android/bluetooth.c:check_discovery_state() 0 6
10-24 07:15:19.450 I/bluetoothd(13365): bluetoothd[13366]:
external/bluetooth/bluez/android/bluetooth.c:start_discovery() type=0x6
10-24 07:15:19.460 I/bluetoothd(13365): bluetoothd[13366]:
external/bluetooth/bluez/android/bluetooth.c:mgmt_discovering_event() type
6 discovering 1
10-24 07:15:19.460 I/bluetoothd(13365): bluetoothd[13366]:
external/bluetooth/bluez/android/bluetooth.c:check_discovery_state() 6 0
- I see the following output in btmon:
Step 1:
# btmon
Bluetooth monitor ver 5.23
= New Index: CC:D2:9C:73:CB:45 (BR/EDR,USB,hci0) [hci0]
0.921673
< HCI Command: LE Set Scan Enable (0x08|0x000c) plen 2 [hci0]
6.885250
Scanning: Disabled (0x00)
Filter duplicates: Disabled (0x00)
> HCI Event: Command Complete (0x0e) plen 4 [hci0]
6.886777
LE Set Scan Enable (0x08|0x000c) ncmd 2
Status: Success (0x00)
@ Discovering: 0x00 (6)
< HCI Command: LE Set Random Address (0x08|0x0005) plen 6 [hci0]
6.891384
Address: 33:31:38:D9:1B:2E (Non-Resolvable)
> HCI Event: Command Complete (0x0e) plen 4 [hci0]
6.892774
LE Set Random Address (0x08|0x0005) ncmd 2
Status: Success (0x00)
< HCI Command: LE Set Scan Parameters (0x08|0x000b) plen 7 [hci0]
6.892944
Type: Active (0x01)
Interval: 11.250 msec (0x0012)
Window: 11.250 msec (0x0012)
Own address type: Random (0x01)
Filter policy: Accept all advertisement (0x00)
> HCI Event: Command Complete (0x0e) plen 4 [hci0]
6.894777
LE Set Scan Parameters (0x08|0x000b) ncmd 2
Status: Success (0x00)
< HCI Command: LE Set Scan Enable (0x08|0x000c) plen 2 [hci0]
6.895268
Scanning: Enabled (0x01)
Filter duplicates: Enabled (0x01)
> HCI Event: Command Complete (0x0e) plen 4 [hci0]
6.896768
LE Set Scan Enable (0x08|0x000c) ncmd 2
Status: Success (0x00)
@ Discovering: 0x01 (6)
< HCI Command: LE Set Scan Enable (0x08|0x000c) plen 2 [hci0]
17.165233
Scanning: Disabled (0x00)
Filter duplicates: Disabled (0x00)
> HCI Event: Command Complete (0x0e) plen 4 [hci0]
17.166804
LE Set Scan Enable (0x08|0x000c) ncmd 2
Status: Success (0x00)
@ Discovering: 0x00 (6)
< HCI Command: LE Set Random Address (0x08|0x0005) plen 6 [hci0]
17.172436
Address: 30:D0:1B:39:11:67 (Non-Resolvable)
> HCI Event: Command Complete (0x0e) plen 4 [hci0]
17.173779
LE Set Random Address (0x08|0x0005) ncmd 2
Status: Success (0x00)
< HCI Command: LE Set Scan Parameters (0x08|0x000b) plen 7 [hci0]
17.173957
Type: Active (0x01)
Interval: 11.250 msec (0x0012)
Window: 11.250 msec (0x0012)
Own address type: Random (0x01)
Filter policy: Accept all advertisement (0x00)
> HCI Event: Command Complete (0x0e) plen 4 [hci0]
17.175784
LE Set Scan Parameters (0x08|0x000b) ncmd 2
Status: Success (0x00)
< HCI Command: LE Set Scan Enable (0x08|0x000c) plen 2 [hci0]
17.175969
Scanning: Enabled (0x01)
Filter duplicates: Enabled (0x01)
> HCI Event: Command Complete (0x0e) plen 4 [hci0]
17.182437
LE Set Scan Enable (0x08|0x000c) ncmd 2
Status: Success (0x00)
@ Discovering: 0x01 (6)
< HCI Command: LE Set Scan Enable (0x08|0x000c) plen 2 [hci0]
27.445182
Scanning: Disabled (0x00)
Filter duplicates: Disabled (0x00)
> HCI Event: Command Complete (0x0e) plen 4 [hci0]
27.446769
LE Set Scan Enable (0x08|0x000c) ncmd 2
Status: Success (0x00)
@ Discovering: 0x00 (6)
< HCI Command: LE Set Random Address (0x08|0x0005) plen 6 [hci0]
27.452355
Address: 1F:D8:B6:3C:C6:59 (Non-Resolvable)
> HCI Event: Command Complete (0x0e) plen 4 [hci0]
27.453758
LE Set Random Address (0x08|0x0005) ncmd 2
Status: Success (0x00)
< HCI Command: LE Set Scan Parameters (0x08|0x000b) plen 7 [hci0]
27.453928
Type: Active (0x01)
Interval: 11.250 msec (0x0012)
Window: 11.250 msec (0x0012)
Own address type: Random (0x01)
Filter policy: Accept all advertisement (0x00)
> HCI Event: Command Complete (0x0e) plen 4 [hci0]
27.461737
LE Set Scan Parameters (0x08|0x000b) ncmd 2
Status: Success (0x00)
< HCI Command: LE Set Scan Enable (0x08|0x000c) plen 2 [hci0]
27.462099
Scanning: Enabled (0x01)
Filter duplicates: Enabled (0x01)
> HCI Event: Command Complete (0x0e) plen 4 [hci0]
27.464075
LE Set Scan Enable (0x08|0x000c) ncmd 2
Status: Success (0x00)
@ Discovering: 0x01 (6)
< HCI Command: LE Set Scan Enable (0x08|0x000c) plen 2 [hci0]
37.725179
Scanning: Disabled (0x00)
Filter duplicates: Disabled (0x00)
> HCI Event: Command Complete (0x0e) plen 4 [hci0]
37.726766
LE Set Scan Enable (0x08|0x000c) ncmd 2
Status: Success (0x00)
@ Discovering: 0x00 (6)
< HCI Command: LE Set Random Address (0x08|0x0005) plen 6 [hci0]
37.732082
Address: 26:B7:AE:E6:75:57 (Non-Resolvable)
> HCI Event: Command Complete (0x0e) plen 4 [hci0]
37.733782
LE Set Random Address (0x08|0x0005) ncmd 2
Status: Success (0x00)
< HCI Command: LE Set Scan Parameters (0x08|0x000b) plen 7 [hci0]
37.734090
Type: Active (0x01)
Interval: 11.250 msec (0x0012)
Window: 11.250 msec (0x0012)
Own address type: Random (0x01)
Filter policy: Accept all advertisement (0x00)
> HCI Event: Command Complete (0x0e) plen 4 [hci0]
37.735758
LE Set Scan Parameters (0x08|0x000b) ncmd 2
Status: Success (0x00)
< HCI Command: LE Set Scan Enable (0x08|0x000c) plen 2 [hci0]
37.735871
Scanning: Enabled (0x01)
Filter duplicates: Enabled (0x01)
> HCI Event: Command Complete (0x0e) plen 4 [hci0]
37.736753
LE Set Scan Enable (0x08|0x000c) ncmd 2
Status: Success (0x00)
@ Discovering: 0x01 (6)
< HCI Command: LE Set Scan Enable (0x08|0x000c) plen 2 [hci0]
48.005204
Scanning: Disabled (0x00)
Filter duplicates: Disabled (0x00)
> HCI Event: Command Complete (0x0e) plen 4 [hci0]
48.006786
LE Set Scan Enable (0x08|0x000c) ncmd 2
Status: Success (0x00)
@ Discovering: 0x00 (6)
< HCI Command: LE Set Random Address (0x08|0x0005) plen 6 [hci0]
48.016702
Address: 06:D6:55:3D:29:5F (Non-Resolvable)
> HCI Event: Command Complete (0x0e) plen 4 [hci0]
48.017777
LE Set Random Address (0x08|0x0005) ncmd 2
Status: Success (0x00)
< HCI Command: LE Set Scan Parameters (0x08|0x000b) plen 7 [hci0]
48.018674
Type: Active (0x01)
Interval: 11.250 msec (0x0012)
Window: 11.250 msec (0x0012)
Own address type: Random (0x01)
Filter policy: Accept all advertisement (0x00)
> HCI Event: Command Complete (0x0e) plen 4 [hci0]
48.019771
LE Set Scan Parameters (0x08|0x000b) ncmd 2
Status: Success (0x00)
< HCI Command: LE Set Scan Enable (0x08|0x000c) plen 2 [hci0]
48.019967
Scanning: Enabled (0x01)
Filter duplicates: Enabled (0x01)
> HCI Event: Command Complete (0x0e) plen 4 [hci0]
48.021775
LE Set Scan Enable (0x08|0x000c) ncmd 2
Status: Success (0x00)
@ Discovering: 0x01 (6)
< HCI Command: LE Set Scan Enable (0x08|0x000c) plen 2 [hci0]
58.290259
Scanning: Disabled (0x00)
Filter duplicates: Disabled (0x00)
> HCI Event: Command Complete (0x0e) plen 4 [hci0]
58.291852
LE Set Scan Enable (0x08|0x000c) ncmd 2
Status: Success (0x00)
@ Discovering: 0x00 (6)
< HCI Command: LE Set Random Address (0x08|0x0005) plen 6 [hci0]
58.297162
Address: 06:E6:71:FF:BA:41 (Non-Resolvable)
> HCI Event: Command Complete (0x0e) plen 4 [hci0]
58.298778
LE Set Random Address (0x08|0x0005) ncmd 2
Status: Success (0x00)
< HCI Command: LE Set Scan Parameters (0x08|0x000b) plen 7 [hci0]
58.299040
Type: Active (0x01)
Interval: 11.250 msec (0x0012)
Window: 11.250 msec (0x0012)
Own address type: Random (0x01)
Filter policy: Accept all advertisement (0x00)
> HCI Event: Command Complete (0x0e) plen 4 [hci0]
58.300779
LE Set Scan Parameters (0x08|0x000b) ncmd 2
Status: Success (0x00)
< HCI Command: LE Set Scan Enable (0x08|0x000c) plen 2 [hci0]
58.301042
Scanning: Enabled (0x01)
Filter duplicates: Enabled (0x01)
> HCI Event: Command Complete (0x0e) plen 4 [hci0]
58.302784
LE Set Scan Enable (0x08|0x000c) ncmd 2
Status: Success (0x00)
@ Discovering: 0x01 (6)
< HCI Command: LE Set Scan Enable (0x08|0x000c) plen 2 [hci0]
68.565182
Scanning: Disabled (0x00)
Filter duplicates: Disabled (0x00)
> HCI Event: Command Complete (0x0e) plen 4 [hci0]
68.566772
LE Set Scan Enable (0x08|0x000c) ncmd 2
Status: Success (0x00)
@ Discovering: 0x00 (6)
< HCI Command: LE Set Random Address (0x08|0x0005) plen 6 [hci0]
68.573095
Address: 25:42:7A:0D:BF:7D (Non-Resolvable)
> HCI Event: Command Complete (0x0e) plen 4 [hci0]
68.574788
LE Set Random Address (0x08|0x0005) ncmd 2
Status: Success (0x00)
< HCI Command: LE Set Scan Parameters (0x08|0x000b) plen 7 [hci0]
68.575193
Type: Active (0x01)
Interval: 11.250 msec (0x0012)
Window: 11.250 msec (0x0012)
Own address type: Random (0x01)
Filter policy: Accept all advertisement (0x00)
> HCI Event: Command Complete (0x0e) plen 4 [hci0]
68.576785
LE Set Scan Parameters (0x08|0x000b) ncmd 2
Status: Success (0x00)
< HCI Command: LE Set Scan Enable (0x08|0x000c) plen 2 [hci0]
68.577027
Scanning: Enabled (0x01)
Filter duplicates: Enabled (0x01)
> HCI Event: Command Complete (0x0e) plen 4 [hci0]
68.584697
LE Set Scan Enable (0x08|0x000c) ncmd 2
Status: Success (0x00)
@ Discovering: 0x01 (6)
< HCI Command: LE Set Scan Enable (0x08|0x000c) plen 2 [hci0]
78.845191
Scanning: Disabled (0x00)
Filter duplicates: Disabled (0x00)
> HCI Event: Command Complete (0x0e) plen 4 [hci0]
78.846780
LE Set Scan Enable (0x08|0x000c) ncmd 2
Status: Success (0x00)
@ Discovering: 0x00 (6)
< HCI Command: LE Set Random Address (0x08|0x0005) plen 6 [hci0]
78.853717
Address: 3A:B8:26:AA:9B:12 (Non-Resolvable)
> HCI Event: Command Complete (0x0e) plen 4 [hci0]
78.854825
LE Set Random Address (0x08|0x0005) ncmd 2
Status: Success (0x00)
< HCI Command: LE Set Scan Parameters (0x08|0x000b) plen 7 [hci0]
78.856067
Type: Active (0x01)
Interval: 11.250 msec (0x0012)
Window: 11.250 msec (0x0012)
Own address type: Random (0x01)
Filter policy: Accept all advertisement (0x00)
> HCI Event: Command Complete (0x0e) plen 4 [hci0]
78.857777
LE Set Scan Parameters (0x08|0x000b) ncmd 2
Status: Success (0x00)
< HCI Command: LE Set Scan Enable (0x08|0x000c) plen 2 [hci0]
78.859335
Scanning: Enabled (0x01)
Filter duplicates: Enabled (0x01)
> HCI Event: Command Complete (0x0e) plen 4 [hci0]
78.864484
LE Set Scan Enable (0x08|0x000c) ncmd 2
Status: Success (0x00)
@ Discovering: 0x01 (6)
/// Step 2:
< HCI Command: LE Set Random Address (0x08|0x0005) plen 6 [hci0]
99.375289
Address: 25:61:0F:37:30:99 (Non-Resolvable)
> HCI Event: Command Complete (0x0e) plen 4 [hci0]
99.378071
LE Set Random Address (0x08|0x0005) ncmd 2
Status: Success (0x00)
< HCI Command: LE Set Scan Parameters (0x08|0x000b) plen 7 [hci0]
99.379701
Type: Active (0x01)
Interval: 11.250 msec (0x0012)
Window: 11.250 msec (0x0012)
Own address type: Random (0x01)
Filter policy: Accept all advertisement (0x00)
> HCI Event: Command Complete (0x0e) plen 4 [hci0]
99.380778
LE Set Scan Parameters (0x08|0x000b) ncmd 2
Status: Success (0x00)
< HCI Command: LE Set Scan Enable (0x08|0x000c) plen 2 [hci0]
99.380939
Scanning: Enabled (0x01)
Filter duplicates: Enabled (0x01)
> HCI Event: Command Complete (0x0e) plen 4 [hci0]
99.382768
LE Set Scan Enable (0x08|0x000c) ncmd 2
Status: Success (0x00)
@ Discovering: 0x01 (6)
< HCI Command: LE Set Scan Enable (0x08|0x000c) plen 2 [hci0]
109.645175
Scanning: Disabled (0x00)
Filter duplicates: Disabled (0x00)
> HCI Event: Command Complete (0x0e) plen 4 [hci0]
109.646778
LE Set Scan Enable (0x08|0x000c) ncmd 2
Status: Success (0x00)
@ Discovering: 0x00 (6)
< HCI Command: LE Set Random Address (0x08|0x0005) plen 6 [hci0]
109.652523
Address: 3F:4D:C3:01:6A:72 (Non-Resolvable)
> HCI Event: Command Complete (0x0e) plen 4 [hci0]
109.653782
LE Set Random Address (0x08|0x0005) ncmd 2
Status: Success (0x00)
< HCI Command: LE Set Scan Parameters (0x08|0x000b) plen 7 [hci0]
109.654052
Type: Active (0x01)
Interval: 11.250 msec (0x0012)
Window: 11.250 msec (0x0012)
Own address type: Random (0x01)
Filter policy: Accept all advertisement (0x00)
> HCI Event: Command Complete (0x0e) plen 4 [hci0]
109.655774
LE Set Scan Parameters (0x08|0x000b) ncmd 2
Status: Success (0x00)
< HCI Command: LE Set Scan Enable (0x08|0x000c) plen 2 [hci0]
109.656344
Scanning: Enabled (0x01)
Filter duplicates: Enabled (0x01)
> HCI Event: Command Complete (0x0e) plen 4 [hci0]
109.657769
LE Set Scan Enable (0x08|0x000c) ncmd 2
Status: Success (0x00)
@ Discovering: 0x01 (6)
--
Patrick Shirkey
Boost Hardware Ltd
^ permalink raw reply
* [PATCH BlueZ] shared/gatt-db: Expose gatt_db_attribute
From: Luiz Augusto von Dentz @ 2014-10-24 13:48 UTC (permalink / raw)
To: linux-bluetooth
From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
This is just a draft API to reduce the lookups in gatt_db and make it
a little bit more convenient for batch operations, so the general idea
is to be able to get a hold of it via gatt_db_get_attribute but also
replace the handles in the queues with proper attributes so the server
code don't have to lookup again when reading/writing, checking
permissions, or any other operation that can be done directly.
---
src/shared/gatt-db.h | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/src/shared/gatt-db.h b/src/shared/gatt-db.h
index 8d18434..ab7469a 100644
--- a/src/shared/gatt-db.h
+++ b/src/shared/gatt-db.h
@@ -96,3 +96,25 @@ bool gatt_db_get_service_uuid(struct gatt_db *db, uint16_t handle,
bool gatt_db_get_attribute_permissions(struct gatt_db *db, uint16_t handle,
uint32_t *permissions);
+
+struct gatt_db_attribute;
+
+struct gatt_db_attribute *gatt_db_get_attribute(struct gatt_db *attrib,
+ uint16_t handle, uint16_t offset);
+
+const bt_uuid_t *gatt_db_attribute_get_type(struct gatt_db_attribute *attrib);
+
+bool gatt_db_attribute_get_service_uuid(struct gatt_db_attribute *attrib,
+ bt_uuid_t *uuid);
+
+bool gatt_db_attribute_get_permissions(struct gatt_db_attribute *attrib,
+ uint32_t *permissions);
+
+bool gatt_db_attribute_read(struct gatt_db_attribute *attrib,
+ uint8_t opcode, bdaddr_t *bdaddr,
+ void *callback, void *user_data);
+
+bool gatt_db_attribute_write(struct gatt_db_attribute *attrib,
+ const uint8_t *value, size_t len,
+ uint8_t opcode, bdaddr_t *bdaddr,
+ void *callback, void *user_data);
--
1.9.3
^ permalink raw reply related
* Re: [PATCH 1/8] android/gatt: Fix return status if cannot alloc memory
From: Szymon Janc @ 2014-10-24 12:18 UTC (permalink / raw)
To: Grzegorz Kolodziejczyk; +Cc: linux-bluetooth
In-Reply-To: <1413553099-19689-1-git-send-email-grzegorz.kolodziejczyk@tieto.com>
Hi Grzegorz,
On Friday 17 of October 2014 15:38:12 Grzegorz Kolodziejczyk wrote:
> NOMEM HAL status should be returned in case if it's not possible to
> alloc memory for notifiaction data.
> ---
> android/gatt.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/android/gatt.c b/android/gatt.c
> index ea20941..c26d45a 100644
> --- a/android/gatt.c
> +++ b/android/gatt.c
> @@ -3759,7 +3759,7 @@ static void handle_client_register_for_notification(const void *buf,
>
> notification = new0(struct notification_data, 1);
> if (!notification) {
> - status = HAL_STATUS_FAILED;
> + status = HAL_STATUS_NOMEM;
> goto failed;
> }
>
All patches have been applied. Thanks.
--
Best regards,
Szymon Janc
^ permalink raw reply
* [PATCH v5 11/11] unit/test-hfp: Add some robustness tests for HFP HF
From: Lukasz Rymanowski @ 2014-10-24 11:59 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Lukasz Rymanowski
In-Reply-To: <1414151975-20588-1-git-send-email-lukasz.rymanowski@tieto.com>
This patch adds folowing tests:
/hfp/test_hf_corrupted_1
/hfp/test_hf_corrupted_2
/hfp/test_hf_empty
/hfp/test_hf_unknown
---
unit/test-hfp.c | 40 ++++++++++++++++++++++++++++++++++++++++
1 file changed, 40 insertions(+)
diff --git a/unit/test-hfp.c b/unit/test-hfp.c
index ab695d7..24ea402 100644
--- a/unit/test-hfp.c
+++ b/unit/test-hfp.c
@@ -563,6 +563,25 @@ static void test_hf_unsolicited(gconstpointer data)
execute_context(context);
}
+static void test_hf_robustness(gconstpointer data)
+{
+ struct context *context = create_context(data);
+ bool ret;
+
+ context->hfp_hf = hfp_hf_new(context->fd_client);
+ g_assert(context->hfp_hf);
+
+ ret = hfp_hf_set_close_on_unref(context->hfp_hf, true);
+ g_assert(ret);
+
+ send_pdu(context);
+
+ hfp_hf_unref(context->hfp_hf);
+ context->hfp_hf = NULL;
+
+ execute_context(context);
+}
+
int main(int argc, char *argv[])
{
g_test_init(&argc, &argv, NULL);
@@ -674,5 +693,26 @@ int main(int argc, char *argv[])
frg_pdu('\n'),
data_end());
+ define_hf_test("/hfp_hf/test_corrupted_1", test_hf_unsolicited,
+ hf_result_handler, NULL,
+ raw_pdu('+', 'C', 'L', 'C', 'C', '\0'),
+ frg_pdu('\r', 'X', '\r', '\n'),
+ frg_pdu('+', 'C', 'L', 'C', 'C', ':', '1', ',', '3'),
+ frg_pdu(',', '0', '\r', '\n'),
+ data_end());
+
+ define_hf_test("/hfp_hf/test_corrupted_2", test_hf_unsolicited,
+ hf_result_handler, NULL,
+ raw_pdu('+', 'C', 'L', 'C', 'C', '\0'),
+ raw_pdu('+', 'C', 'L', 'C', 'C', '\r', '\n'),
+ data_end());
+
+ define_hf_test("/hfp_hf/test_empty", test_hf_robustness, NULL, NULL,
+ raw_pdu('\r'), data_end());
+
+ define_hf_test("/hfp_hf/test_unknown", test_hf_robustness, NULL, NULL,
+ raw_pdu('\r', '\n', 'B', 'R', '\r', '\n'),
+ data_end());
+
return g_test_run();
}
--
1.8.4
^ permalink raw reply related
* [PATCH v5 10/11] unit/test-hfp: Add tests for unsolicited results for HFP HF
From: Lukasz Rymanowski @ 2014-10-24 11:59 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Lukasz Rymanowski
In-Reply-To: <1414151975-20588-1-git-send-email-lukasz.rymanowski@tieto.com>
This patch adds three test case:
/hfp_hf/test_unsolicited_1
/hfp_hf/test_unsolicited_2
/hfp_hf/test_unsolicited_3
---
unit/test-hfp.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 60 insertions(+)
diff --git a/unit/test-hfp.c b/unit/test-hfp.c
index 3c25691..ab695d7 100644
--- a/unit/test-hfp.c
+++ b/unit/test-hfp.c
@@ -527,6 +527,42 @@ static void test_hf_send_command(gconstpointer data)
execute_context(context);
}
+static void hf_result_handler(struct hfp_hf_result *result,
+ void *user_data)
+{
+ struct context *context = user_data;
+
+ hfp_hf_disconnect(context->hfp_hf);
+}
+
+static void test_hf_unsolicited(gconstpointer data)
+{
+ struct context *context = create_context(data);
+ bool ret;
+
+ context->hfp_hf = hfp_hf_new(context->fd_client);
+ g_assert(context->hfp_hf);
+
+ ret = hfp_hf_set_close_on_unref(context->hfp_hf, true);
+ g_assert(ret);
+
+ if (context->data->hf_result_func) {
+ const struct test_pdu *pdu;
+
+ pdu = &context->data->pdu_list[context->pdu_offset++];
+
+ ret = hfp_hf_register(context->hfp_hf,
+ context->data->hf_result_func,
+ (char *)pdu->data, context,
+ NULL);
+ g_assert(ret);
+ }
+
+ send_pdu(context);
+
+ execute_context(context);
+}
+
int main(int argc, char *argv[])
{
g_test_init(&argc, &argv, NULL);
@@ -614,5 +650,29 @@ int main(int argc, char *argv[])
frg_pdu('\r', '\n', 'O', 'k', '\r', '\n'),
data_end());
+ define_hf_test("/hfp_hf/test_unsolicited_1", test_hf_unsolicited,
+ hf_result_handler, NULL,
+ raw_pdu('+', 'C', 'L', 'C', 'C', '\0'),
+ frg_pdu('\r', '\n', '+', 'C', 'L', 'C'),
+ frg_pdu('C', '\r', '\n'),
+ data_end());
+
+ define_hf_test("/hfp_hf/test_unsolicited_2", test_hf_unsolicited,
+ hf_result_handler, NULL,
+ raw_pdu('+', 'C', 'L', 'C', 'C', '\0'),
+ frg_pdu('\r', '\n', '+', 'C', 'L', 'C', 'C', ':', '1'),
+ frg_pdu(',', '3', ',', '0', '\r', '\n'),
+ data_end());
+
+ define_hf_test("/hfp_hf/test_unsolicited_3", test_hf_unsolicited,
+ hf_result_handler, NULL,
+ raw_pdu('+', 'C', 'L', 'C', 'C', '\0'),
+ frg_pdu('\r'), frg_pdu('\n'), frg_pdu('+'),
+ frg_pdu('C'), frg_pdu('L'), frg_pdu('C'), frg_pdu('C'),
+ frg_pdu(':'), frg_pdu('1'), frg_pdu(','), frg_pdu('3'),
+ frg_pdu(','), frg_pdu('0'), frg_pdu('\r'),
+ frg_pdu('\n'),
+ data_end());
+
return g_test_run();
}
--
1.8.4
^ permalink raw reply related
* [PATCH v5 09/11] unit/test-hfp: Add send command tests for HFP HF
From: Lukasz Rymanowski @ 2014-10-24 11:59 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Lukasz Rymanowski
In-Reply-To: <1414151975-20588-1-git-send-email-lukasz.rymanowski@tieto.com>
This patch adds following tests:
/hfp_hf/test_send_command_1
/hfp_hf/test_send_command_2
---
unit/test-hfp.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 74 insertions(+)
diff --git a/unit/test-hfp.c b/unit/test-hfp.c
index 1a8548e..3c25691 100644
--- a/unit/test-hfp.c
+++ b/unit/test-hfp.c
@@ -468,6 +468,65 @@ static void test_hf_init(gconstpointer data)
execute_context(context);
}
+static bool unsolicited_resp = false;
+
+static void hf_unsolicited_resp_cb(struct hfp_hf_result *result,
+ void *user_data) {
+ unsolicited_resp = true;
+}
+
+static void hf_response_with_data(enum hfp_result res,
+ void *user_data)
+{
+ struct context *context = user_data;
+
+ g_assert(unsolicited_resp);
+ unsolicited_resp = false;
+
+ hfp_hf_disconnect(context->hfp_hf);
+}
+
+static void hf_response_cb(enum hfp_result res, void *user_data)
+{
+ struct context *context = user_data;
+
+ hfp_hf_disconnect(context->hfp_hf);
+}
+
+static void test_hf_send_command(gconstpointer data)
+{
+ struct context *context = create_context(data);
+ const struct test_pdu *pdu;
+ bool ret;
+
+ context->hfp_hf = hfp_hf_new(context->fd_client);
+ g_assert(context->hfp_hf);
+
+ ret = hfp_hf_set_close_on_unref(context->hfp_hf, true);
+ g_assert(ret);
+
+ if (context->data->response_func) {
+ if (context->data->hf_result_func) {
+ pdu = &context->data->pdu_list[context->pdu_offset++];
+
+ ret = hfp_hf_register(context->hfp_hf,
+ context->data->hf_result_func,
+ (char *)pdu->data,
+ NULL, NULL);
+ g_assert(ret);
+ }
+
+ pdu = &context->data->pdu_list[context->pdu_offset++];
+
+ ret = hfp_hf_send_command(context->hfp_hf,
+ context->data->response_func,
+ context, (char *)pdu->data);
+ g_assert(ret);
+ }
+
+ execute_context(context);
+}
+
int main(int argc, char *argv[])
{
g_test_init(&argc, &argv, NULL);
@@ -539,6 +598,21 @@ int main(int argc, char *argv[])
define_hf_test("/hfp_hf/test_init", test_hf_init, NULL, NULL,
data_end());
+ define_hf_test("/hfp_hf/test_send_command_1", test_hf_send_command,
+ NULL, hf_response_cb,
+ raw_pdu('A', 'T', '+', 'B', 'R', 'S', 'F', '\0'),
+ raw_pdu('\r', '\n', 'O', 'k', '\r', '\n'),
+ data_end());
+
+ define_hf_test("/hfp_hf/test_send_command_2", test_hf_send_command,
+ hf_unsolicited_resp_cb,
+ hf_response_with_data,
+ raw_pdu('+', 'B', 'R', 'S', 'F', '\0'),
+ raw_pdu('A', 'T', '+', 'B', 'R', 'S', 'F', '\0'),
+ frg_pdu('\r', '\n', '+', 'B', 'R', 'S', 'F', '\r',
+ '\n'),
+ frg_pdu('\r', '\n', 'O', 'k', '\r', '\n'),
+ data_end());
return g_test_run();
}
--
1.8.4
^ permalink raw reply related
* [PATCH v5 08/11] unit/test-hfp: Add init test for HFP HF
From: Lukasz Rymanowski @ 2014-10-24 11:59 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Lukasz Rymanowski
In-Reply-To: <1414151975-20588-1-git-send-email-lukasz.rymanowski@tieto.com>
This patch adds basic infrastruction for HFP HF test plus
init test.
It also moves send_pdu function in the file so it can be used by
test_hf_handler
---
unit/test-hfp.c | 103 ++++++++++++++++++++++++++++++++++++++++++++++----------
1 file changed, 85 insertions(+), 18 deletions(-)
diff --git a/unit/test-hfp.c b/unit/test-hfp.c
index 4b3473b..1a8548e 100644
--- a/unit/test-hfp.c
+++ b/unit/test-hfp.c
@@ -36,6 +36,7 @@ struct context {
int fd_server;
int fd_client;
struct hfp_gw *hfp;
+ struct hfp_hf *hfp_hf;
const struct test_data *data;
unsigned int pdu_offset;
};
@@ -52,6 +53,8 @@ struct test_data {
char *test_name;
struct test_pdu *pdu_list;
hfp_result_func_t result_func;
+ hfp_response_func_t response_func;
+ hfp_hf_result_func_t hf_result_func;
GIOFunc test_handler;
};
@@ -99,6 +102,22 @@ struct test_data {
data.test_handler = test_handler; \
} while (0)
+#define define_hf_test(name, function, result_func, response_function, \
+ args...)\
+ do { \
+ const struct test_pdu pdus[] = { \
+ args, { } \
+ }; \
+ static struct test_data data; \
+ data.test_name = g_strdup(name); \
+ data.pdu_list = g_malloc(sizeof(pdus)); \
+ data.hf_result_func = result_func; \
+ data.response_func = response_function; \
+ memcpy(data.pdu_list, pdus, sizeof(pdus)); \
+ g_test_add_data_func(name, &data, function); \
+ data.test_handler = test_hf_handler; \
+ } while (0)
+
static void context_quit(struct context *context)
{
g_main_loop_quit(context->main_loop);
@@ -128,6 +147,52 @@ static gboolean test_handler(GIOChannel *channel, GIOCondition cond,
return FALSE;
}
+static gboolean send_pdu(gpointer user_data)
+{
+ struct context *context = user_data;
+ const struct test_pdu *pdu;
+ ssize_t len;
+
+ pdu = &context->data->pdu_list[context->pdu_offset++];
+
+ if (pdu && !pdu->valid)
+ return FALSE;
+
+ len = write(context->fd_server, pdu->data, pdu->size);
+ g_assert_cmpint(len, ==, pdu->size);
+
+ pdu = &context->data->pdu_list[context->pdu_offset];
+ if (pdu->fragmented)
+ g_idle_add(send_pdu, context);
+
+ return FALSE;
+}
+
+static gboolean test_hf_handler(GIOChannel *channel, GIOCondition cond,
+ gpointer user_data)
+{
+ struct context *context = user_data;
+ gchar buf[60];
+ gsize bytes_read;
+ GError *error = NULL;
+
+ if (cond & (G_IO_HUP | G_IO_ERR | G_IO_NVAL))
+ goto done;
+
+ /* dummy read */
+ g_io_channel_read_chars(channel, buf, 60, &bytes_read, &error);
+
+ send_pdu(context);
+
+ return TRUE;
+
+done:
+ context_quit(context);
+ context->watch_id = 0;
+
+ return FALSE;
+}
+
static void cmd_handler(const char *command, void *user_data)
{
struct context *context = user_data;
@@ -203,6 +268,9 @@ static void execute_context(struct context *context)
if (context->hfp)
hfp_gw_unref(context->hfp);
+ if (context->hfp_hf)
+ hfp_hf_unref(context->hfp_hf);
+
g_free(context);
}
@@ -275,24 +343,6 @@ static void test_register(gconstpointer data)
execute_context(context);
}
-static gboolean send_pdu(gpointer user_data)
-{
- struct context *context = user_data;
- const struct test_pdu *pdu;
- ssize_t len;
-
- pdu = &context->data->pdu_list[context->pdu_offset++];
-
- len = write(context->fd_server, pdu->data, pdu->size);
- g_assert_cmpint(len, ==, pdu->size);
-
- pdu = &context->data->pdu_list[context->pdu_offset];
- if (pdu->fragmented)
- g_idle_add(send_pdu, context);
-
- return FALSE;
-}
-
static void test_fragmented(gconstpointer data)
{
struct context *context = create_context(data);
@@ -404,6 +454,20 @@ static void check_string_2(struct hfp_gw_result *result,
hfp_gw_send_result(context->hfp, HFP_RESULT_ERROR);
}
+static void test_hf_init(gconstpointer data)
+{
+ struct context *context = create_context(data);
+
+ context->hfp_hf = hfp_hf_new(context->fd_client);
+ g_assert(context->hfp_hf);
+ g_assert(hfp_hf_set_close_on_unref(context->hfp_hf, true));
+
+ hfp_hf_unref(context->hfp_hf);
+ context->hfp_hf = NULL;
+
+ execute_context(context);
+}
+
int main(int argc, char *argv[])
{
g_test_init(&argc, &argv, NULL);
@@ -473,5 +537,8 @@ int main(int argc, char *argv[])
raw_pdu('\r'),
data_end());
+ define_hf_test("/hfp_hf/test_init", test_hf_init, NULL, NULL,
+ data_end());
+
return g_test_run();
}
--
1.8.4
^ permalink raw reply related
* [PATCH v5 07/11] unit/test-hfp: Provide test_handler function via struct data
From: Lukasz Rymanowski @ 2014-10-24 11:59 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Lukasz Rymanowski
In-Reply-To: <1414151975-20588-1-git-send-email-lukasz.rymanowski@tieto.com>
This patch allows us to use user defined test handler depends on needs.
Will use it in following patches which implements tests for HFP HF.
---
unit/test-hfp.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/unit/test-hfp.c b/unit/test-hfp.c
index a8801b0..4b3473b 100644
--- a/unit/test-hfp.c
+++ b/unit/test-hfp.c
@@ -52,6 +52,7 @@ struct test_data {
char *test_name;
struct test_pdu *pdu_list;
hfp_result_func_t result_func;
+ GIOFunc test_handler;
};
#define data(args...) ((const unsigned char[]) { args })
@@ -95,6 +96,7 @@ struct test_data {
data.result_func = result_function; \
memcpy(data.pdu_list, pdus, sizeof(pdus)); \
g_test_add_data_func(name, &data, function); \
+ data.test_handler = test_handler; \
} while (0)
static void context_quit(struct context *context)
@@ -158,6 +160,7 @@ static struct context *create_context(gconstpointer data)
struct context *context = g_new0(struct context, 1);
GIOChannel *channel;
int err, sv[2];
+ const struct test_data *d = data;
context->main_loop = g_main_loop_new(NULL, FALSE);
g_assert(context->main_loop);
@@ -173,7 +176,8 @@ static struct context *create_context(gconstpointer data)
context->watch_id = g_io_add_watch(channel,
G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
- test_handler, context);
+ d->test_handler, context);
+
g_assert(context->watch_id > 0);
g_io_channel_unref(channel);
--
1.8.4
^ permalink raw reply related
* [PATCH v5 06/11] shared/hfp: Add send AT command API for HFP HF
From: Lukasz Rymanowski @ 2014-10-24 11:59 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Lukasz Rymanowski
In-Reply-To: <1414151975-20588-1-git-send-email-lukasz.rymanowski@tieto.com>
This patch adds handling send and response of AT command.
Note that we always wait for AT command response before sending next
command, however user can fill hfp_hf with more than one command.
All the commands are queued and send one by one.
---
src/shared/hfp.c | 162 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/shared/hfp.h | 6 +++
2 files changed, 168 insertions(+)
diff --git a/src/shared/hfp.c b/src/shared/hfp.c
index 37a18d9..eb6bf4e 100644
--- a/src/shared/hfp.c
+++ b/src/shared/hfp.c
@@ -70,6 +70,9 @@ struct hfp_hf {
struct ringbuf *read_buf;
struct ringbuf *write_buf;
+ bool writer_active;
+ struct queue *cmd_queue;
+
struct queue *event_handlers;
hfp_debug_func_t debug_callback;
@@ -101,6 +104,13 @@ struct hfp_hf_result {
unsigned int offset;
};
+struct cmd_response {
+ hfp_response_func_t resp_cb;
+ struct hfp_hf_result *response;
+ char *resp_data;
+ void *user_data;
+};
+
struct event_handler {
char *prefix;
void *user_data;
@@ -865,17 +875,95 @@ static void destroy_event_handler(void *data)
free(handler);
}
+static bool hf_can_write_data(struct io *io, void *user_data)
+{
+ struct hfp_hf *hfp = user_data;
+ ssize_t bytes_written;
+
+ bytes_written = ringbuf_write(hfp->write_buf, hfp->fd);
+ if (bytes_written < 0)
+ return false;
+
+ if (ringbuf_len(hfp->write_buf) > 0)
+ return true;
+
+ return false;
+}
+
+static void hf_write_watch_destroy(void *user_data)
+{
+ struct hfp_hf *hfp = user_data;
+
+ hfp->writer_active = false;
+}
+
static void hf_skip_whitespace(struct hfp_hf_result *result)
{
while (result->data[result->offset] == ' ')
result->offset++;
}
+static bool is_response(const char *prefix, enum hfp_result *result)
+{
+ if (strcmp(prefix, "OK") == 0) {
+ *result = HFP_RESULT_OK;
+ return true;
+ }
+
+ if (strcmp(prefix, "ERROR") == 0) {
+ *result = HFP_RESULT_ERROR;
+ return true;
+ }
+
+ if (strcmp(prefix, "NO CARRIER") == 0) {
+ *result = HFP_RESULT_NO_CARRIER;
+ return true;
+ }
+
+ if (strcmp(prefix, "NO ANSWER") == 0) {
+ *result = HFP_RESULT_NO_ANSWER;
+ return true;
+ }
+
+ if (strcmp(prefix, "BUSY") == 0) {
+ *result = HFP_RESULT_BUSY;
+ return true;
+ }
+
+ if (strcmp(prefix, "DELAYED") == 0) {
+ *result = HFP_RESULT_DELAYED;
+ return true;
+ }
+
+ if (strcmp(prefix, "BLACKLISTED") == 0) {
+ *result = HFP_RESULT_BLACKLISTED;
+ return true;
+ }
+
+ return false;
+}
+
+static void hf_wakeup_writer(struct hfp_hf *hfp)
+{
+ if (hfp->writer_active)
+ return;
+
+ if (!ringbuf_len(hfp->write_buf))
+ return;
+
+ if (!io_set_write_handler(hfp->io, hf_can_write_data,
+ hfp, hf_write_watch_destroy))
+ return;
+
+ hfp->writer_active = true;
+}
+
static void hf_call_prefix_handler(struct hfp_hf *hfp, const char *data)
{
struct event_handler *handler;
const char *separators = ";:\0";
struct hfp_hf_result result_data;
+ enum hfp_result result;
char lookup_prefix[18];
uint8_t pref_len = 0;
const char *prefix;
@@ -901,6 +989,22 @@ static void hf_call_prefix_handler(struct hfp_hf *hfp, const char *data)
lookup_prefix[pref_len] = '\0';
result_data.offset += pref_len + 1;
+ if (is_response(lookup_prefix, &result)) {
+ struct cmd_response *cmd;
+
+ cmd = queue_peek_head(hfp->cmd_queue);
+ if (!cmd)
+ return;
+
+ cmd->resp_cb(result, cmd->user_data);
+
+ queue_remove(hfp->cmd_queue, cmd);
+ free(cmd);
+
+ hf_wakeup_writer(hfp);
+ return;
+ }
+
handler = queue_find(hfp->event_handlers, match_handler_event_prefix,
lookup_prefix);
if (!handler)
@@ -1073,6 +1177,18 @@ struct hfp_hf *hfp_hf_new(int fd)
return NULL;
}
+ hfp->cmd_queue = queue_new();
+ if (!hfp->cmd_queue) {
+ io_destroy(hfp->io);
+ ringbuf_free(hfp->write_buf);
+ ringbuf_free(hfp->read_buf);
+ queue_destroy(hfp->event_handlers, NULL);
+ free(hfp);
+ return NULL;
+ }
+
+ hfp->writer_active = false;
+
if (!io_set_read_handler(hfp->io, hf_can_read_data, hfp,
read_watch_destroy)) {
queue_destroy(hfp->event_handlers,
@@ -1126,6 +1242,9 @@ void hfp_hf_unref(struct hfp_hf *hfp)
queue_destroy(hfp->event_handlers, destroy_event_handler);
hfp->event_handlers = NULL;
+ queue_destroy(hfp->cmd_queue, free);
+ hfp->cmd_queue = NULL;
+
if (!hfp->in_disconnect) {
free(hfp);
return;
@@ -1185,6 +1304,49 @@ bool hfp_hf_set_close_on_unref(struct hfp_hf *hfp, bool do_close)
return true;
}
+bool hfp_hf_send_command(struct hfp_hf *hfp, hfp_response_func_t resp_cb,
+ void *user_data, const char *format, ...)
+{
+ va_list ap;
+ char *fmt;
+ int len;
+ struct cmd_response *cmd;
+
+ if (!hfp || !format || !resp_cb)
+ return false;
+
+ if (asprintf(&fmt, "%s\r", format) < 0)
+ return false;
+
+ cmd = new0(struct cmd_response, 1);
+ if (!cmd)
+ return false;
+
+ va_start(ap, format);
+ len = ringbuf_vprintf(hfp->write_buf, fmt, ap);
+ va_end(ap);
+
+ free(fmt);
+
+ if (len < 0) {
+ free(cmd);
+ return false;
+ }
+
+ cmd->resp_cb = resp_cb;
+ cmd->user_data = user_data;
+
+ if (!queue_push_tail(hfp->cmd_queue, cmd)) {
+ ringbuf_drain(hfp->write_buf, len);
+ free(cmd);
+ return false;
+ }
+
+ hf_wakeup_writer(hfp);
+
+ return true;
+}
+
bool hfp_hf_register(struct hfp_hf *hfp, hfp_hf_result_func_t callback,
const char *prefix,
void *user_data,
diff --git a/src/shared/hfp.h b/src/shared/hfp.h
index 3860e25..1467c62 100644
--- a/src/shared/hfp.h
+++ b/src/shared/hfp.h
@@ -32,6 +32,8 @@ enum hfp_result {
HFP_RESULT_NO_DIALTONE = 6,
HFP_RESULT_BUSY = 7,
HFP_RESULT_NO_ANSWER = 8,
+ HFP_RESULT_DELAYED = 9,
+ HFP_RESULT_BLACKLISTED = 10,
};
enum hfp_error {
@@ -130,6 +132,8 @@ struct hfp_hf_result;
typedef void (*hfp_hf_result_func_t)(struct hfp_hf_result *result,
void *user_data);
+typedef void (*hfp_response_func_t)(enum hfp_result result, void *user_data);
+
struct hfp_hf;
struct hfp_hf *hfp_hf_new(int fd);
@@ -148,3 +152,5 @@ bool hfp_hf_register(struct hfp_hf *hfp, hfp_hf_result_func_t callback,
const char *prefix, void *user_data,
hfp_destroy_func_t destroy);
bool hfp_hf_unregister(struct hfp_hf *hfp, const char *prefix);
+bool hfp_hf_send_command(struct hfp_hf *hfp, hfp_response_func_t resp_cb,
+ void *user_data, const char *format, ...);
--
1.8.4
^ permalink raw reply related
* [PATCH v5 05/11] shared/hfp: Add HFP HF parser
From: Lukasz Rymanowski @ 2014-10-24 11:59 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Lukasz Rymanowski
In-Reply-To: <1414151975-20588-1-git-send-email-lukasz.rymanowski@tieto.com>
This patch adds parser for AT responses and unsolicited results.
---
src/shared/hfp.c | 175 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 175 insertions(+)
diff --git a/src/shared/hfp.c b/src/shared/hfp.c
index 84c0db1..37a18d9 100644
--- a/src/shared/hfp.c
+++ b/src/shared/hfp.c
@@ -865,6 +865,170 @@ static void destroy_event_handler(void *data)
free(handler);
}
+static void hf_skip_whitespace(struct hfp_hf_result *result)
+{
+ while (result->data[result->offset] == ' ')
+ result->offset++;
+}
+
+static void hf_call_prefix_handler(struct hfp_hf *hfp, const char *data)
+{
+ struct event_handler *handler;
+ const char *separators = ";:\0";
+ struct hfp_hf_result result_data;
+ char lookup_prefix[18];
+ uint8_t pref_len = 0;
+ const char *prefix;
+ int i;
+
+ result_data.offset = 0;
+ result_data.data = data;
+
+ hf_skip_whitespace(&result_data);
+
+ if (strlen(data + result_data.offset) < 2)
+ return;
+
+ prefix = data + result_data.offset;
+
+ pref_len = strcspn(prefix, separators);
+ if (pref_len > 17 || pref_len < 2)
+ return;
+
+ for (i = 0; i < pref_len; i++)
+ lookup_prefix[i] = toupper(prefix[i]);
+
+ lookup_prefix[pref_len] = '\0';
+ result_data.offset += pref_len + 1;
+
+ handler = queue_find(hfp->event_handlers, match_handler_event_prefix,
+ lookup_prefix);
+ if (!handler)
+ return;
+
+ handler->callback(&result_data, handler->user_data);
+}
+
+static char *find_cr_lf(char *str, size_t len)
+{
+ char *ptr;
+ size_t count, offset;
+
+ offset = 0;
+
+ ptr = memchr(str, '\r', len);
+ while (ptr) {
+ /*
+ * Check if there is more data after '\r'. If so check for
+ * '\n'
+ */
+ count = ptr - str;
+ if ((count < (len - 1)) && *(ptr + 1) == '\n')
+ return ptr;
+
+ /* There is only '\r'? Let's try to find next one */
+ offset += count + 1;
+
+ if (offset >= len)
+ return NULL;
+
+ ptr = memchr(str + offset, '\r', len - offset);
+ }
+
+ return NULL;
+}
+
+static void hf_process_input(struct hfp_hf *hfp)
+{
+ char *str, *ptr, *str2, *tmp;
+ size_t len, count, offset, len2;
+ bool free_tmp = false;
+
+ str = ringbuf_peek(hfp->read_buf, 0, &len);
+ if (!str)
+ return;
+
+ offset = 0;
+
+ ptr = find_cr_lf(str, len);
+ while (ptr) {
+ count = ptr - (str + offset);
+ if (count == 0) {
+ /* 2 is for <cr><lf> */
+ offset += 2;
+ } else {
+ *ptr = '\0';
+ hf_call_prefix_handler(hfp, str + offset);
+ offset += count + 2;
+ }
+
+ ptr = find_cr_lf(str + offset, len - offset);
+ }
+
+ /*
+ * Just check if there is no wrapped data in ring buffer.
+ * Should not happen too often
+ */
+ if (len == ringbuf_len(hfp->read_buf))
+ goto done;
+
+ /* If we are here second time for some reason, that is wrong */
+ if (free_tmp)
+ goto done;
+
+ str2 = ringbuf_peek(hfp->read_buf, len, &len2);
+ if (!str2)
+ goto done;
+
+ ptr = find_cr_lf(str2, len2);
+ if (!ptr) {
+ /* Might happen that we wrap between \r and \n */
+ ptr = memchr(str2, '\n', len2);
+ if (!ptr)
+ goto done;
+ }
+
+ count = ptr - str2;
+
+ if (count) {
+ *ptr = '\0';
+
+ tmp = malloc(len + count);
+
+ /* "str" here is not a string so we need to use memcpy */
+ memcpy(tmp, str, len);
+ memcpy(tmp + len, str2, count);
+
+ free_tmp = true;
+ } else {
+ str[len-1] = '\0';
+ tmp = str;
+ }
+
+ hf_call_prefix_handler(hfp, tmp);
+ offset += count;
+
+done:
+ ringbuf_drain(hfp->read_buf, offset);
+
+ if (free_tmp)
+ free(tmp);
+}
+
+static bool hf_can_read_data(struct io *io, void *user_data)
+{
+ struct hfp_hf *hfp = user_data;
+ ssize_t bytes_read;
+
+ bytes_read = ringbuf_read(hfp->read_buf, hfp->fd);
+ if (bytes_read < 0)
+ return false;
+
+ hf_process_input(hfp);
+
+ return true;
+}
+
struct hfp_hf *hfp_hf_new(int fd)
{
struct hfp_hf *hfp;
@@ -909,6 +1073,17 @@ struct hfp_hf *hfp_hf_new(int fd)
return NULL;
}
+ if (!io_set_read_handler(hfp->io, hf_can_read_data, hfp,
+ read_watch_destroy)) {
+ queue_destroy(hfp->event_handlers,
+ destroy_event_handler);
+ io_destroy(hfp->io);
+ ringbuf_free(hfp->write_buf);
+ ringbuf_free(hfp->read_buf);
+ free(hfp);
+ return NULL;
+ }
+
return hfp_hf_ref(hfp);
}
--
1.8.4
^ permalink raw reply related
* [PATCH v5 04/11] shared/hfp: Add register/unregister event for HFP HF
From: Lukasz Rymanowski @ 2014-10-24 11:59 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Lukasz Rymanowski
In-Reply-To: <1414151975-20588-1-git-send-email-lukasz.rymanowski@tieto.com>
---
src/shared/hfp.c | 100 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/shared/hfp.h | 9 +++++
2 files changed, 109 insertions(+)
diff --git a/src/shared/hfp.c b/src/shared/hfp.c
index b7855ed..84c0db1 100644
--- a/src/shared/hfp.c
+++ b/src/shared/hfp.c
@@ -70,6 +70,8 @@ struct hfp_hf {
struct ringbuf *read_buf;
struct ringbuf *write_buf;
+ struct queue *event_handlers;
+
hfp_debug_func_t debug_callback;
hfp_destroy_func_t debug_destroy;
void *debug_data;
@@ -94,6 +96,18 @@ struct hfp_gw_result {
unsigned int offset;
};
+struct hfp_hf_result {
+ const char *data;
+ unsigned int offset;
+};
+
+struct event_handler {
+ char *prefix;
+ void *user_data;
+ hfp_destroy_func_t destroy;
+ hfp_hf_result_func_t callback;
+};
+
static void destroy_cmd_handler(void *data)
{
struct cmd_handler *handler = data;
@@ -828,6 +842,29 @@ bool hfp_gw_disconnect(struct hfp_gw *hfp)
return io_shutdown(hfp->io);
}
+static bool match_handler_event_prefix(const void *a, const void *b)
+{
+ const struct event_handler *handler = a;
+ const char *prefix = b;
+
+ if (memcmp(handler->prefix, prefix, strlen(prefix)))
+ return false;
+
+ return true;
+}
+
+static void destroy_event_handler(void *data)
+{
+ struct event_handler *handler = data;
+
+ if (handler->destroy)
+ handler->destroy(handler->user_data);
+
+ free(handler->prefix);
+
+ free(handler);
+}
+
struct hfp_hf *hfp_hf_new(int fd)
{
struct hfp_hf *hfp;
@@ -863,6 +900,15 @@ struct hfp_hf *hfp_hf_new(int fd)
return NULL;
}
+ hfp->event_handlers = queue_new();
+ if (!hfp->event_handlers) {
+ io_destroy(hfp->io);
+ ringbuf_free(hfp->write_buf);
+ ringbuf_free(hfp->read_buf);
+ free(hfp);
+ return NULL;
+ }
+
return hfp_hf_ref(hfp);
}
@@ -902,6 +948,9 @@ void hfp_hf_unref(struct hfp_hf *hfp)
ringbuf_free(hfp->write_buf);
hfp->write_buf = NULL;
+ queue_destroy(hfp->event_handlers, destroy_event_handler);
+ hfp->event_handlers = NULL;
+
if (!hfp->in_disconnect) {
free(hfp);
return;
@@ -961,6 +1010,57 @@ bool hfp_hf_set_close_on_unref(struct hfp_hf *hfp, bool do_close)
return true;
}
+bool hfp_hf_register(struct hfp_hf *hfp, hfp_hf_result_func_t callback,
+ const char *prefix,
+ void *user_data,
+ hfp_destroy_func_t destroy)
+{
+ struct event_handler *handler;
+
+ if (!callback)
+ return false;
+
+ handler = new0(struct event_handler, 1);
+ if (!handler)
+ return false;
+
+ handler->callback = callback;
+ handler->user_data = user_data;
+
+ handler->prefix = strdup(prefix);
+ if (!handler->prefix) {
+ free(handler);
+ return false;
+ }
+
+ if (queue_find(hfp->event_handlers, match_handler_event_prefix,
+ handler->prefix)) {
+ destroy_event_handler(handler);
+ return false;
+ }
+
+ handler->destroy = destroy;
+
+ return queue_push_tail(hfp->event_handlers, handler);
+}
+
+bool hfp_hf_unregister(struct hfp_hf *hfp, const char *prefix)
+{
+ struct cmd_handler *handler;
+
+ /* Cast to void as queue_remove needs that */
+ handler = queue_remove_if(hfp->event_handlers,
+ match_handler_event_prefix,
+ (void *) prefix);
+
+ if (!handler)
+ return false;
+
+ destroy_event_handler(handler);
+
+ return true;
+}
+
static void hf_disconnect_watch_destroy(void *user_data)
{
struct hfp_hf *hfp = user_data;
diff --git a/src/shared/hfp.h b/src/shared/hfp.h
index d98d14b..3860e25 100644
--- a/src/shared/hfp.h
+++ b/src/shared/hfp.h
@@ -125,6 +125,11 @@ bool hfp_gw_result_get_unquoted_string(struct hfp_gw_result *result, char *buf,
uint8_t len);
bool hfp_gw_result_has_next(struct hfp_gw_result *result);
+struct hfp_hf_result;
+
+typedef void (*hfp_hf_result_func_t)(struct hfp_hf_result *result,
+ void *user_data);
+
struct hfp_hf;
struct hfp_hf *hfp_hf_new(int fd);
@@ -139,3 +144,7 @@ bool hfp_hf_set_disconnect_handler(struct hfp_hf *hfp,
void *user_data,
hfp_destroy_func_t destroy);
bool hfp_hf_disconnect(struct hfp_hf *hfp);
+bool hfp_hf_register(struct hfp_hf *hfp, hfp_hf_result_func_t callback,
+ const char *prefix, void *user_data,
+ hfp_destroy_func_t destroy);
+bool hfp_hf_unregister(struct hfp_hf *hfp, const char *prefix);
--
1.8.4
^ permalink raw reply related
* [PATCH v5 03/11] shared/hfp: Add set disconnect handler and disconnect API to HFP HF
From: Lukasz Rymanowski @ 2014-10-24 11:59 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Lukasz Rymanowski
In-Reply-To: <1414151975-20588-1-git-send-email-lukasz.rymanowski@tieto.com>
---
src/shared/hfp.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/shared/hfp.h | 5 +++++
2 files changed, 68 insertions(+)
diff --git a/src/shared/hfp.c b/src/shared/hfp.c
index ad2daa2..b7855ed 100644
--- a/src/shared/hfp.c
+++ b/src/shared/hfp.c
@@ -74,6 +74,10 @@ struct hfp_hf {
hfp_destroy_func_t debug_destroy;
void *debug_data;
+ hfp_disconnect_func_t disconnect_callback;
+ hfp_destroy_func_t disconnect_destroy;
+ void *disconnect_data;
+
bool in_disconnect;
bool destroyed;
};
@@ -956,3 +960,62 @@ bool hfp_hf_set_close_on_unref(struct hfp_hf *hfp, bool do_close)
return true;
}
+
+static void hf_disconnect_watch_destroy(void *user_data)
+{
+ struct hfp_hf *hfp = user_data;
+
+ if (hfp->disconnect_destroy)
+ hfp->disconnect_destroy(hfp->disconnect_data);
+
+ if (hfp->destroyed)
+ free(hfp);
+}
+
+static bool hf_io_disconnected(struct io *io, void *user_data)
+{
+ struct hfp_hf *hfp = user_data;
+
+ hfp->in_disconnect = true;
+
+ if (hfp->disconnect_callback)
+ hfp->disconnect_callback(hfp->disconnect_data);
+
+ hfp->in_disconnect = false;
+
+ return false;
+}
+
+bool hfp_hf_set_disconnect_handler(struct hfp_hf *hfp,
+ hfp_disconnect_func_t callback,
+ void *user_data,
+ hfp_destroy_func_t destroy)
+{
+ if (!hfp)
+ return false;
+
+ if (hfp->disconnect_destroy)
+ hfp->disconnect_destroy(hfp->disconnect_data);
+
+ if (!io_set_disconnect_handler(hfp->io, hf_io_disconnected, hfp,
+ hf_disconnect_watch_destroy)) {
+ hfp->disconnect_callback = NULL;
+ hfp->disconnect_destroy = NULL;
+ hfp->disconnect_data = NULL;
+ return false;
+ }
+
+ hfp->disconnect_callback = callback;
+ hfp->disconnect_destroy = destroy;
+ hfp->disconnect_data = user_data;
+
+ return true;
+}
+
+bool hfp_hf_disconnect(struct hfp_hf *hfp)
+{
+ if (!hfp)
+ return false;
+
+ return io_shutdown(hfp->io);
+}
diff --git a/src/shared/hfp.h b/src/shared/hfp.h
index 21d205b..d98d14b 100644
--- a/src/shared/hfp.h
+++ b/src/shared/hfp.h
@@ -134,3 +134,8 @@ void hfp_hf_unref(struct hfp_hf *hfp);
bool hfp_hf_set_debug(struct hfp_hf *hfp, hfp_debug_func_t callback,
void *user_data, hfp_destroy_func_t destroy);
bool hfp_hf_set_close_on_unref(struct hfp_hf *hfp, bool do_close);
+bool hfp_hf_set_disconnect_handler(struct hfp_hf *hfp,
+ hfp_disconnect_func_t callback,
+ void *user_data,
+ hfp_destroy_func_t destroy);
+bool hfp_hf_disconnect(struct hfp_hf *hfp);
--
1.8.4
^ permalink raw reply related
* [PATCH v5 02/11] shared/hfp: Add set_debug and close_on_unref API for HFP HF
From: Lukasz Rymanowski @ 2014-10-24 11:59 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Lukasz Rymanowski
In-Reply-To: <1414151975-20588-1-git-send-email-lukasz.rymanowski@tieto.com>
---
src/shared/hfp.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/shared/hfp.h | 3 +++
2 files changed, 60 insertions(+)
diff --git a/src/shared/hfp.c b/src/shared/hfp.c
index dbd049a..ad2daa2 100644
--- a/src/shared/hfp.c
+++ b/src/shared/hfp.c
@@ -70,6 +70,10 @@ struct hfp_hf {
struct ringbuf *read_buf;
struct ringbuf *write_buf;
+ hfp_debug_func_t debug_callback;
+ hfp_destroy_func_t debug_destroy;
+ void *debug_data;
+
bool in_disconnect;
bool destroyed;
};
@@ -886,6 +890,8 @@ void hfp_hf_unref(struct hfp_hf *hfp)
if (hfp->close_on_unref)
close(hfp->fd);
+ hfp_hf_set_debug(hfp, NULL, NULL, NULL);
+
ringbuf_free(hfp->read_buf);
hfp->read_buf = NULL;
@@ -899,3 +905,54 @@ void hfp_hf_unref(struct hfp_hf *hfp)
hfp->destroyed = true;
}
+
+static void hf_read_tracing(const void *buf, size_t count,
+ void *user_data)
+{
+ struct hfp_hf *hfp = user_data;
+
+ util_hexdump('>', buf, count, hfp->debug_callback, hfp->debug_data);
+}
+
+static void hf_write_tracing(const void *buf, size_t count,
+ void *user_data)
+{
+ struct hfp_hf *hfp = user_data;
+
+ util_hexdump('<', buf, count, hfp->debug_callback, hfp->debug_data);
+}
+
+bool hfp_hf_set_debug(struct hfp_hf *hfp, hfp_debug_func_t callback,
+ void *user_data, hfp_destroy_func_t destroy)
+{
+ if (!hfp)
+ return false;
+
+ if (hfp->debug_destroy)
+ hfp->debug_destroy(hfp->debug_data);
+
+ hfp->debug_callback = callback;
+ hfp->debug_destroy = destroy;
+ hfp->debug_data = user_data;
+
+ if (hfp->debug_callback) {
+ ringbuf_set_input_tracing(hfp->read_buf, hf_read_tracing, hfp);
+ ringbuf_set_input_tracing(hfp->write_buf, hf_write_tracing,
+ hfp);
+ } else {
+ ringbuf_set_input_tracing(hfp->read_buf, NULL, NULL);
+ ringbuf_set_input_tracing(hfp->write_buf, NULL, NULL);
+ }
+
+ return true;
+}
+
+bool hfp_hf_set_close_on_unref(struct hfp_hf *hfp, bool do_close)
+{
+ if (!hfp)
+ return false;
+
+ hfp->close_on_unref = do_close;
+
+ return true;
+}
diff --git a/src/shared/hfp.h b/src/shared/hfp.h
index 0b57e2e..21d205b 100644
--- a/src/shared/hfp.h
+++ b/src/shared/hfp.h
@@ -131,3 +131,6 @@ struct hfp_hf *hfp_hf_new(int fd);
struct hfp_hf *hfp_hf_ref(struct hfp_hf *hfp);
void hfp_hf_unref(struct hfp_hf *hfp);
+bool hfp_hf_set_debug(struct hfp_hf *hfp, hfp_debug_func_t callback,
+ void *user_data, hfp_destroy_func_t destroy);
+bool hfp_hf_set_close_on_unref(struct hfp_hf *hfp, bool do_close);
--
1.8.4
^ permalink raw reply related
* [PATCH v5 01/11] shared/hfp: Add support for HFP HF
From: Lukasz Rymanowski @ 2014-10-24 11:59 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Lukasz Rymanowski
In-Reply-To: <1414151975-20588-1-git-send-email-lukasz.rymanowski@tieto.com>
This patch add struct hfp_hf plus fuctions to create an instance ref and
unref. This code based on existing hfp_gw
---
src/shared/hfp.c | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/shared/hfp.h | 7 +++++
2 files changed, 99 insertions(+)
diff --git a/src/shared/hfp.c b/src/shared/hfp.c
index efc981f..dbd049a 100644
--- a/src/shared/hfp.c
+++ b/src/shared/hfp.c
@@ -62,6 +62,18 @@ struct hfp_gw {
bool destroyed;
};
+struct hfp_hf {
+ int ref_count;
+ int fd;
+ bool close_on_unref;
+ struct io *io;
+ struct ringbuf *read_buf;
+ struct ringbuf *write_buf;
+
+ bool in_disconnect;
+ bool destroyed;
+};
+
struct cmd_handler {
char *prefix;
void *user_data;
@@ -807,3 +819,83 @@ bool hfp_gw_disconnect(struct hfp_gw *hfp)
return io_shutdown(hfp->io);
}
+
+struct hfp_hf *hfp_hf_new(int fd)
+{
+ struct hfp_hf *hfp;
+
+ if (fd < 0)
+ return NULL;
+
+ hfp = new0(struct hfp_hf, 1);
+ if (!hfp)
+ return NULL;
+
+ hfp->fd = fd;
+ hfp->close_on_unref = false;
+
+ hfp->read_buf = ringbuf_new(4096);
+ if (!hfp->read_buf) {
+ free(hfp);
+ return NULL;
+ }
+
+ hfp->write_buf = ringbuf_new(4096);
+ if (!hfp->write_buf) {
+ ringbuf_free(hfp->read_buf);
+ free(hfp);
+ return NULL;
+ }
+
+ hfp->io = io_new(fd);
+ if (!hfp->io) {
+ ringbuf_free(hfp->write_buf);
+ ringbuf_free(hfp->read_buf);
+ free(hfp);
+ return NULL;
+ }
+
+ return hfp_hf_ref(hfp);
+}
+
+struct hfp_hf *hfp_hf_ref(struct hfp_hf *hfp)
+{
+ if (!hfp)
+ return NULL;
+
+ __sync_fetch_and_add(&hfp->ref_count, 1);
+
+ return hfp;
+}
+
+void hfp_hf_unref(struct hfp_hf *hfp)
+{
+ if (!hfp)
+ return;
+
+ if (__sync_sub_and_fetch(&hfp->ref_count, 1))
+ return;
+
+ io_set_write_handler(hfp->io, NULL, NULL, NULL);
+ io_set_read_handler(hfp->io, NULL, NULL, NULL);
+ io_set_disconnect_handler(hfp->io, NULL, NULL, NULL);
+
+ io_destroy(hfp->io);
+ hfp->io = NULL;
+
+ if (hfp->close_on_unref)
+ close(hfp->fd);
+
+ ringbuf_free(hfp->read_buf);
+ hfp->read_buf = NULL;
+
+ ringbuf_free(hfp->write_buf);
+ hfp->write_buf = NULL;
+
+ if (!hfp->in_disconnect) {
+ free(hfp);
+ return;
+ }
+
+ hfp->destroyed = true;
+}
diff --git a/src/shared/hfp.h b/src/shared/hfp.h
index 743db65..0b57e2e 100644
--- a/src/shared/hfp.h
+++ b/src/shared/hfp.h
@@ -124,3 +124,10 @@ bool hfp_gw_result_get_string(struct hfp_gw_result *result, char *buf,
bool hfp_gw_result_get_unquoted_string(struct hfp_gw_result *result, char *buf,
uint8_t len);
bool hfp_gw_result_has_next(struct hfp_gw_result *result);
+
+struct hfp_hf;
+
+struct hfp_hf *hfp_hf_new(int fd);
+
+struct hfp_hf *hfp_hf_ref(struct hfp_hf *hfp);
+void hfp_hf_unref(struct hfp_hf *hfp);
--
1.8.4
^ permalink raw reply related
* [PATCH v5 00/11] shared/hfp: Add support for HFP HF
From: Lukasz Rymanowski @ 2014-10-24 11:59 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Lukasz Rymanowski
Following patches extends hfp API with HFP HF functionality.
HFP HF parser has been added and unit test for it.
To consider: how strict we should be when it comes to parsing
AT responses. For example, at the moment, command +CCLC:<cr><lf>
will be recognized as +CCLC: eventhough correct response format
should be <cr><lf>+CCLC:<cr><lf>
Note: As discussed on IRC I did not try to generalize code.
v2:
* minor self review fixes
* response callback on send command, contains now result (OK/ERROR) and
data from unsolicited response if available.
v3:
* Fix some memory leaks found on self review
v4:
* Fallback to approach from v1 in context of response callback for AT command.
Bassically, if AT+X has +X and OK response, response callback contains only OK or
ERROR code (including CME which will be added in following patches). To get +X
response, user need to use hfp_hf_register() API. It is done mostly to keep hfp.c
simple. With this approach we do not have to cache all +X in hfp.c before calling
response callback.
v5:
* Szymon comments taken into account
* Support to handle wrapped commands in ringbuffer. Note that for testing I used
modified buffer size in hfp but eventually unit test will be done for that.
Lukasz Rymanowski (11):
shared/hfp: Add support for HFP HF
shared/hfp: Add set_debug and close_on_unref API for HFP HF
shared/hfp: Add set disconnect handler and disconnect API to HFP HF
shared/hfp: Add register/unregister event for HFP HF
shared/hfp: Add HFP HF parser
shared/hfp: Add send AT command API for HFP HF
unit/test-hfp: Provide test_handler function via struct data
unit/test-hfp: Add init test for HFP HF
unit/test-hfp: Add send command tests for HFP HF
unit/test-hfp: Add tests for unsolicited results for HFP HF
unit/test-hfp: Add some robustness tests for HFP HF
src/shared/hfp.c | 649 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/shared/hfp.h | 30 +++
unit/test-hfp.c | 283 ++++++++++++++++++++++--
3 files changed, 943 insertions(+), 19 deletions(-)
--
1.8.4
^ permalink raw reply
* [PATCH] shared/io: Remove disconnect handler in io_destoy
From: Marcin Kraglak @ 2014-10-24 11:16 UTC (permalink / raw)
To: linux-bluetooth
Diconnect callback may be called after destroying IO in next
mainloop iteration (it leada to reading freed data). Removing
disconnect handler prevents that situation.
---
src/shared/io-glib.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/src/shared/io-glib.c b/src/shared/io-glib.c
index a2ada66..5ebde3d 100644
--- a/src/shared/io-glib.c
+++ b/src/shared/io-glib.c
@@ -115,6 +115,11 @@ void io_destroy(struct io *io)
io->write_watch = 0;
}
+ if (io->disconnect_watch > 0) {
+ g_source_remove(io->disconnect_watch);
+ io->disconnect_watch = 0;
+ }
+
g_io_channel_unref(io->channel);
io->channel = NULL;
--
1.9.3
^ permalink raw reply related
* Re: [PATCH BlueZ 2/8] shared/gatt-db: Add complete callback to gatt_db_read.
From: Luiz Augusto von Dentz @ 2014-10-24 9:31 UTC (permalink / raw)
To: Arman Uguray; +Cc: linux-bluetooth@vger.kernel.org
In-Reply-To: <1413838861-29956-3-git-send-email-armansito@chromium.org>
Hi Arman,
On Tue, Oct 21, 2014 at 12:00 AM, Arman Uguray <armansito@chromium.org> wrote:
> This patch introduces a completion callback parameter to gatt_db_read,
> which is meant to be used by a gatt_db_read_t implementation to signal
> the end of an asynchronous read operation performed in the upper layer.
> ---
> android/gatt.c | 21 ++++++++++++++++++---
> src/shared/gatt-db.c | 7 +++++--
> src/shared/gatt-db.h | 9 ++++++++-
> src/shared/gatt-server.c | 4 ++--
> 4 files changed, 33 insertions(+), 8 deletions(-)
>
> diff --git a/android/gatt.c b/android/gatt.c
> index ea20941..e2aa686 100644
> --- a/android/gatt.c
> +++ b/android/gatt.c
> @@ -4694,7 +4694,8 @@ static void read_requested_attributes(void *data, void *user_data)
> resp_data->offset,
> process_data->opcode,
> &process_data->device->bdaddr,
> - &value, &value_len))
> + &value, &value_len,
> + NULL, NULL))
> error = ATT_ECODE_UNLIKELY;
>
> /* We have value here already if no callback will be called */
> @@ -4744,7 +4745,10 @@ static struct pending_trans_data *conn_add_transact(struct app_connection *conn,
> }
>
> static void read_cb(uint16_t handle, uint16_t offset, uint8_t att_opcode,
> - bdaddr_t *bdaddr, void *user_data)
> + bdaddr_t *bdaddr,
> + gatt_db_read_complete_t complete_func,
> + void *complete_data,
> + void *user_data)
> {
> struct pending_trans_data *transaction;
> struct hal_ev_gatt_server_request_read ev;
> @@ -6266,7 +6270,10 @@ static struct gap_srvc_handles gap_srvc_data;
> #define PERIPHERAL_PRIVACY_DISABLE 0x00
>
> static void gap_read_cb(uint16_t handle, uint16_t offset, uint8_t att_opcode,
> - bdaddr_t *bdaddr, void *user_data)
> + bdaddr_t *bdaddr,
> + gatt_db_read_complete_t complete_func,
> + void *complete_data,
> + void *user_data)
> {
> struct pending_request *entry;
> struct gatt_device *dev;
> @@ -6373,6 +6380,8 @@ static void register_gap_service(void)
>
> static void device_info_read_cb(uint16_t handle, uint16_t offset,
> uint8_t att_opcode, bdaddr_t *bdaddr,
> + gatt_db_read_complete_t complete_func,
> + void *complete_data,
> void *user_data)
> {
> struct pending_request *entry;
> @@ -6406,6 +6415,8 @@ done:
>
> static void device_info_read_system_id_cb(uint16_t handle, uint16_t offset,
> uint8_t att_opcode, bdaddr_t *bdaddr,
> + gatt_db_read_complete_t complete_func,
> + void *complete_data,
> void *user_data)
> {
> struct pending_request *entry;
> @@ -6438,6 +6449,8 @@ done:
>
> static void device_info_read_pnp_id_cb(uint16_t handle, uint16_t offset,
> uint8_t att_opcode, bdaddr_t *bdaddr,
> + gatt_db_read_complete_t complete_func,
> + void *complete_data,
> void *user_data)
> {
> struct pending_request *entry;
> @@ -6602,6 +6615,8 @@ static void gatt_srvc_change_write_cb(uint16_t handle, uint16_t offset,
>
> static void gatt_srvc_change_read_cb(uint16_t handle, uint16_t offset,
> uint8_t att_opcode, bdaddr_t *bdaddr,
> + gatt_db_read_complete_t complete_func,
> + void *complete_data,
> void *user_data)
> {
> struct pending_request *entry;
> diff --git a/src/shared/gatt-db.c b/src/shared/gatt-db.c
> index b3f95d2..c342e32 100644
> --- a/src/shared/gatt-db.c
> +++ b/src/shared/gatt-db.c
> @@ -638,7 +638,9 @@ static bool find_service_for_handle(const void *data, const void *user_data)
>
> bool gatt_db_read(struct gatt_db *db, uint16_t handle, uint16_t offset,
> uint8_t att_opcode, bdaddr_t *bdaddr,
> - uint8_t **value, int *length)
> + uint8_t **value, int *length,
> + gatt_db_read_complete_t complete_func,
> + void *complete_data)
> {
> struct gatt_db_service *service;
> uint16_t service_handle;
> @@ -665,7 +667,8 @@ bool gatt_db_read(struct gatt_db *db, uint16_t handle, uint16_t offset,
> if (a->read_func) {
> *value = NULL;
> *length = -1;
> - a->read_func(handle, offset, att_opcode, bdaddr, a->user_data);
> + a->read_func(handle, offset, att_opcode, bdaddr, complete_func,
> + complete_data, a->user_data);
> } else {
> if (offset > a->value_len)
> return false;
> diff --git a/src/shared/gatt-db.h b/src/shared/gatt-db.h
> index 8d18434..1c8739e 100644
> --- a/src/shared/gatt-db.h
> +++ b/src/shared/gatt-db.h
> @@ -30,8 +30,13 @@ uint16_t gatt_db_add_service(struct gatt_db *db, const bt_uuid_t *uuid,
> bool primary, uint16_t num_handles);
> bool gatt_db_remove_service(struct gatt_db *db, uint16_t handle);
>
> +typedef void (*gatt_db_read_complete_t)(uint16_t handle, uint16_t att_ecode,
> + const uint8_t *value, size_t len,
> + void *complete_data);
> typedef void (*gatt_db_read_t) (uint16_t handle, uint16_t offset,
> uint8_t att_opcode, bdaddr_t *bdaddr,
> + gatt_db_read_complete_t complete_func,
> + void *complete_data,
> void *user_data);
>
> typedef void (*gatt_db_write_t) (uint16_t handle, uint16_t offset,
> @@ -81,7 +86,9 @@ void gatt_db_find_information(struct gatt_db *db, uint16_t start_handle,
>
> bool gatt_db_read(struct gatt_db *db, uint16_t handle, uint16_t offset,
> uint8_t att_opcode, bdaddr_t *bdaddr,
> - uint8_t **value, int *length);
> + uint8_t **value, int *length,
> + gatt_db_read_complete_t complete_func,
> + void *complete_data);
Lets remove value and length here and make it always return via
callback, we can probably use a idle callback if there is a problem to
return the values immediately.
> bool gatt_db_write(struct gatt_db *db, uint16_t handle, uint16_t offset,
> const uint8_t *value, size_t len,
> diff --git a/src/shared/gatt-server.c b/src/shared/gatt-server.c
> index 657b564..3233b21 100644
> --- a/src/shared/gatt-server.c
> +++ b/src/shared/gatt-server.c
> @@ -114,8 +114,8 @@ static bool encode_read_by_grp_type_rsp(struct gatt_db *db, struct queue *q,
> */
> if (!gatt_db_read(db, start_handle, 0,
> BT_ATT_OP_READ_BY_GRP_TYPE_REQ,
> - NULL, &value,
> - &value_len) || value_len < 0)
> + NULL, &value, &value_len,
> + NULL, NULL) || value_len < 0)
> return false;
>
> /*
> --
> 2.1.0.rc2.206.gedb03e5
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
--
Luiz Augusto von Dentz
^ permalink raw reply
* Re: [PATCH BlueZ 6/8] shared/gatt-server: Implement "Read By Type" request.
From: Luiz Augusto von Dentz @ 2014-10-24 9:25 UTC (permalink / raw)
To: Arman Uguray; +Cc: linux-bluetooth@vger.kernel.org
In-Reply-To: <1413838861-29956-7-git-send-email-armansito@chromium.org>
Hi Arman,
On Tue, Oct 21, 2014 at 12:00 AM, Arman Uguray <armansito@chromium.org> wrote:
> This patch implements the ATT protocol "Read By Type" request for
> shared/gatt-server. Logic is implemented that allows asynchronous
> reading of non-standard attribute values via the registered read and
> read completion callbacks.
> ---
> src/shared/gatt-server.c | 273 ++++++++++++++++++++++++++++++++++++++++++++++-
> 1 file changed, 270 insertions(+), 3 deletions(-)
>
> diff --git a/src/shared/gatt-server.c b/src/shared/gatt-server.c
> index 3233b21..6c5ea2b 100644
> --- a/src/shared/gatt-server.c
> +++ b/src/shared/gatt-server.c
> @@ -38,6 +38,16 @@
> #define MIN(a, b) ((a) < (b) ? (a) : (b))
> #endif
>
> +struct async_read_op {
> + struct bt_gatt_server *server;
> + uint8_t opcode;
> + bool done;
> + uint8_t *pdu;
> + size_t pdu_len;
> + int value_len;
> + struct queue *db_data;
> +};
> +
> struct bt_gatt_server {
> struct gatt_db *db;
> struct bt_att *att;
> @@ -46,6 +56,9 @@ struct bt_gatt_server {
>
> unsigned int mtu_id;
> unsigned int read_by_grp_type_id;
> + unsigned int read_by_type_id;
> +
> + struct async_read_op *pending_read_op;
>
> bt_gatt_server_debug_func_t debug_callback;
> bt_gatt_server_destroy_func_t debug_destroy;
> @@ -59,8 +72,12 @@ static void bt_gatt_server_free(struct bt_gatt_server *server)
>
> bt_att_unregister(server->att, server->mtu_id);
> bt_att_unregister(server->att, server->read_by_grp_type_id);
> + bt_att_unregister(server->att, server->read_by_type_id);
> bt_att_unref(server->att);
>
> + if (server->pending_read_op)
> + server->pending_read_op->server = NULL;
> +
> free(server);
> }
>
> @@ -124,21 +141,21 @@ static bool encode_read_by_grp_type_rsp(struct gatt_db *db, struct queue *q,
> * value is seen.
> */
> if (iter == 0) {
> - data_val_len = value_len;
> + data_val_len = MIN(MIN(mtu - 6, 251), value_len);
> pdu[0] = data_val_len + 4;
> iter++;
> } else if (value_len != data_val_len)
> break;
>
> /* Stop if this unit would surpass the MTU */
> - if (iter + data_val_len + 4 > mtu)
> + if (iter + data_val_len + 4 > mtu - 1)
> break;
>
> end_handle = gatt_db_get_end_handle(db, start_handle);
>
> put_le16(start_handle, pdu + iter);
> put_le16(end_handle, pdu + iter + 2);
> - memcpy(pdu + iter + 4, value, value_len);
> + memcpy(pdu + iter + 4, value, data_val_len);
>
> iter += data_val_len + 4;
> }
> @@ -235,6 +252,248 @@ done:
> NULL, NULL, NULL);
> }
>
> +static void async_read_op_destroy(struct async_read_op *op)
> +{
> + if (op->server)
> + op->server->pending_read_op = NULL;
> +
> + queue_destroy(op->db_data, NULL);
> + free(op->pdu);
> + free(op);
> +}
> +
> +static void process_read_by_type(struct async_read_op *op);
> +
> +static void read_by_type_read_complete_cb(uint16_t handle, uint16_t att_ecode,
> + const uint8_t *value, size_t len,
> + void *complete_data)
> +{
> + struct async_read_op *op = complete_data;
> + struct bt_gatt_server *server = op->server;
> + uint16_t mtu;
> +
> + if (!server) {
> + async_read_op_destroy(op);
> + return;
> + }
> +
> + mtu = bt_att_get_mtu(server->att);
> +
> + /* Terminate the operation if there was an error */
> + if (att_ecode) {
> + uint8_t pdu[4];
> +
> + encode_error_rsp(BT_ATT_OP_READ_BY_TYPE_REQ, handle, att_ecode,
> + pdu);
> + bt_att_send(server->att, BT_ATT_OP_ERROR_RSP, pdu, 4, NULL,
> + NULL, NULL);
> + async_read_op_destroy(op);
> + return;
> + }
> +
> + if (op->pdu_len == 0) {
> + op->value_len = MIN(MIN(mtu - 4, 253), len);
> + op->pdu[0] = op->value_len + 2;
> + op->pdu_len++;
> + } else if (len != op->value_len) {
> + op->done = true;
> + goto done;
> + }
> +
> + /* Stop if this would surpass the MTU */
> + if (op->pdu_len + op->value_len + 2 > mtu - 1) {
> + op->done = true;
> + goto done;
> + }
> +
> + /* Encode the current value */
> + put_le16(handle, op->pdu + op->pdu_len);
> + memcpy(op->pdu + op->pdu_len + 2, value, op->value_len);
> +
> + op->pdu_len += op->value_len + 2;
> +
> + if (op->pdu_len == mtu - 1)
> + op->done = true;
The code above is duplicated and it is actually causing some warnings
comparing unsigned with signed (usually cause by '-' operation) which
I started fixing myself but stop once I realize this was the result of
gatt_db_read having 2 modes to read, sync and async, which I don't
think is a good idea.
> +done:
> + process_read_by_type(op);
> +}
> +
> +static void process_read_by_type(struct async_read_op *op)
> +{
> + struct bt_gatt_server *server = op->server;
> + uint16_t mtu = bt_att_get_mtu(server->att);
> + uint8_t rsp_opcode;
> + uint8_t rsp_len;
> + uint8_t ecode;
> + uint16_t ehandle;
> + uint16_t start_handle;
> + uint8_t *value;
> + int value_len;
> + uint32_t perm;
> +
> + if (op->done) {
> + rsp_opcode = BT_ATT_OP_READ_BY_TYPE_RSP;
> + rsp_len = op->pdu_len;
> + goto done;
> + }
> +
> + while (queue_peek_head(op->db_data)) {
> + start_handle = PTR_TO_UINT(queue_pop_head(op->db_data));
> + value = NULL;
> + value_len = 0;
> +
> + if (!gatt_db_get_attribute_permissions(server->db, start_handle,
> + &perm)) {
> + ecode = BT_ATT_ERROR_UNLIKELY;
> + goto error;
> + }
> +
> + /*
> + * Check for the READ access permission. Encryption,
> + * authentication, and authorization permissions need to be
> + * checked by the read handler, since bt_att is agnostic to
> + * connection type and doesn't have security information on it.
> + */
> + if (perm && !(perm & BT_ATT_PERM_READ)) {
> + ecode = BT_ATT_ERROR_READ_NOT_PERMITTED;
> + goto error;
> + }
I would suggest moving this check to gatt_db_read which should return
-EPERM or the actual code if it is too hard to have errno mapping for
each error code.
> + if (!gatt_db_read(server->db, start_handle, 0, op->opcode, NULL,
> + &value, &value_len,
> + read_by_type_read_complete_cb, op)) {
> + ecode = BT_ATT_ERROR_UNLIKELY;
> + goto error;
> + }
> +
> + /* The read has been deferred to the upper layer if |value_len|
> + * is less than 0.
> + */
> + if (value_len < 0)
> + return;
> +
> + if (op->pdu_len == 0) {
> + op->value_len = MIN(MIN(mtu - 4, 253), value_len);
> + op->pdu[0] = op->value_len + 2;
> + op->pdu_len++;
> + } else if (value_len != op->value_len)
> + break;
> +
> + /* Stop if this would surpass the MTU */
> + if (op->pdu_len + op->value_len + 2 > mtu - 1)
> + break;
> +
> + /* Encode the current value */
> + put_le16(start_handle, op->pdu + op->pdu_len);
> + memcpy(op->pdu + op->pdu_len + 2, value, op->value_len);
> +
> + op->pdu_len += op->value_len + 2;
> +
> + if (op->pdu_len == mtu - 1)
> + break;
> + }
> +
> + rsp_opcode = BT_ATT_OP_READ_BY_TYPE_RSP;
> + rsp_len = op->pdu_len;
> +
> + goto done;
> +
> +error:
> + rsp_opcode = BT_ATT_OP_ERROR_RSP;
> + rsp_len = 4;
> + encode_error_rsp(BT_ATT_OP_READ_BY_TYPE_REQ, ehandle, ecode, op->pdu);
> +
> +done:
> + bt_att_send(server->att, rsp_opcode, op->pdu, rsp_len, NULL,
> + NULL, NULL);
> + async_read_op_destroy(op);
> +}
> +
> +static void read_by_type_cb(uint8_t opcode, const void *pdu,
> + uint16_t length, void *user_data)
> +{
> + struct bt_gatt_server *server = user_data;
> + uint16_t start, end;
> + bt_uuid_t type;
> + uint8_t rsp_pdu[4];
> + uint16_t ehandle = 0;
> + uint8_t ecode;
> + struct queue *q = NULL;
> + struct async_read_op *op;
> +
> + if (length != 6 && length != 20) {
> + ecode = BT_ATT_ERROR_INVALID_PDU;
> + goto error;
> + }
> +
> + q = queue_new();
> + if (!q) {
> + ecode = BT_ATT_ERROR_INSUFFICIENT_RESOURCES;
> + goto error;
> + }
> +
> + start = get_le16(pdu);
> + end = get_le16(pdu + 2);
> + get_uuid_le(pdu + 4, length - 4, &type);
> +
> + util_debug(server->debug_callback, server->debug_data,
> + "Read By Type - start: 0x%04x end: 0x%04x",
> + start, end);
> +
> + if (!start || !end) {
> + ecode = BT_ATT_ERROR_INVALID_HANDLE;
> + goto error;
> + }
> +
> + ehandle = start;
> +
> + if (start > end) {
> + ecode = BT_ATT_ERROR_INVALID_HANDLE;
> + goto error;
> + }
> +
> + gatt_db_read_by_type(server->db, start, end, type, q);
> +
> + if (queue_isempty(q)) {
> + ecode = BT_ATT_ERROR_ATTRIBUTE_NOT_FOUND;
> + goto error;
> + }
> +
> + if (server->pending_read_op) {
> + ecode = BT_ATT_ERROR_UNLIKELY;
> + goto error;
> + }
> +
> + op = new0(struct async_read_op, 1);
> + if (!op) {
> + ecode = BT_ATT_ERROR_INSUFFICIENT_RESOURCES;
> + goto error;
> + }
> +
> + op->pdu = malloc(bt_att_get_mtu(server->att));
> + if (!op->pdu) {
> + free(op);
> + ecode = BT_ATT_ERROR_INSUFFICIENT_RESOURCES;
> + goto error;
> + }
> +
> + op->opcode = opcode;
> + op->server = server;
> + op->db_data = q;
> + server->pending_read_op = op;
> +
> + process_read_by_type(op);
> +
> + return;
> +
> +error:
> + encode_error_rsp(opcode, ehandle, ecode, rsp_pdu);
> + queue_destroy(q, NULL);
> + bt_att_send(server->att, BT_ATT_OP_ERROR_RSP, rsp_pdu, 4,
> + NULL, NULL, NULL);
> +}
> +
> static void exchange_mtu_cb(uint8_t opcode, const void *pdu,
> uint16_t length, void *user_data)
> {
> @@ -283,6 +542,14 @@ static bool gatt_server_register_att_handlers(struct bt_gatt_server *server)
> if (!server->read_by_grp_type_id)
> return false;
>
> + /* Read By Type */
> + server->read_by_type_id = bt_att_register(server->att,
> + BT_ATT_OP_READ_BY_TYPE_REQ,
> + read_by_type_cb,
> + server, NULL);
> + if (!server->read_by_type_id)
> + return false;
> +
> return true;
> }
>
> --
> 2.1.0.rc2.206.gedb03e5
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-bluetooth" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
--
Luiz Augusto von Dentz
^ permalink raw reply
* Re: GATT + DBus API Questions
From: Ryan Du Bois @ 2014-10-24 0:21 UTC (permalink / raw)
To: Arman Uguray; +Cc: BlueZ development
In-Reply-To: <CAHrH25SBUL+JtDN_YF-FHfMRa3jqkhZs1YSr5QL5K5Oe_+xJQQ@mail.gmail.com>
[-- Attachment #1: Type: text/plain, Size: 3059 bytes --]
Hey Arman,
On Oct 23, 2014, at 5:00 PM, Arman Uguray <armansito@chromium.org> wrote:
> Hi Ryan,
>
> On Thu, Oct 23, 2014 at 4:41 PM, Ryan Du Bois <rdub@kamama.com> wrote:
>> Hey There,
>>
>> I've been trying to create a GATT service via the DBus BlueZ API (org.bluez.GattManager1 + org.bluez.GattService1/GattCharacteristic1). I'm currently using dbus-python to do this.
>>
>> What I have been able to accomplish thus far (with much exploring of the source code, and additional DBG() messages added to illuminate where I had been going wrong) is the following:
>> - Created proper DBus Proxy objects for GattService1 & GattCharacteristic1
>> - Each object vends the org.freedesktop.DBus.Properties interface, to allow BlueZ to retrieve the UUID and other properties on each instance.
>> - Created a proper ObjectManager proxy object to allow BlueZ to retrieve the aforementioned GattService1 and GattCharacteristic1 objects.
>> - Called GattManager1's RegisterService() method with appropriate arguments.
>> - Observed that BlueZ's GattManager1 instance calls my ObjectManager's GetManagedObjects() method, and receives the appropriate object paths/handles/properties.
>> - Observed that BlueZ accomplishes all the internal machinery necessary to register the GATT Service in src/gatt-dbus.c (namely, I get the "Added GATT service /com/kamama/blargh..." printout on the console, when running in debug mode).
>>
>> What I'm not able to see is the GATT service being listed when I explore the GATT services on my device via a BTLE exploration tool (I'm using LightBlue on Mac OS X to explore this device).
>>
>> Looking closer at the code, it looks to me like src/gatt-dbus.c is not hooked up to attrib/gatt-service.c, which is probably why my GATT Service and Characteristic are not showing up when exploring the device.
>>
>> Am I missing something, or is this not yet implemented?
>>
>> Thanks!
>> --
>> +Ryan Du Bois
>> rdub@kamama.com
>>
>
> As far as I know, gatt-dbus isn't actually wired up to attrib-server
> as you said. So it populates an internal linked list of attributes but
> then doesn't actually do anything over the listening socket it
> creates.
>
> The thing is, we're currently in the process of rewriting all of
> bluez's internal GATT/ATT tools and we'll probably entirely rewrite
> src/gatt-dbus as well. An experimental implementation should appear
> for both GATT client and server roles in the upcoming months, but
> until then there's no good way to host GATT services over D-Bus.
>
> Thanks,
> Arman
Okay, that correlates with what I'm seeing. Most examples I've seen online
have been implemented in C, calling gatt_service_add().
In the time between now and a working DBus GATT API, would that
approach be the proper method to host a GATT service with BlueZ?
I'm on 5.21 at the moment, but could easily upgrade to something else
if it's better for GATT services.
Thanks!
--
+Ryan Du Bois
rdub@kamama.com
[-- Attachment #2: Message signed with OpenPGP using GPGMail --]
[-- Type: application/pgp-signature, Size: 496 bytes --]
^ permalink raw reply
* [PATCH] Add le_scan_restart that can be used to restart le scan. In order to use it please i.e. do:
From: Jakub Pawlowski @ 2014-10-24 0:20 UTC (permalink / raw)
To: linux-bluetooth; +Cc: Jakub Pawlowski
queue_delayed_work(hdev->workqueue, &hdev->le_scan_restart, 300);
---
include/net/bluetooth/hci_core.h | 3 +++
net/bluetooth/hci_core.c | 40 ++++++++++++++++++++++++++++++++++++++++
net/bluetooth/hci_event.c | 3 ++-
3 files changed, 45 insertions(+), 1 deletion(-)
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index b8685a7..0865bc1 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -307,6 +307,8 @@ struct hci_dev {
struct discovery_state discovery;
struct hci_conn_hash conn_hash;
+ bool scan_restart;
+
struct list_head mgmt_pending;
struct list_head blacklist;
struct list_head whitelist;
@@ -334,6 +336,7 @@ struct hci_dev {
unsigned long dev_flags;
struct delayed_work le_scan_disable;
+ struct delayed_work le_scan_restart;
__s8 adv_tx_power;
__u8 adv_data[HCI_MAX_AD_LENGTH];
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c
index cb05d7f..19f0b03 100644
--- a/net/bluetooth/hci_core.c
+++ b/net/bluetooth/hci_core.c
@@ -2580,6 +2580,7 @@ static int hci_dev_do_close(struct hci_dev *hdev)
cancel_delayed_work(&hdev->service_cache);
cancel_delayed_work_sync(&hdev->le_scan_disable);
+ cancel_delayed_work_sync(&hdev->le_scan_restart);
if (test_bit(HCI_MGMT, &hdev->dev_flags))
cancel_delayed_work_sync(&hdev->rpa_expired);
@@ -3846,6 +3847,8 @@ static void le_scan_disable_work(struct work_struct *work)
BT_DBG("%s", hdev->name);
+ cancel_delayed_work_sync(&hdev->le_scan_restart);
+
hci_req_init(&req, hdev);
hci_req_add_le_scan_disable(&req);
@@ -3855,6 +3858,40 @@ static void le_scan_disable_work(struct work_struct *work)
BT_ERR("Disable LE scanning request failed: err %d", err);
}
+static void le_scan_restart_work_complete(struct hci_dev *hdev, u8 status)
+{
+ hdev->scan_restart = false;
+
+ if (status) {
+ BT_ERR("Failed to restart LE scanning: status %d", status);
+ }
+}
+
+static void le_scan_restart_work(struct work_struct *work)
+{
+ struct hci_dev *hdev = container_of(work, struct hci_dev,
+ le_scan_restart.work);
+ struct hci_request req;
+ struct hci_cp_le_set_scan_enable cp;
+ int err;
+
+ BT_DBG("%s", hdev->name);
+
+ hci_req_init(&req, hdev);
+
+ hci_req_add_le_scan_disable(&req);
+
+ memset(&cp, 0, sizeof(cp));
+ cp.enable = LE_SCAN_ENABLE;
+ hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(cp), &cp);
+
+ hdev->scan_restart = true;
+
+ err = hci_req_run(&req, le_scan_restart_work_complete);
+ if (err)
+ BT_ERR("Disable LE scanning request failed: err %d", err);
+}
+
static void set_random_addr(struct hci_request *req, bdaddr_t *rpa)
{
struct hci_dev *hdev = req->hdev;
@@ -4007,6 +4044,8 @@ struct hci_dev *hci_alloc_dev(void)
hdev->conn_info_min_age = DEFAULT_CONN_INFO_MIN_AGE;
hdev->conn_info_max_age = DEFAULT_CONN_INFO_MAX_AGE;
+ hdev->scan_restart = false;
+
mutex_init(&hdev->lock);
mutex_init(&hdev->req_lock);
@@ -4032,6 +4071,7 @@ struct hci_dev *hci_alloc_dev(void)
INIT_DELAYED_WORK(&hdev->power_off, hci_power_off);
INIT_DELAYED_WORK(&hdev->discov_off, hci_discov_off);
INIT_DELAYED_WORK(&hdev->le_scan_disable, le_scan_disable_work);
+ INIT_DELAYED_WORK(&hdev->le_scan_restart, le_scan_restart_work);
skb_queue_head_init(&hdev->rx_q);
skb_queue_head_init(&hdev->cmd_q);
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index 9629153..0191f76 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -1155,7 +1155,8 @@ static void hci_cc_le_set_scan_enable(struct hci_dev *hdev,
/* Cancel this timer so that we don't try to disable scanning
* when it's already disabled.
*/
- cancel_delayed_work(&hdev->le_scan_disable);
+ if (!hdev->scan_restart)
+ cancel_delayed_work(&hdev->le_scan_disable);
clear_bit(HCI_LE_SCAN, &hdev->dev_flags);
--
2.1.0.rc2.206.gedb03e5
^ permalink raw reply related
* Re: GATT + DBus API Questions
From: Arman Uguray @ 2014-10-24 0:00 UTC (permalink / raw)
To: Ryan Du Bois; +Cc: BlueZ development
In-Reply-To: <35EC48BC-A069-4F13-94E8-32A1533BB15C@kamama.com>
Hi Ryan,
On Thu, Oct 23, 2014 at 4:41 PM, Ryan Du Bois <rdub@kamama.com> wrote:
> Hey There,
>
> I've been trying to create a GATT service via the DBus BlueZ API (org.bluez.GattManager1 + org.bluez.GattService1/GattCharacteristic1). I'm currently using dbus-python to do this.
>
> What I have been able to accomplish thus far (with much exploring of the source code, and additional DBG() messages added to illuminate where I had been going wrong) is the following:
> - Created proper DBus Proxy objects for GattService1 & GattCharacteristic1
> - Each object vends the org.freedesktop.DBus.Properties interface, to allow BlueZ to retrieve the UUID and other properties on each instance.
> - Created a proper ObjectManager proxy object to allow BlueZ to retrieve the aforementioned GattService1 and GattCharacteristic1 objects.
> - Called GattManager1's RegisterService() method with appropriate arguments.
> - Observed that BlueZ's GattManager1 instance calls my ObjectManager's GetManagedObjects() method, and receives the appropriate object paths/handles/properties.
> - Observed that BlueZ accomplishes all the internal machinery necessary to register the GATT Service in src/gatt-dbus.c (namely, I get the "Added GATT service /com/kamama/blargh..." printout on the console, when running in debug mode).
>
> What I'm not able to see is the GATT service being listed when I explore the GATT services on my device via a BTLE exploration tool (I'm using LightBlue on Mac OS X to explore this device).
>
> Looking closer at the code, it looks to me like src/gatt-dbus.c is not hooked up to attrib/gatt-service.c, which is probably why my GATT Service and Characteristic are not showing up when exploring the device.
>
> Am I missing something, or is this not yet implemented?
>
> Thanks!
> --
> +Ryan Du Bois
> rdub@kamama.com
>
As far as I know, gatt-dbus isn't actually wired up to attrib-server
as you said. So it populates an internal linked list of attributes but
then doesn't actually do anything over the listening socket it
creates.
The thing is, we're currently in the process of rewriting all of
bluez's internal GATT/ATT tools and we'll probably entirely rewrite
src/gatt-dbus as well. An experimental implementation should appear
for both GATT client and server roles in the upcoming months, but
until then there's no good way to host GATT services over D-Bus.
Thanks,
Arman
^ permalink raw reply
* GATT + DBus API Questions
From: Ryan Du Bois @ 2014-10-23 23:41 UTC (permalink / raw)
To: linux-bluetooth
[-- Attachment #1: Type: text/plain, Size: 1739 bytes --]
Hey There,
I've been trying to create a GATT service via the DBus BlueZ API (org.bluez.GattManager1 + org.bluez.GattService1/GattCharacteristic1). I'm currently using dbus-python to do this.
What I have been able to accomplish thus far (with much exploring of the source code, and additional DBG() messages added to illuminate where I had been going wrong) is the following:
- Created proper DBus Proxy objects for GattService1 & GattCharacteristic1
- Each object vends the org.freedesktop.DBus.Properties interface, to allow BlueZ to retrieve the UUID and other properties on each instance.
- Created a proper ObjectManager proxy object to allow BlueZ to retrieve the aforementioned GattService1 and GattCharacteristic1 objects.
- Called GattManager1's RegisterService() method with appropriate arguments.
- Observed that BlueZ's GattManager1 instance calls my ObjectManager's GetManagedObjects() method, and receives the appropriate object paths/handles/properties.
- Observed that BlueZ accomplishes all the internal machinery necessary to register the GATT Service in src/gatt-dbus.c (namely, I get the "Added GATT service /com/kamama/blargh..." printout on the console, when running in debug mode).
What I'm not able to see is the GATT service being listed when I explore the GATT services on my device via a BTLE exploration tool (I'm using LightBlue on Mac OS X to explore this device).
Looking closer at the code, it looks to me like src/gatt-dbus.c is not hooked up to attrib/gatt-service.c, which is probably why my GATT Service and Characteristic are not showing up when exploring the device.
Am I missing something, or is this not yet implemented?
Thanks!
--
+Ryan Du Bois
rdub@kamama.com
[-- Attachment #2: Message signed with OpenPGP using GPGMail --]
[-- Type: application/pgp-signature, Size: 496 bytes --]
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox