Linux bluetooth development
 help / color / mirror / Atom feed
* [PATCH 1/5] unit/avrcp: Pass context to control handlers
From: Andrei Emeltchenko @ 2014-03-10 13:39 UTC (permalink / raw)
  To: linux-bluetooth

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

---
 unit/test-avrcp.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/unit/test-avrcp.c b/unit/test-avrcp.c
index 9760420..fe7009a 100644
--- a/unit/test-avrcp.c
+++ b/unit/test-avrcp.c
@@ -578,7 +578,7 @@ static void test_server(gconstpointer data)
 
 	avrcp_set_passthrough_handlers(context->session, passthrough_handlers,
 								context);
-	avrcp_set_control_handlers(context->session, control_handlers, NULL);
+	avrcp_set_control_handlers(context->session, control_handlers, context);
 
 	g_idle_add(send_pdu, context);
 
-- 
1.8.3.2


^ permalink raw reply related

* [PATCH 2/5] unit/avrcp: Add /TP/NFY/BV-05-C test.
From: Andrei Emeltchenko @ 2014-03-10 13:39 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1394458798-13822-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>

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

Test verifies Register notification - Track Changed - Track Playing.
---
 unit/test-avrcp.c | 19 ++++++++++++++++++-
 1 file changed, 18 insertions(+), 1 deletion(-)

diff --git a/unit/test-avrcp.c b/unit/test-avrcp.c
index fe7009a..fa93b25 100644
--- a/unit/test-avrcp.c
+++ b/unit/test-avrcp.c
@@ -501,6 +501,7 @@ static ssize_t avrcp_handle_register_notification(struct avrcp *session,
 							uint8_t *params,
 							void *user_data)
 {
+	struct context *context = user_data;
 	uint8_t event;
 	uint8_t pdu[9];
 	size_t pdu_len;
@@ -516,7 +517,11 @@ static ssize_t avrcp_handle_register_notification(struct avrcp *session,
 
 	switch (event) {
 	case AVRCP_EVENT_TRACK_CHANGED:
-		memset(&pdu[1], 0xff, 8);
+		if (g_str_equal(context->data->test_name, "/TP/NFY/BV-05-C"))
+			memset(&pdu[1], 0, 8);
+		else
+			memset(&pdu[1], 0xff, 8);
+
 		pdu_len += 8;
 		break;
 	case AVRCP_EVENT_SETTINGS_CHANGED:
@@ -972,5 +977,17 @@ int main(int argc, char *argv[])
 				0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
 				0xff, 0xff));
 
+	/* Register notification - Track Changed - Track Playing - TG */
+	define_test("/TP/NFY/BV-05-C", test_server,
+			raw_pdu(0x00, 0x11, 0x0e, 0x03, 0x48, 0x00,
+				0x00, 0x19, 0x58, AVRCP_REGISTER_NOTIFICATION,
+				0x00, 0x00, 0x05, AVRCP_EVENT_TRACK_CHANGED,
+				0x00, 0x00, 0x00, 0x00),
+			raw_pdu(0x02, 0x11, 0x0e, AVC_CTYPE_INTERIM, 0x48, 0x00,
+				0x00, 0x19, 0x58, AVRCP_REGISTER_NOTIFICATION,
+				0x00, 0x00, 0x09, AVRCP_EVENT_TRACK_CHANGED,
+				0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+				0x00, 0x00));
+
 	return g_test_run();
 }
-- 
1.8.3.2


^ permalink raw reply related

* [PATCH 3/5] unit/avrcp: Add /TP/NFY/BV-08-C test
From: Andrei Emeltchenko @ 2014-03-10 13:39 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1394458798-13822-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>

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

Test verifies that Target issued Track Changed INTERIM response when
the track is SELECTED.
---
 unit/test-avrcp.c | 16 +++++++++++++++-
 1 file changed, 15 insertions(+), 1 deletion(-)

diff --git a/unit/test-avrcp.c b/unit/test-avrcp.c
index fa93b25..0e65789 100644
--- a/unit/test-avrcp.c
+++ b/unit/test-avrcp.c
@@ -517,7 +517,9 @@ static ssize_t avrcp_handle_register_notification(struct avrcp *session,
 
 	switch (event) {
 	case AVRCP_EVENT_TRACK_CHANGED:
-		if (g_str_equal(context->data->test_name, "/TP/NFY/BV-05-C"))
+		if (g_str_equal(context->data->test_name, "/TP/NFY/BV-05-C") ||
+			g_str_equal(context->data->test_name,
+							"/TP/NFY/BV-08-C"))
 			memset(&pdu[1], 0, 8);
 		else
 			memset(&pdu[1], 0xff, 8);
@@ -989,5 +991,17 @@ int main(int argc, char *argv[])
 				0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 				0x00, 0x00));
 
+	/* Register notification - Track Changed - Selected Track - TG */
+	define_test("/TP/NFY/BV-08-C", test_server,
+			raw_pdu(0x00, 0x11, 0x0e, 0x03, 0x48, 0x00,
+				0x00, 0x19, 0x58, AVRCP_REGISTER_NOTIFICATION,
+				0x00, 0x00, 0x05, AVRCP_EVENT_TRACK_CHANGED,
+				0x00, 0x00, 0x00, 0x00),
+			raw_pdu(0x02, 0x11, 0x0e, AVC_CTYPE_INTERIM, 0x48, 0x00,
+				0x00, 0x19, 0x58, AVRCP_REGISTER_NOTIFICATION,
+				0x00, 0x00, 0x09, AVRCP_EVENT_TRACK_CHANGED,
+				0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+				0x00, 0x00));
+
 	return g_test_run();
 }
-- 
1.8.3.2


^ permalink raw reply related

* [PATCH 4/5] unit/avrcp: Add /TP/NFY/BI-01-C test
From: Andrei Emeltchenko @ 2014-03-10 13:39 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1394458798-13822-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>

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

Test verifies that Target returns error on register for invalid event.
---
 unit/test-avrcp.c | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/unit/test-avrcp.c b/unit/test-avrcp.c
index 0e65789..09d7689 100644
--- a/unit/test-avrcp.c
+++ b/unit/test-avrcp.c
@@ -1003,5 +1003,18 @@ int main(int argc, char *argv[])
 				0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 				0x00, 0x00));
 
+	/* Register notification - Register for events invalid behavior - TG */
+	define_test("/TP/NFY/BI-01-C", test_server,
+			raw_pdu(0x00, 0x11, 0x0e, 0x03, 0x48, 0x00,
+				0x00, 0x19, 0x58, AVRCP_REGISTER_NOTIFICATION,
+				0x00, 0x00, 0x05,
+				/* Invalid event id */
+				0xff,
+				0x00, 0x00, 0x00, 0x00),
+			raw_pdu(0x02, 0x11, 0x0e, AVC_CTYPE_REJECTED,
+				0x48, 0x00, 0x00, 0x19, 0x58,
+				AVRCP_REGISTER_NOTIFICATION,
+				0x00, 0x00, 0x01, AVRCP_STATUS_INVALID_PARAM));
+
 	return g_test_run();
 }
-- 
1.8.3.2


^ permalink raw reply related

* [PATCH 5/5] unit/avrcp: Add /TP/INV/BI-01-C test
From: Andrei Emeltchenko @ 2014-03-10 13:39 UTC (permalink / raw)
  To: linux-bluetooth
In-Reply-To: <1394458798-13822-1-git-send-email-Andrei.Emeltchenko.news@gmail.com>

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

Test verifies that AVRCP_STATUS_INVALID_COMMAND returned when received
command with Invalid PDU ID.
---
 unit/test-avrcp.c | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/unit/test-avrcp.c b/unit/test-avrcp.c
index 09d7689..5d78a9a 100644
--- a/unit/test-avrcp.c
+++ b/unit/test-avrcp.c
@@ -1016,5 +1016,19 @@ int main(int argc, char *argv[])
 				AVRCP_REGISTER_NOTIFICATION,
 				0x00, 0x00, 0x01, AVRCP_STATUS_INVALID_PARAM));
 
+	/* Invalid commands */
+
+	/* Invalid PDU ID - TG */
+	define_test("/TP/INV/BI-01-C", test_server,
+			raw_pdu(0x00, 0x11, 0x0e, 0x03, 0x48, 0x00,
+				0x00, 0x19, 0x58,
+				/* Invalid PDU ID */
+				0xff,
+				0x00, 0x00, 0x00),
+			raw_pdu(0x02, 0x11, 0x0e, AVC_CTYPE_REJECTED,
+				0x48, 0x00, 0x00, 0x19, 0x58,
+				0xff, 0x00, 0x00, 0x01,
+				AVRCP_STATUS_INVALID_COMMAND));
+
 	return g_test_run();
 }
-- 
1.8.3.2


^ permalink raw reply related

* Re: Background scanning and white list usage
From: Andre Guedes @ 2014-03-10 14:21 UTC (permalink / raw)
  To: Marcel Holtmann; +Cc: Johan Hedberg, linux-bluetooth
In-Reply-To: <674370E9-FCF0-43B1-B93C-D42778313642@holtmann.org>

Hi Johan/Marcel,

On 03/07/2014 04:30 AM, Marcel Holtmann wrote:
> Hi Andre,
>
>>>>> The complicated part comes into play when we have devices with
>>>>> LE Privacy enabled and when they are using resolvable private
>>>>> addresses. Meaning when our IRK list is populated with identity
>>>>> addresses and their IRKs. The only way to make this work with the
>>>>> current available controller features is if we program the RPA
>>>>> into the white list. Since that RPA is going to change over time,
>>>>> we need to stop scanning with the white list filter every now and
>>>>> then, scan for all devices and resolve the RPA. If we see a new
>>>>> RPA for a know IRK, we have to replace the old RPA in the white
>>>>> list with the new RPA. And then we go back to scanning with the
>>>>> white list filter policy.
>>>>>
>>>>> Now the important question is what are good enough intervals to
>>>>> make this work smoothly. Devices using LE Privacy will take a hit
>>>>> in their re-connection time, but that is what we have to trade in
>>>>> for compared to waking up the host for every single advertising
>>>>> packet.
>>>>>
>>>>> My initial idea is to scan 5 minutes using the white list, then
>>>>> scan 10 seconds without the white list, then back to 5 minutes
>>>>> using the white list and so on.
>>>>>
>>>>> The default value for the PRA lifetime according to the
>>>>> specification is 15 minutes. I timed recent iOS devices which
>>>>> seem to be using 9 minutes intervals. So we have to play a little
>>>>> bit with this and see what are good values.
>>>>>
>>>>> Maybe 3 minutes white list scan and 5 seconds without white list
>>>>> is better. Things to try out.
>>>>
>>>> I don't think this is a good idea at all. With LE starting
>>>> advertising is typically seen as the initiating action of
>>>> connection creation (unlike with BR/EDR where HCI_Create_Connection
>>>> is the initiating action). Typically peripherals mean "connect to
>>>> me now!" when they start connectable advertising.
>>>>
>>>> Let's stay you switch on your peripheral device, or it comes into
>>>> range you haven't used it for some time (hours or even days). If
>>>> it's using RPAs it's pretty much guaranteed to have a different one
>>>> than what we know of and even if we're using 3 minutes white list
>>>> scanning the user is on average going to have to wait for 1.5
>>>> minutes for the device to get connected which is not acceptable
>>>> behavior (the extreme example would be if this is a keyboard or a
>>>> mouse which you start using for the first time in the morning -
>>>> moving the mouse or pressing a key on the keyboard should certainly
>>>> get you a connection in less than 1 second).
>>>
>>> HID devices would suffer the most here. Fully agree here.
>>>
>>> However since neither Microsoft Windows nor OS X can deal with RPAs
>>> at the moment, I do not think we are entering a dangerous zone here
>>> from an interoperability point of view. Actually Windows 8.1 is not
>>> able to connect to any random address for that matter.
>>>
>>> My point is that we certainly not make it worse.
>>
>> HoG is not the only problem. I'm afraid delaying re-connection 3-5
>> minutes we might become others profiles impractical (e.g. Fob keeps
>> beeping even if it is beside the cellphone).
>
> to be honest not every bonded device needs to auto-reconnect. So this might all work out and when resolution in the controller becomes available, it can be nicely switched over.
>
>>>> I fully understand the desire to use the white list as it's a very
>>>> nice power saving feature, but I don't think we can win here as
>>>> long as we don't have a way to have the controller do the resolving
>>>> for us.
>>>>
>>>> One thing we could potentially try to do (but which I doubt is
>>>> really worth it in the end) is to track the age of resolved RPAs.
>>>> If we have an RPA which was resolved say less than 5 minutes ago we
>>>> consider it appropriate to place into the white list. Otherwise we
>>>> skip using the white list.
>>>
>>> I was thinking about this as well. Over time we could learn the age
>>> of a RPA and thus schedule the scanning without white list times most
>>> efficient. Frankly, I want to get the white list usage going first.
>>> As long as you only have public or static addresses, it is the way to
>>> go. And then we optimize it when we have to deal with RPAs.
>>
>> I agree with Johan about this aging approach, I seems not worthy. Honestly, I don't see how we would properly deal with white list and LE Privacy issue by now.
>
> As I said, we try out best and see how it works out. The interval can be tweaked of course.
>
>>> We can not close our eyes to iOS devices using RPAs and I am not
>>> willing to take the power hit of getting flooded with advertising
>>> reports.
>>
>> To fix this other issue (advertising flooding), filtering duplicates is just fine.
>>
>> The problem with enabling filter duplicates in background scan happens in the following scenario:
>>   * Background scan is running.
>>   * A device disconnects and starts advertising.
>>   * Before host gets the disconnect event, the advertising is reported
>>     to host. Since there is no pending LE connection at that time,
>>     nothing happens.
>>   * Host gets the disconnection event and adds a pending connection.
>>   * No advertising is reported (since controller is filtering) and the
>>     connection is never established.
>
> that is why we have to disable and re-enable scanning from time to time.
>
>> To address this scenario, all we have to do is: always restart background scan when a new LE pending connection is added. This way, we unsure that we don't miss the advertising report.
>>
>> If you guys agree with this approach I can write the patches.
>
> I want to start using the white list for scanning. That is our next step.

So, I think it would be fine we have first this advertising flooding 
issue fixed by enabling  duplicate filter. Then we improve the 
background scan by using white list.

At the end, after experiments, if the white list approach doesn't work 
well, we simply fall back to scan with duplicate filter enabled.

I'll send patches soon.

Regards,

Andre

^ permalink raw reply

* Re: [RC6 Bell Chime] Re: [PATCH 00/24] rfcomm fixes
From: John W. Linville @ 2014-03-10 15:08 UTC (permalink / raw)
  To: Sander Eikelenboom
  Cc: Marcel Holtmann, Gustavo F. Padovan, Peter Hurley, Linus Torvalds,
	bluez mailin list (linux-bluetooth@vger.kernel.org), linux-kernel
In-Reply-To: <1295963563.20140310093843@eikelenboom.it>

On Mon, Mar 10, 2014 at 09:38:43AM +0100, Sander Eikelenboom wrote:
> Hi all,
> 
> Since:
> - 3.14-RC6 has been cut
> - this regression is known and reported since the merge window
> - the fix (revert of 3 patches) is known for over a month now
> - but it's still not in mainline
> - my polite ping request from last week seems to have provoked exactly 0 (zero) response.
> 
> IT'S TIME TO CHIME SOME BELLS :-)
> 
> Hope that WILL be heard somewhere ...
> 
> --
> Sander
> 
> PS. on the informative side the 3 commits to be reverted are:
> 
> f86772af6a0f643d3e13eb3f4f9213ae0c333ee4 Bluetooth: Remove rfcomm_carrier_raised()
> 4a2fb3ecc7467c775b154813861f25a0ddc11aa0 Bluetooth: Always wait for a connection on RFCOMM open()
> e228b63390536f5b737056059a9a04ea016b1abf Bluetooth: Move rfcomm_get_device() before rfcomm_dev_activate()

Gustavo, should I be expecting a pull request?

-- 
John W. Linville		Someday the world will need a hero, and you
linville@tuxdriver.com			might be all we have.  Be ready.

^ permalink raw reply

* [PATCH] android/pts: AVRCP PTS tests results
From: Sebastian Chlad @ 2014-03-10 17:08 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: Sebastian Chlad

Adding PTS tests results, mainly for Volume Level Handling section.
---
 android/pts-avrcp.txt | 22 +++++++++++++---------
 1 file changed, 13 insertions(+), 9 deletions(-)

diff --git a/android/pts-avrcp.txt b/android/pts-avrcp.txt
index a6d5222..b6f591b 100644
--- a/android/pts-avrcp.txt
+++ b/android/pts-avrcp.txt
@@ -77,12 +77,16 @@ TC_CT_PTT_BV_04_I	N/A
 TC_CT_PTT_BV_05_I	N/A
 TC_CT_RCR_BV_01_C	N/A
 TC_CT_RCR_BV_03_C	N/A
-TC_CT_VLH_BI_03_C	INC
-TC_CT_VLH_BI_04_C	INC
-TC_CT_VLH_BV_01_C	INC
-TC_CT_VLH_BV_01_I	INC
-TC_CT_VLH_BV_02_I	INC
-TC_CT_VLH_BV_03_C	INC
+TC_CT_VLH_BI_03_C	PASS	Send SetAbsolute Volume command by pressing
+				volume up or down buttons then adb logcat and
+				check VOLUME_CHANGED value
+TC_CT_VLH_BI_04_C	PASS	adb logcat: check VOLUME_CHANGED value
+TC_CT_VLH_BV_01_C	PASS	Send SetAbsolute Volume command by pressing
+				volume up or down buttons
+TC_CT_VLH_BV_01_I	PASS	adb logcat: check VOLUME_CHANGED value
+TC_CT_VLH_BV_02_I	PASS	Send SetAbsolute Volume command by pressing
+				volume up or down buttons
+TC_CT_VLH_BV_03_C	PASS
 -------------------------------------------------------------------------------
 
 
@@ -147,7 +151,7 @@ TC_TG_MCN_SRC_BV_04_C	N/A
 TC_TG_MCN_SRC_BV_04_I	N/A
 TC_TG_MCN_SRC_BV_06_C	N/A
 TC_TG_MDI_BV_02_C	PASS
-TC_TG_MDI_BV_04_C	FAIL
+TC_TG_MDI_BV_04_C	PASS
 TC_TG_MDI_BV_05_C	PASS
 TC_TG_MPS_BI_01_C	N/A
 TC_TG_MPS_BI_02_C	N/A
@@ -184,8 +188,8 @@ TC_TG_PTT_BV_02_I	PASS
 TC_TG_PTT_BV_03_I	N/A
 TC_TG_PTT_BV_04_I	N/A
 TC_TG_PTT_BV_05_I	N/A
-TC_TG_RCR_BV_02_C	INC
-TC_TG_RCR_BV_04_C	INC
+TC_TG_RCR_BV_02_C	PASS
+TC_TG_RCR_BV_04_C	PASS
 TC_TG_VLH_BI_01_C	N/A
 TC_TG_VLH_BI_02_C	N/A
 TC_TG_VLH_BV_01_I	N/A
-- 
1.8.5.3


^ permalink raw reply related

* Re: [PATCH] android/pts: AVRCP PTS tests results
From: Luiz Augusto von Dentz @ 2014-03-10 17:26 UTC (permalink / raw)
  To: Sebastian Chlad; +Cc: linux-bluetooth@vger.kernel.org
In-Reply-To: <1394471306-13826-1-git-send-email-sebastian.chlad@tieto.com>

Hi Sebastian,

On Mon, Mar 10, 2014 at 7:08 PM, Sebastian Chlad
<sebastian.chlad@tieto.com> wrote:
> Adding PTS tests results, mainly for Volume Level Handling section.
> ---
>  android/pts-avrcp.txt | 22 +++++++++++++---------
>  1 file changed, 13 insertions(+), 9 deletions(-)
>
> diff --git a/android/pts-avrcp.txt b/android/pts-avrcp.txt
> index a6d5222..b6f591b 100644
> --- a/android/pts-avrcp.txt
> +++ b/android/pts-avrcp.txt
> @@ -77,12 +77,16 @@ TC_CT_PTT_BV_04_I   N/A
>  TC_CT_PTT_BV_05_I      N/A
>  TC_CT_RCR_BV_01_C      N/A
>  TC_CT_RCR_BV_03_C      N/A
> -TC_CT_VLH_BI_03_C      INC
> -TC_CT_VLH_BI_04_C      INC
> -TC_CT_VLH_BV_01_C      INC
> -TC_CT_VLH_BV_01_I      INC
> -TC_CT_VLH_BV_02_I      INC
> -TC_CT_VLH_BV_03_C      INC
> +TC_CT_VLH_BI_03_C      PASS    Send SetAbsolute Volume command by pressing
> +                               volume up or down buttons then adb logcat and
> +                               check VOLUME_CHANGED value
> +TC_CT_VLH_BI_04_C      PASS    adb logcat: check VOLUME_CHANGED value
> +TC_CT_VLH_BV_01_C      PASS    Send SetAbsolute Volume command by pressing
> +                               volume up or down buttons
> +TC_CT_VLH_BV_01_I      PASS    adb logcat: check VOLUME_CHANGED value
> +TC_CT_VLH_BV_02_I      PASS    Send SetAbsolute Volume command by pressing
> +                               volume up or down buttons
> +TC_CT_VLH_BV_03_C      PASS
>  -------------------------------------------------------------------------------
>
>
> @@ -147,7 +151,7 @@ TC_TG_MCN_SRC_BV_04_C       N/A
>  TC_TG_MCN_SRC_BV_04_I  N/A
>  TC_TG_MCN_SRC_BV_06_C  N/A
>  TC_TG_MDI_BV_02_C      PASS
> -TC_TG_MDI_BV_04_C      FAIL
> +TC_TG_MDI_BV_04_C      PASS
>  TC_TG_MDI_BV_05_C      PASS
>  TC_TG_MPS_BI_01_C      N/A
>  TC_TG_MPS_BI_02_C      N/A
> @@ -184,8 +188,8 @@ TC_TG_PTT_BV_02_I   PASS
>  TC_TG_PTT_BV_03_I      N/A
>  TC_TG_PTT_BV_04_I      N/A
>  TC_TG_PTT_BV_05_I      N/A
> -TC_TG_RCR_BV_02_C      INC
> -TC_TG_RCR_BV_04_C      INC
> +TC_TG_RCR_BV_02_C      PASS
> +TC_TG_RCR_BV_04_C      PASS
>  TC_TG_VLH_BI_01_C      N/A
>  TC_TG_VLH_BI_02_C      N/A
>  TC_TG_VLH_BV_01_I      N/A
> --
> 1.8.5.3

Applied, thanks.



-- 
Luiz Augusto von Dentz

^ permalink raw reply

* [PATCH BlueZ v0 00/16] Add basic GATT characteristics
From: Claudio Takahasi @ 2014-03-10 18:50 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: claudio.takahasi

This patchset adds the following features:
  * register external characteristics
  * basic read or write external characteristics

Usage of glib is being avoided inside src/gatt.c. Properties/flags is not
implemented yet.

How to test:
It is possible to test the implemented features using a modified
gatttool version. Unix socket is used as transport to allow basic
ATT operations: 
git://git.infradead.org/users/cktakahasi/bluez.git gatt-api-forupstream-group2-patchv0-testing

$gatttool -I -L
[LOCAL][LE]> connect
Local connection
Connection successful
[LOCAL][LE]> primary
attr handle: 0x0001, end grp handle: 0x0003 uuid: 000034fb-0000-1000-8000-00805f9b34fb
[LOCAL][LE]> characteristics
handle: 0x0002, char properties: 0x00, char value handle: 0x0003, uuid: 00002a06-0000-1000-8000-00805f9b34fb
[LOCAL][LE]> char-read-hnd 0x0003
Characteristic value/descriptor: 00 
[LOCAL][LE]> char-write-req 0x0003 02
Characteristic value was written successfully
[LOCAL][LE]> char-read-hnd 0x0003
Characteristic value/descriptor: 02 

Alvaro Silva (3):
  tools: Add Alert Level characteristic to gatt-service
  tools: Add reading Value property of gatt-service
  tools: Add setting Value property of gatt-service

Andre Guedes (2):
  gatt: Add function to create constant attributes
  gatt: Add helper for creating GATT characteristics

Claudio Takahasi (11):
  gatt: Add characteristic to the database
  gatt: Add hash table of GDBusProxy objects
  gatt: Add read callback to btd_gatt_add_char helper
  gatt: Assign read callback for external services
  gatt: Add helper for reading characteristics
  gatt: Add write callback to btd_gatt_add_char helper
  gdbus: Add g_dbus_proxy_set_property_array
  gatt: Assign write callback for external services
  gatt: Add result callback for Write Request
  gatt: Add Write Request handling for GDBusProxy
  tools: Emit property changed when Value changes

 gdbus/client.c       |  85 +++++++++++++++++++++++
 gdbus/gdbus.h        |   5 ++
 src/gatt-dbus.c      | 189 +++++++++++++++++++++++++++++++++++++++++++++++++--
 src/gatt.c           | 138 +++++++++++++++++++++++++++++++++++--
 src/gatt.h           |  52 ++++++++++++++
 tools/gatt-service.c | 157 ++++++++++++++++++++++++++++++++++++++----
 6 files changed, 604 insertions(+), 22 deletions(-)

-- 
1.8.3.1


^ permalink raw reply

* [PATCH BlueZ v0 01/16] gatt: Add function to create constant attributes
From: Claudio Takahasi @ 2014-03-10 18:50 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: claudio.takahasi, Andre Guedes
In-Reply-To: <1394477445-8987-1-git-send-email-claudio.takahasi@openbossa.org>

From: Andre Guedes <andre.guedes@openbossa.org>

This patch adds a helper function to create attribute with static
values. It is intended to be used to create GATT services, and
characteristic declarations.
---
 src/gatt.c | 32 ++++++++++++++++++++++++++------
 1 file changed, 26 insertions(+), 6 deletions(-)

diff --git a/src/gatt.c b/src/gatt.c
index f7b74d6..7882a91 100644
--- a/src/gatt.c
+++ b/src/gatt.c
@@ -30,6 +30,7 @@
 #include "log.h"
 #include "lib/uuid.h"
 #include "attrib/att.h"
+#include "src/shared/util.h"
 
 #include "gatt-dbus.h"
 #include "gatt.h"
@@ -48,6 +49,25 @@ struct btd_attribute {
 static GList *local_attribute_db;
 static uint16_t next_handle = 0x0001;
 
+/*
+ * Helper function to create new attributes containing constant/static values.
+ * eg: declaration of services/characteristics, and characteristics with
+ * fixed values.
+ */
+static struct btd_attribute *new_const_attribute(const bt_uuid_t *type,
+							const uint8_t *value,
+							uint16_t len)
+{
+	struct btd_attribute *attr = malloc0(sizeof(struct btd_attribute) +
+									len);
+
+	memcpy(&attr->type, type, sizeof(*type));
+	memcpy(&attr->value, value, len);
+	attr->value_len = len;
+
+	return attr;
+}
+
 static int local_database_add(uint16_t handle, struct btd_attribute *attr)
 {
 	attr->handle = handle;
@@ -59,9 +79,9 @@ static int local_database_add(uint16_t handle, struct btd_attribute *attr)
 
 struct btd_attribute *btd_gatt_add_service(const bt_uuid_t *uuid)
 {
+	struct btd_attribute *attr;
 	uint16_t len = bt_uuid_len(uuid);
-	struct btd_attribute *attr = g_malloc0(sizeof(struct btd_attribute) +
-									len);
+	uint8_t value[len];
 
 	/*
 	 * Service DECLARATION
@@ -75,13 +95,13 @@ struct btd_attribute *btd_gatt_add_service(const bt_uuid_t *uuid)
 	 * (2) - 2 or 16 octets: Service UUID
 	 */
 
-	attr->type = primary_uuid;
+	/* Set attribute value */
+	att_put_uuid(*uuid, value);
 
-	att_put_uuid(*uuid, attr->value);
-	attr->value_len = len;
+	attr = new_const_attribute(&primary_uuid, value, len);
 
 	if (local_database_add(next_handle, attr) < 0) {
-		g_free(attr);
+		free(attr);
 		return NULL;
 	}
 
-- 
1.8.3.1


^ permalink raw reply related

* [PATCH BlueZ v0 02/16] gatt: Add helper for creating GATT characteristics
From: Claudio Takahasi @ 2014-03-10 18:50 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: claudio.takahasi, Andre Guedes
In-Reply-To: <1394477445-8987-1-git-send-email-claudio.takahasi@openbossa.org>

From: Andre Guedes <andre.guedes@openbossa.org>

This patch adds btd_gatt_add_char() helper. It creates and adds the
Characteristic declaration, and Characteristic value attributes to the
local attribute database.
---
 src/gatt.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/gatt.h | 11 +++++++++
 2 files changed, 91 insertions(+)

diff --git a/src/gatt.c b/src/gatt.c
index 7882a91..7f7af80 100644
--- a/src/gatt.c
+++ b/src/gatt.c
@@ -39,6 +39,9 @@
 static const bt_uuid_t primary_uuid  = { .type = BT_UUID16,
 					.value.u16 = GATT_PRIM_SVC_UUID };
 
+static const bt_uuid_t chr_uuid = { .type = BT_UUID16,
+					.value.u16 = GATT_CHARAC_UUID };
+
 struct btd_attribute {
 	uint16_t handle;
 	bt_uuid_t type;
@@ -111,6 +114,83 @@ struct btd_attribute *btd_gatt_add_service(const bt_uuid_t *uuid)
 	return attr;
 }
 
+struct btd_attribute *btd_gatt_add_char(bt_uuid_t *uuid, uint8_t properties)
+{
+	struct btd_attribute *char_decl, *char_value = NULL;
+
+	/* Attribute value length */
+	uint16_t len = 1 + 2 + bt_uuid_len(uuid);
+	uint8_t value[len];
+
+	/*
+	 * Characteristic DECLARATION
+	 *
+	 *   TYPE         ATTRIBUTE VALUE
+	 * +-------+---------------------------------+
+	 * |0x2803 | 0xXX 0xYYYY 0xZZZZ...           |
+	 * | (1)   |  (2)   (3)   (4)                |
+	 * +------+----------------------------------+
+	 * (1) - 2 octets: Characteristic declaration UUID
+	 * (2) - 1 octet : Properties
+	 * (3) - 2 octets: Handle of the characteristic Value
+	 * (4) - 2 or 16 octets: Characteristic UUID
+	 */
+
+	value[0] = properties;
+
+	/*
+	 * Since we don't know yet the characteristic value attribute
+	 * handle, we skip and set it later.
+	 */
+
+	att_put_uuid(*uuid, &value[3]);
+
+	char_decl = new_const_attribute(&chr_uuid, value, len);
+	if (local_database_add(next_handle, char_decl) < 0)
+		goto fail;
+
+	next_handle = next_handle + 1;
+
+	/*
+	 * Characteristic VALUE
+	 *
+	 *   TYPE         ATTRIBUTE VALUE
+	 * +----------+---------------------------------+
+	 * |0xZZZZ... | 0x...                           |
+	 * |  (1)     |  (2)                            |
+	 * +----------+---------------------------------+
+	 * (1) - 2 or 16 octets: Characteristic UUID
+	 * (2) - N octets: Value is read dynamically from the service
+	 * implementation (external entity).
+	 */
+
+	char_value = new0(struct btd_attribute, 1);
+	memcpy(&char_value->type, uuid, sizeof(char_value->type));
+
+	/* TODO: Read & Write callbacks */
+
+	if (local_database_add(next_handle, char_value) < 0)
+		goto fail;
+
+	next_handle = next_handle + 1;
+
+	/*
+	 * Update characteristic value handle in characteristic declaration
+	 * attribute. For local attributes, we can assume that the handle
+	 * representing the characteristic value will get the next available
+	 * handle. However, for remote attribute this assumption is not valid.
+	 */
+	att_put_u16(char_value->handle, &char_decl->value[1]);
+
+	return char_value;
+
+fail:
+	free(char_decl);
+	free(char_value);
+
+	return NULL;
+}
+
 void gatt_init(void)
 {
 	DBG("Starting GATT server");
diff --git a/src/gatt.h b/src/gatt.h
index 8dd1312..7df82cf 100644
--- a/src/gatt.h
+++ b/src/gatt.h
@@ -34,3 +34,14 @@ void gatt_cleanup(void);
  * NULL is returned.
  */
 struct btd_attribute *btd_gatt_add_service(const bt_uuid_t *uuid);
+
+/*
+ * btd_gatt_add_char - Add a characteristic (declaration and value attributes)
+ * to local attribute database.
+ * @uuid:	Characteristic UUID (16-bits or 128-bits).
+ * @properties:	Characteristic properties. See Core SPEC 4.1 page 2183.
+ *
+ * Returns a reference to characteristic value attribute. In case of error,
+ * NULL is returned.
+ */
+struct btd_attribute *btd_gatt_add_char(bt_uuid_t *uuid, uint8_t properties);
-- 
1.8.3.1


^ permalink raw reply related

* [PATCH BlueZ v0 03/16] gatt: Add characteristic to the database
From: Claudio Takahasi @ 2014-03-10 18:50 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: claudio.takahasi
In-Reply-To: <1394477445-8987-1-git-send-email-claudio.takahasi@openbossa.org>

Initial support for GATT characteristics. This patch adds the
characteristic declaration attribute to the GATT local database based
on the fetched GDBusProxy objects.
---
 src/gatt-dbus.c | 38 +++++++++++++++++++++++++++++++++++++-
 1 file changed, 37 insertions(+), 1 deletion(-)

diff --git a/src/gatt-dbus.c b/src/gatt-dbus.c
index 3fbff87..8cf222d 100644
--- a/src/gatt-dbus.c
+++ b/src/gatt-dbus.c
@@ -163,6 +163,39 @@ static int register_external_service(const struct external_app *eapp,
 	return 0;
 }
 
+static int register_external_characteristics(GSList *proxies)
+
+{
+	GSList *list;
+
+	for (list = proxies; list; list = g_slist_next(proxies)) {
+		DBusMessageIter iter;
+		const char *str, *path;
+		bt_uuid_t uuid;
+		GDBusProxy *proxy = list->data;
+
+		if (!g_dbus_proxy_get_property(proxy, "UUID", &iter))
+			return -EINVAL;
+
+		if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
+			return -EINVAL;
+
+		dbus_message_iter_get_basic(&iter, &str);
+
+		if (bt_string_to_uuid(&uuid, str) < 0)
+			return -EINVAL;
+
+		/* TODO: Missing Flags/property */
+		if (btd_gatt_add_char(&uuid, 0x00) == NULL)
+			return -EINVAL;
+
+		path = g_dbus_proxy_get_path(proxy);
+		DBG("Added GATT CHR: %s (%s)", path, str);
+	}
+
+	return 0;
+}
+
 static void client_ready(GDBusClient *client, void *user_data)
 {
 	struct external_app *eapp = user_data;
@@ -177,6 +210,9 @@ static void client_ready(GDBusClient *client, void *user_data)
 	if (register_external_service(eapp, proxy) < 0)
 		goto fail;
 
+	if (register_external_characteristics(g_slist_next(eapp->proxies)) < 0)
+		goto fail;
+
 	DBG("Added GATT service %s", eapp->path);
 
 	reply = dbus_message_new_method_return(eapp->reg);
@@ -186,7 +222,7 @@ fail:
 	error("Could not register external service: %s", eapp->path);
 
 	reply = btd_error_invalid_args(eapp->reg);
-	/* TODO: missing eapp cleanup */
+	/* TODO: missing eapp/database cleanup */
 
 reply:
 	dbus_message_unref(eapp->reg);
-- 
1.8.3.1


^ permalink raw reply related

* [PATCH BlueZ v0 04/16] gatt: Add hash table of GDBusProxy objects
From: Claudio Takahasi @ 2014-03-10 18:50 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: claudio.takahasi
In-Reply-To: <1394477445-8987-1-git-send-email-claudio.takahasi@openbossa.org>

This commits adds a hash table to map attributes into GDBusProxy,
allowing to call remote objects for reading and writing values.
---
 src/gatt-dbus.c | 27 +++++++++++++++++++++++----
 1 file changed, 23 insertions(+), 4 deletions(-)

diff --git a/src/gatt-dbus.c b/src/gatt-dbus.c
index 8cf222d..014b8d6 100644
--- a/src/gatt-dbus.c
+++ b/src/gatt-dbus.c
@@ -56,6 +56,12 @@ struct external_app {
 	unsigned int watch;
 };
 
+/*
+ * Attribute to Proxy hash table. Used to map incoming
+ * ATT operations to its external characteristic proxy.
+ */
+static GHashTable *proxy_hash;
+
 static GSList *external_apps;
 
 static int external_app_path_cmp(gconstpointer a, gconstpointer b)
@@ -172,6 +178,7 @@ static int register_external_characteristics(GSList *proxies)
 		DBusMessageIter iter;
 		const char *str, *path;
 		bt_uuid_t uuid;
+		struct btd_attribute *attr;
 		GDBusProxy *proxy = list->data;
 
 		if (!g_dbus_proxy_get_property(proxy, "UUID", &iter))
@@ -186,11 +193,14 @@ static int register_external_characteristics(GSList *proxies)
 			return -EINVAL;
 
 		/* TODO: Missing Flags/property */
-		if (btd_gatt_add_char(&uuid, 0x00) == NULL)
+		attr = btd_gatt_add_char(&uuid, 0x00);
+		if (attr == NULL)
 			return -EINVAL;
 
 		path = g_dbus_proxy_get_path(proxy);
 		DBG("Added GATT CHR: %s (%s)", path, str);
+
+		g_hash_table_insert(proxy_hash, attr, g_dbus_proxy_ref(proxy));
 	}
 
 	return 0;
@@ -313,13 +323,22 @@ static const GDBusMethodTable methods[] = {
 
 gboolean gatt_dbus_manager_register(void)
 {
-	return g_dbus_register_interface(btd_get_dbus_connection(),
-					"/org/bluez", GATT_MGR_IFACE,
-					methods, NULL, NULL, NULL, NULL);
+	if (g_dbus_register_interface(btd_get_dbus_connection(),
+				"/org/bluez", GATT_MGR_IFACE,
+				methods, NULL, NULL, NULL, NULL) == FALSE)
+		return FALSE;
+
+	proxy_hash = g_hash_table_new_full(g_direct_hash, g_direct_equal,
+				NULL, (GDestroyNotify) g_dbus_proxy_unref);
+
+	return TRUE;
 }
 
 void gatt_dbus_manager_unregister(void)
 {
+	g_hash_table_destroy(proxy_hash);
+	proxy_hash = NULL;
+
 	g_dbus_unregister_interface(btd_get_dbus_connection(), "/org/bluez",
 							GATT_MGR_IFACE);
 }
-- 
1.8.3.1


^ permalink raw reply related

* [PATCH BlueZ v0 05/16] gatt: Add read callback to btd_gatt_add_char helper
From: Claudio Takahasi @ 2014-03-10 18:50 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: claudio.takahasi
In-Reply-To: <1394477445-8987-1-git-send-email-claudio.takahasi@openbossa.org>

This patch adds a function callback for read operations. When a remote
device wants to reads a given attribute, the core calls the specified
read callback to get the value from the external services.
---
 src/gatt-dbus.c |  2 +-
 src/gatt.c      |  7 +++++--
 src/gatt.h      | 19 ++++++++++++++++++-
 3 files changed, 24 insertions(+), 4 deletions(-)

diff --git a/src/gatt-dbus.c b/src/gatt-dbus.c
index 014b8d6..a904a97 100644
--- a/src/gatt-dbus.c
+++ b/src/gatt-dbus.c
@@ -193,7 +193,7 @@ static int register_external_characteristics(GSList *proxies)
 			return -EINVAL;
 
 		/* TODO: Missing Flags/property */
-		attr = btd_gatt_add_char(&uuid, 0x00);
+		attr = btd_gatt_add_char(&uuid, 0x00, NULL);
 		if (attr == NULL)
 			return -EINVAL;
 
diff --git a/src/gatt.c b/src/gatt.c
index 7f7af80..059e085 100644
--- a/src/gatt.c
+++ b/src/gatt.c
@@ -45,6 +45,7 @@ static const bt_uuid_t chr_uuid = { .type = BT_UUID16,
 struct btd_attribute {
 	uint16_t handle;
 	bt_uuid_t type;
+	btd_attr_read_t read_cb;
 	uint16_t value_len;
 	uint8_t value[0];
 };
@@ -114,7 +115,8 @@ struct btd_attribute *btd_gatt_add_service(const bt_uuid_t *uuid)
 	return attr;
 }
 
-struct btd_attribute *btd_gatt_add_char(bt_uuid_t *uuid, uint8_t properties)
+struct btd_attribute *btd_gatt_add_char(bt_uuid_t *uuid, uint8_t properties,
+						btd_attr_read_t read_cb)
 {
 	struct btd_attribute *char_decl, *char_value = NULL;
 
@@ -166,8 +168,9 @@ struct btd_attribute *btd_gatt_add_char(bt_uuid_t *uuid, uint8_t properties)
 
 	char_value = new0(struct btd_attribute, 1);
 	memcpy(&char_value->type, uuid, sizeof(char_value->type));
+	char_value->read_cb = read_cb;
 
-	/* TODO: Read & Write callbacks */
+	/* TODO: Write callbacks */
 
 	if (local_database_add(next_handle, char_value) < 0)
 		goto fail;
diff --git a/src/gatt.h b/src/gatt.h
index 7df82cf..0021076 100644
--- a/src/gatt.h
+++ b/src/gatt.h
@@ -27,6 +27,22 @@ void gatt_init(void);
 
 void gatt_cleanup(void);
 
+/*
+ * Callbacks of this type are called once the value from the attribute is
+ * ready to be read from the service implementation. Result callback is
+ * the asynchronous function that should be used to inform the caller
+ * the read value.
+ * @err:	error in errno format.
+ * @value:	pointer to value
+ * @len:	length of value
+ * @user_data:	user_data passed in btd_attr_read_t callback
+ */
+typedef void (*btd_attr_read_result_t) (int err, uint8_t *value, size_t len,
+							void *user_data);
+typedef void (*btd_attr_read_t) (struct btd_attribute *attr,
+						btd_attr_read_result_t result,
+						void *user_data);
+
 /* btd_gatt_add_service - Add a service declaration to local attribute database.
  * @uuid:	Service UUID.
  *
@@ -44,4 +60,5 @@ struct btd_attribute *btd_gatt_add_service(const bt_uuid_t *uuid);
  * Returns a reference to characteristic value attribute. In case of error,
  * NULL is returned.
  */
-struct btd_attribute *btd_gatt_add_char(bt_uuid_t *uuid, uint8_t properties);
+struct btd_attribute *btd_gatt_add_char(bt_uuid_t *uuid, uint8_t properties,
+						btd_attr_read_t read_cb);
-- 
1.8.3.1


^ permalink raw reply related

* [PATCH BlueZ v0 06/16] gatt: Assign read callback for external services
From: Claudio Takahasi @ 2014-03-10 18:50 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: claudio.takahasi
In-Reply-To: <1394477445-8987-1-git-send-email-claudio.takahasi@openbossa.org>

This patch adds the callback for reading the external characteristic
Value. Internally, GDBusProxy implementation tracks all properties Value
changes consequently Value can be ready directly from the proxy without
additional method calls.
---
 src/gatt-dbus.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 46 insertions(+), 2 deletions(-)

diff --git a/src/gatt-dbus.c b/src/gatt-dbus.c
index a904a97..28604ea 100644
--- a/src/gatt-dbus.c
+++ b/src/gatt-dbus.c
@@ -139,6 +139,46 @@ static void proxy_removed(GDBusProxy *proxy, void *user_data)
 	eapp->proxies = g_slist_remove(eapp->proxies, proxy);
 }
 
+static void proxy_read_cb(struct btd_attribute *attr,
+				btd_attr_read_result_t result, void *user_data)
+{
+	DBusMessageIter iter, array;
+	GDBusProxy *proxy;
+	uint8_t *value;
+	int len;
+
+	/*
+	 * Remote device is trying to read the informed attribute,
+	 * "Value" should be read from the proxy. GDBusProxy tracks
+	 * properties changes automatically, it is not necessary to
+	 * get the value directly from the GATT server.
+	 */
+	proxy = g_hash_table_lookup(proxy_hash, attr);
+	if (proxy == NULL) {
+		result(ENOENT, NULL, 0, user_data);
+		return;
+	}
+
+	if (!g_dbus_proxy_get_property(proxy, "Value", &iter)) {
+		/* Unusual situation, read property will checked earlier */
+		result(EPERM, NULL, 0, user_data);
+		return;
+	}
+
+	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
+		DBG("External service inconsistent!");
+		result(EPERM, NULL, 0, user_data);
+		return;
+	}
+
+	dbus_message_iter_recurse(&iter, &array);
+	dbus_message_iter_get_fixed_array(&array, &value, &len);
+
+	DBG("attribute: %p read %d bytes", attr, len);
+
+	result(0, value, len, user_data);
+}
+
 static int register_external_service(const struct external_app *eapp,
 							GDBusProxy *proxy)
 {
@@ -192,8 +232,12 @@ static int register_external_characteristics(GSList *proxies)
 		if (bt_string_to_uuid(&uuid, str) < 0)
 			return -EINVAL;
 
-		/* TODO: Missing Flags/property */
-		attr = btd_gatt_add_char(&uuid, 0x00, NULL);
+		/*
+		 * TODO: Missing Flags/property
+		 * Add properties according to Core SPEC 4.1 page 2183.
+		 * Reference table 3.5: Characteristic Properties bit field.
+		 */
+		attr = btd_gatt_add_char(&uuid, 0x00, proxy_read_cb);
 		if (attr == NULL)
 			return -EINVAL;
 
-- 
1.8.3.1


^ permalink raw reply related

* [PATCH BlueZ v0 07/16] gatt: Add helper for reading characteristics
From: Claudio Takahasi @ 2014-03-10 18:50 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: claudio.takahasi
In-Reply-To: <1394477445-8987-1-git-send-email-claudio.takahasi@openbossa.org>

This patch adds the btd_gatt_read_attribute() helper. It reads the
attribute value based on its read callback function. The callback can
the an abstraction for reading an external object proxy or a remote
attribute, acting as a helper function for server and client
implementations.
---
 src/gatt.c | 22 ++++++++++++++++++++++
 src/gatt.h |  9 +++++++++
 2 files changed, 31 insertions(+)

diff --git a/src/gatt.c b/src/gatt.c
index 059e085..0137123 100644
--- a/src/gatt.c
+++ b/src/gatt.c
@@ -25,6 +25,7 @@
 #include <config.h>
 #endif
 
+#include <errno.h>
 #include <glib.h>
 
 #include "log.h"
@@ -194,6 +195,27 @@ fail:
 	return NULL;
 }
 
+void btd_gatt_read_attribute(struct btd_attribute *attr,
+					btd_attr_read_result_t result,
+					void *user_data)
+{
+	/*
+	 * When read_cb is available, it means that the attribute value
+	 * is dynamic, and its value must be read from the external
+	 * implementation. If "value_len" is set, the attribute value is
+	 * constant. Additional checking are performed by the attribute server
+	 * when the ATT Read request arrives based on the characteristic
+	 * properties. At this point, properties bitmask doesn't need to be
+	 * checked.
+	 */
+	if (attr->read_cb)
+		attr->read_cb(attr, result, user_data);
+	else if (attr->value_len > 0)
+		result(0, attr->value, attr->value_len, user_data);
+	else
+		result(EPERM, NULL, 0, user_data);
+}
+
 void gatt_init(void)
 {
 	DBG("Starting GATT server");
diff --git a/src/gatt.h b/src/gatt.h
index 0021076..4363769 100644
--- a/src/gatt.h
+++ b/src/gatt.h
@@ -62,3 +62,12 @@ struct btd_attribute *btd_gatt_add_service(const bt_uuid_t *uuid);
  */
 struct btd_attribute *btd_gatt_add_char(bt_uuid_t *uuid, uint8_t properties,
 						btd_attr_read_t read_cb);
+
+/* btd_gatt_read_attribute - Read the value of an attribute.
+ * @attr:	Attribute to be read.
+ * @result:	Callback function to be called with the result.
+ * @user_data:	Data to be passed to the result callback function.
+ */
+void btd_gatt_read_attribute(struct btd_attribute *attr,
+					btd_attr_read_result_t result,
+					void *user_data);
-- 
1.8.3.1


^ permalink raw reply related

* [PATCH BlueZ v0 08/16] gatt: Add write callback to btd_gatt_add_char helper
From: Claudio Takahasi @ 2014-03-10 18:50 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: claudio.takahasi
In-Reply-To: <1394477445-8987-1-git-send-email-claudio.takahasi@openbossa.org>

This patch adds a function callback for write operations. When a remote
device writes to a given attribute, the core calls the specified write
callback informing the attribute server the new characteristic value.
---
 src/gatt-dbus.c |  2 +-
 src/gatt.c      |  7 ++++---
 src/gatt.h      | 14 +++++++++++++-
 3 files changed, 18 insertions(+), 5 deletions(-)

diff --git a/src/gatt-dbus.c b/src/gatt-dbus.c
index 28604ea..10d682d 100644
--- a/src/gatt-dbus.c
+++ b/src/gatt-dbus.c
@@ -237,7 +237,7 @@ static int register_external_characteristics(GSList *proxies)
 		 * Add properties according to Core SPEC 4.1 page 2183.
 		 * Reference table 3.5: Characteristic Properties bit field.
 		 */
-		attr = btd_gatt_add_char(&uuid, 0x00, proxy_read_cb);
+		attr = btd_gatt_add_char(&uuid, 0x00, proxy_read_cb, NULL);
 		if (attr == NULL)
 			return -EINVAL;
 
diff --git a/src/gatt.c b/src/gatt.c
index 0137123..04b537e 100644
--- a/src/gatt.c
+++ b/src/gatt.c
@@ -47,6 +47,7 @@ struct btd_attribute {
 	uint16_t handle;
 	bt_uuid_t type;
 	btd_attr_read_t read_cb;
+	btd_attr_write_t write_cb;
 	uint16_t value_len;
 	uint8_t value[0];
 };
@@ -117,7 +118,8 @@ struct btd_attribute *btd_gatt_add_service(const bt_uuid_t *uuid)
 }
 
 struct btd_attribute *btd_gatt_add_char(bt_uuid_t *uuid, uint8_t properties,
-						btd_attr_read_t read_cb)
+						btd_attr_read_t read_cb,
+						btd_attr_write_t write_cb)
 {
 	struct btd_attribute *char_decl, *char_value = NULL;
 
@@ -170,8 +172,7 @@ struct btd_attribute *btd_gatt_add_char(bt_uuid_t *uuid, uint8_t properties,
 	char_value = new0(struct btd_attribute, 1);
 	memcpy(&char_value->type, uuid, sizeof(char_value->type));
 	char_value->read_cb = read_cb;
-
-	/* TODO: Write callbacks */
+	char_value->write_cb = write_cb;
 
 	if (local_database_add(next_handle, char_value) < 0)
 		goto fail;
diff --git a/src/gatt.h b/src/gatt.h
index 4363769..f6b4aca 100644
--- a/src/gatt.h
+++ b/src/gatt.h
@@ -42,6 +42,14 @@ typedef void (*btd_attr_read_result_t) (int err, uint8_t *value, size_t len,
 typedef void (*btd_attr_read_t) (struct btd_attribute *attr,
 						btd_attr_read_result_t result,
 						void *user_data);
+/*
+ * Callbacks from this type are called once the value from the attribute was
+ * written.
+ * @err:	error in errno format.
+ * @user_data:	user_data passed in btd_attr_write_t callback
+ */
+typedef void (*btd_attr_write_t) (struct btd_attribute *attr,
+					const uint8_t *value, size_t len);
 
 /* btd_gatt_add_service - Add a service declaration to local attribute database.
  * @uuid:	Service UUID.
@@ -56,12 +64,16 @@ struct btd_attribute *btd_gatt_add_service(const bt_uuid_t *uuid);
  * to local attribute database.
  * @uuid:	Characteristic UUID (16-bits or 128-bits).
  * @properties:	Characteristic properties. See Core SPEC 4.1 page 2183.
+ * @read_cb:	Callback used to provide the characteristic value.
+ * @write_cb:	Callback called to notify the implementation that a new value
+ *              is available.
  *
  * Returns a reference to characteristic value attribute. In case of error,
  * NULL is returned.
  */
 struct btd_attribute *btd_gatt_add_char(bt_uuid_t *uuid, uint8_t properties,
-						btd_attr_read_t read_cb);
+						btd_attr_read_t read_cb,
+						btd_attr_write_t write_cb);
 
 /* btd_gatt_read_attribute - Read the value of an attribute.
  * @attr:	Attribute to be read.
-- 
1.8.3.1


^ permalink raw reply related

* [PATCH BlueZ v0 09/16] gdbus: Add g_dbus_proxy_set_property_array
From: Claudio Takahasi @ 2014-03-10 18:50 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: claudio.takahasi
In-Reply-To: <1394477445-8987-1-git-send-email-claudio.takahasi@openbossa.org>

This patch adds a new gdbus utility function to allow setting a property
of fixed, and non-fixed values array.
---
 gdbus/client.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 gdbus/gdbus.h  |  5 ++++
 2 files changed, 90 insertions(+)

diff --git a/gdbus/client.c b/gdbus/client.c
index 5193b6c..6fea3d9 100644
--- a/gdbus/client.c
+++ b/gdbus/client.c
@@ -727,6 +727,91 @@ gboolean g_dbus_proxy_set_property_basic(GDBusProxy *proxy,
 	return TRUE;
 }
 
+gboolean g_dbus_proxy_set_property_array(GDBusProxy *proxy,
+				const char *name, int type, const void *value,
+				int size, GDBusResultFunction function,
+				void *user_data, GDBusDestroyFunction destroy)
+{
+	struct set_property_data *data;
+	GDBusClient *client;
+	DBusMessage *msg;
+	DBusMessageIter iter, variant, array;
+	DBusPendingCall *call;
+	char array_sig[3];
+	char type_sig[2];
+
+	if (proxy == NULL || name == NULL || value == NULL)
+		return FALSE;
+
+	if (dbus_type_is_basic(type) == FALSE)
+		return FALSE;
+
+	client = proxy->client;
+	if (client == NULL)
+		return FALSE;
+
+	data = g_try_new0(struct set_property_data, 1);
+	if (data == NULL)
+		return FALSE;
+
+	data->function = function;
+	data->user_data = user_data;
+	data->destroy = destroy;
+
+	msg = dbus_message_new_method_call(client->service_name,
+			proxy->obj_path, DBUS_INTERFACE_PROPERTIES, "Set");
+	if (msg == NULL) {
+		g_free(data);
+		return FALSE;
+	}
+
+	array_sig[0] = DBUS_TYPE_ARRAY;
+	array_sig[1] = (char) type;
+	array_sig[2] = '\0';
+
+	type_sig[0] = (char) type;
+	type_sig[1] = '\0';
+
+	dbus_message_iter_init_append(msg, &iter);
+	dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING,
+							&proxy->interface);
+	dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &name);
+
+	dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
+						array_sig, &variant);
+
+	dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY,
+						type_sig, &array);
+
+	if (dbus_type_is_fixed(type) == TRUE)
+		dbus_message_iter_append_fixed_array(&array, type,
+							&value, size);
+	else if (type == DBUS_TYPE_STRING || type == DBUS_TYPE_OBJECT_PATH) {
+		int i;
+		const char **str = (const char **) value;
+
+		for (i = 0; i < size; i++)
+			dbus_message_iter_append_basic(&array, type, &str[i]);
+	}
+
+	dbus_message_iter_close_container(&variant, &array);
+	dbus_message_iter_close_container(&iter, &variant);
+
+	if (g_dbus_send_message_with_reply(client->dbus_conn, msg,
+							&call, -1) == FALSE) {
+		dbus_message_unref(msg);
+		g_free(data);
+		return FALSE;
+	}
+
+	dbus_pending_call_set_notify(call, set_property_reply, data, g_free);
+	dbus_pending_call_unref(call);
+
+	dbus_message_unref(msg);
+
+	return TRUE;
+}
+
 struct method_call_data {
 	GDBusReturnFunction function;
 	void *user_data;
diff --git a/gdbus/gdbus.h b/gdbus/gdbus.h
index 8ada200..40a5abe 100644
--- a/gdbus/gdbus.h
+++ b/gdbus/gdbus.h
@@ -329,6 +329,11 @@ gboolean g_dbus_proxy_set_property_basic(GDBusProxy *proxy,
 				GDBusResultFunction function, void *user_data,
 				GDBusDestroyFunction destroy);
 
+gboolean g_dbus_proxy_set_property_array(GDBusProxy *proxy,
+				const char *name, int type, const void *value,
+				int size, GDBusResultFunction function,
+				void *user_data, GDBusDestroyFunction destroy);
+
 typedef void (* GDBusSetupFunction) (DBusMessageIter *iter, void *user_data);
 typedef void (* GDBusReturnFunction) (DBusMessage *message, void *user_data);
 
-- 
1.8.3.1


^ permalink raw reply related

* [PATCH BlueZ v0 10/16] gatt: Assign write callback for external services
From: Claudio Takahasi @ 2014-03-10 18:50 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: claudio.takahasi
In-Reply-To: <1394477445-8987-1-git-send-email-claudio.takahasi@openbossa.org>

This patch adds the callback for writing the external characteristic
value. Internally, DBusProxy implementation calls the Set method of the
"Value" property. At the moment, potential errors returned by the
external service implementation are being ignored.

The ATT operation (Write Command or Request) is not exposed to the service
implementation. Internally, gatt-dbus will handle possible returned errors,
and notify the core based on the callbacks informed. Write Command
doesn't have callback since it doesn't return ATT errors.
---
 src/gatt-dbus.c | 27 ++++++++++++++++++++++++++-
 1 file changed, 26 insertions(+), 1 deletion(-)

diff --git a/src/gatt-dbus.c b/src/gatt-dbus.c
index 10d682d..d71d993 100644
--- a/src/gatt-dbus.c
+++ b/src/gatt-dbus.c
@@ -179,6 +179,30 @@ static void proxy_read_cb(struct btd_attribute *attr,
 	result(0, value, len, user_data);
 }
 
+static void proxy_write_reply(const DBusError *derr, void *user_data)
+{
+	if (derr)
+		DBG("Write reply: %s", derr->message);
+}
+
+static void proxy_write_cb(struct btd_attribute *attr,
+					const uint8_t *value, size_t len)
+{
+	GDBusProxy *proxy;
+
+	proxy = g_hash_table_lookup(proxy_hash, attr);
+	if (proxy == NULL)
+		/* FIXME: Attribute not found */
+		return;
+
+	g_dbus_proxy_set_property_array(proxy, "Value", DBUS_TYPE_BYTE,
+						value, len, proxy_write_reply,
+						NULL, NULL);
+
+	DBG("Server: Write characteristic callback %s",
+					g_dbus_proxy_get_path(proxy));
+}
+
 static int register_external_service(const struct external_app *eapp,
 							GDBusProxy *proxy)
 {
@@ -237,7 +261,8 @@ static int register_external_characteristics(GSList *proxies)
 		 * Add properties according to Core SPEC 4.1 page 2183.
 		 * Reference table 3.5: Characteristic Properties bit field.
 		 */
-		attr = btd_gatt_add_char(&uuid, 0x00, proxy_read_cb, NULL);
+		attr = btd_gatt_add_char(&uuid, 0x00, proxy_read_cb,
+							proxy_write_cb);
 		if (attr == NULL)
 			return -EINVAL;
 
-- 
1.8.3.1


^ permalink raw reply related

* [PATCH BlueZ v0 11/16] gatt: Add result callback for Write Request
From: Claudio Takahasi @ 2014-03-10 18:50 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: claudio.takahasi
In-Reply-To: <1394477445-8987-1-git-send-email-claudio.takahasi@openbossa.org>

This patch adds an extra callback to inform the result of the write
operation on an external entity to allow the core to reply properly
for the ATT request.
---
 src/gatt-dbus.c | 4 +++-
 src/gatt.h      | 5 ++++-
 2 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/src/gatt-dbus.c b/src/gatt-dbus.c
index d71d993..7bc19c8 100644
--- a/src/gatt-dbus.c
+++ b/src/gatt-dbus.c
@@ -186,7 +186,9 @@ static void proxy_write_reply(const DBusError *derr, void *user_data)
 }
 
 static void proxy_write_cb(struct btd_attribute *attr,
-					const uint8_t *value, size_t len)
+					const uint8_t *value, size_t len,
+					btd_attr_write_result_t result,
+					void *user_data)
 {
 	GDBusProxy *proxy;
 
diff --git a/src/gatt.h b/src/gatt.h
index f6b4aca..296258e 100644
--- a/src/gatt.h
+++ b/src/gatt.h
@@ -48,8 +48,11 @@ typedef void (*btd_attr_read_t) (struct btd_attribute *attr,
  * @err:	error in errno format.
  * @user_data:	user_data passed in btd_attr_write_t callback
  */
+typedef void (*btd_attr_write_result_t) (int err, void *user_data);
 typedef void (*btd_attr_write_t) (struct btd_attribute *attr,
-					const uint8_t *value, size_t len);
+					const uint8_t *value, size_t len,
+					btd_attr_write_result_t result,
+					void *user_data);
 
 /* btd_gatt_add_service - Add a service declaration to local attribute database.
  * @uuid:	Service UUID.
-- 
1.8.3.1


^ permalink raw reply related

* [PATCH BlueZ v0 12/16] gatt: Add Write Request handling for GDBusProxy
From: Claudio Takahasi @ 2014-03-10 18:50 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: claudio.takahasi
In-Reply-To: <1394477445-8987-1-git-send-email-claudio.takahasi@openbossa.org>

When the characteristic requires Write Request, the ATT response should
be sent after receiving the reply for the Set method call.
---
 src/gatt-dbus.c | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 61 insertions(+), 6 deletions(-)

diff --git a/src/gatt-dbus.c b/src/gatt-dbus.c
index 7bc19c8..c5f1597 100644
--- a/src/gatt-dbus.c
+++ b/src/gatt-dbus.c
@@ -56,6 +56,11 @@ struct external_app {
 	unsigned int watch;
 };
 
+struct proxy_write_data {
+	btd_attr_write_result_t result_cb;
+	void *user_data;
+};
+
 /*
  * Attribute to Proxy hash table. Used to map incoming
  * ATT operations to its external characteristic proxy.
@@ -181,8 +186,30 @@ static void proxy_read_cb(struct btd_attribute *attr,
 
 static void proxy_write_reply(const DBusError *derr, void *user_data)
 {
-	if (derr)
-		DBG("Write reply: %s", derr->message);
+	struct proxy_write_data *wdata = user_data;
+	int err = 0;
+
+	/*
+	 * Security requirements shall be handled by the core. If external
+	 * applications returns an error, the reasons will be restricted to
+	 * invalid argument or application specific errors.
+	 */
+
+	if (dbus_error_is_set(derr) == FALSE)
+		goto done;
+
+	DBG("Write reply: %s", derr->message);
+
+	if (dbus_error_has_name(derr, DBUS_ERROR_NO_REPLY))
+		err = ETIMEDOUT;
+	else if (dbus_error_has_name(derr, ERROR_INTERFACE ".InvalidArguments"))
+		err = EINVAL;
+	else
+		err = EPROTO;
+
+done:
+	if (wdata && wdata->result_cb)
+		wdata->result_cb(err, wdata->user_data);
 }
 
 static void proxy_write_cb(struct btd_attribute *attr,
@@ -193,16 +220,44 @@ static void proxy_write_cb(struct btd_attribute *attr,
 	GDBusProxy *proxy;
 
 	proxy = g_hash_table_lookup(proxy_hash, attr);
-	if (proxy == NULL)
-		/* FIXME: Attribute not found */
+	if (proxy == NULL) {
+		result(ENOENT, user_data);
 		return;
+	}
 
-	g_dbus_proxy_set_property_array(proxy, "Value", DBUS_TYPE_BYTE,
+	/*
+	 * "result" callback defines if the core wants to receive the
+	 * operation result, allowing to select ATT Write Request or Write
+	 * Command. Descriptors requires Write Request operation. For
+	 * Characteristics, the implementation will define which operations
+	 * are allowed based on the properties/flags.
+	 * TODO: Write Long Characteristics/Descriptors.
+	 */
+
+	if (result) {
+		struct proxy_write_data *wdata;
+
+		wdata = g_new0(struct proxy_write_data, 1);
+		wdata->result_cb = result;
+		wdata->user_data = user_data;
+
+		g_dbus_proxy_set_property_array(proxy, "Value", DBUS_TYPE_BYTE,
+						value, len, proxy_write_reply,
+						wdata, g_free);
+	} else {
+		/*
+		 * Caller is not interested in the Set method call result.
+		 * This flow implements the ATT Write Command scenario, where
+		 * the remote doesn't receive ATT response.
+		 */
+		g_dbus_proxy_set_property_array(proxy, "Value", DBUS_TYPE_BYTE,
 						value, len, proxy_write_reply,
 						NULL, NULL);
+	}
 
-	DBG("Server: Write characteristic callback %s",
+	DBG("Server: Write attribute callback %s",
 					g_dbus_proxy_get_path(proxy));
+
 }
 
 static int register_external_service(const struct external_app *eapp,
-- 
1.8.3.1


^ permalink raw reply related

* [PATCH BlueZ v0 13/16] tools: Add Alert Level characteristic to gatt-service
From: Claudio Takahasi @ 2014-03-10 18:50 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: claudio.takahasi, Alvaro Silva
In-Reply-To: <1394477445-8987-1-git-send-email-claudio.takahasi@openbossa.org>

From: Alvaro Silva <alvaro.silva@openbossa.org>

This patch registers the Alert Level characteristic object related to
Immediate Alert Service. It adds the characteristic UUID property only.
---
 tools/gatt-service.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 52 insertions(+), 1 deletion(-)

diff --git a/tools/gatt-service.c b/tools/gatt-service.c
index cba0ff3..d1606ad 100644
--- a/tools/gatt-service.c
+++ b/tools/gatt-service.c
@@ -37,13 +37,30 @@
 
 #define GATT_MGR_IFACE			"org.bluez.GattManager1"
 #define GATT_SERVICE_IFACE		"org.bluez.GattService1"
+#define GATT_CHR_IFACE			"org.bluez.GattCharacteristic1"
 
 /* Immediate Alert Service UUID */
 #define IAS_UUID			"00001802-0000-1000-8000-00805f9b34fb"
+#define ALERT_LEVEL_CHR_UUID		"00002a06-0000-1000-8000-00805f9b34fb"
 
 static GMainLoop *main_loop;
 static GSList *services;
 
+static gboolean chr_get_uuid(const GDBusPropertyTable *property,
+					DBusMessageIter *iter, void *user_data)
+{
+	const char *uuid = user_data;
+
+	dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &uuid);
+
+	return TRUE;
+}
+
+static const GDBusPropertyTable chr_properties[] = {
+	{ "UUID",	"s",	chr_get_uuid },
+	{ }
+};
+
 static gboolean service_get_uuid(const GDBusPropertyTable *property,
 					DBusMessageIter *iter, void *user_data)
 {
@@ -83,6 +100,27 @@ static const GDBusPropertyTable service_properties[] = {
 	{ }
 };
 
+static int register_characteristic(DBusConnection *conn, const char *uuid,
+						const char *service_path)
+{
+	static int id = 1;
+	char *path;
+	int ret = 0;
+
+	path = g_strdup_printf("%s/characteristic%d", service_path, id++);
+
+	if (g_dbus_register_interface(conn, path, GATT_CHR_IFACE,
+					NULL, NULL, chr_properties,
+					g_strdup(uuid), g_free) == FALSE) {
+		printf("Couldn't register characteristic interface\n");
+		ret = -EIO;
+	}
+
+	g_free(path);
+
+	return ret;
+}
+
 static char *register_service(DBusConnection *conn, const char *uuid)
 {
 	static int id = 1;
@@ -103,11 +141,24 @@ static char *register_service(DBusConnection *conn, const char *uuid)
 static void create_services(DBusConnection *conn)
 {
 	char *service_path;
+	int ret;
 
 	service_path = register_service(conn, IAS_UUID);
+	if (service_path == NULL)
+		return;
 
-	services = g_slist_prepend(services, service_path);
+	/* Add Alert Level Characteristic to Immediate Alert Service */
+	ret = register_characteristic(conn, ALERT_LEVEL_CHR_UUID,
+							service_path);
+	if (ret < 0) {
+		printf("Couldn't register Alert Level characteristic (IAS)\n");
+		g_dbus_unregister_interface(conn, service_path,
+							GATT_SERVICE_IFACE);
+		g_free(service_path);
+		return;
+	}
 
+	services = g_slist_prepend(services, service_path);
 	printf("Registered service: %s\n", service_path);
 }
 
-- 
1.8.3.1


^ permalink raw reply related

* [PATCH BlueZ v0 14/16] tools: Add reading Value property of gatt-service
From: Claudio Takahasi @ 2014-03-10 18:50 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: claudio.takahasi, Alvaro Silva
In-Reply-To: <1394477445-8987-1-git-send-email-claudio.takahasi@openbossa.org>

From: Alvaro Silva <alvaro.silva@openbossa.org>

This patch extends the gatt-service.c example adding the callback to
allow reading the Value property. At the moment, it is a generic
callback and it doesn't consider characteristic value property
restrictions.
---
 tools/gatt-service.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 54 insertions(+), 6 deletions(-)

diff --git a/tools/gatt-service.c b/tools/gatt-service.c
index d1606ad..25528ca 100644
--- a/tools/gatt-service.c
+++ b/tools/gatt-service.c
@@ -46,18 +46,44 @@
 static GMainLoop *main_loop;
 static GSList *services;
 
+struct characteristic {
+	char *uuid;
+	uint8_t *value;
+	int vlen;
+};
+
 static gboolean chr_get_uuid(const GDBusPropertyTable *property,
 					DBusMessageIter *iter, void *user_data)
 {
-	const char *uuid = user_data;
+	struct characteristic *chr = user_data;
 
-	dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &uuid);
+	dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &chr->uuid);
+
+	return TRUE;
+}
+
+static gboolean chr_get_value(const GDBusPropertyTable *property,
+					DBusMessageIter *iter, void *user_data)
+{
+	struct characteristic *chr = user_data;
+	DBusMessageIter array;
+
+	printf("Get(\"Value\")\n");
+
+	dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
+					DBUS_TYPE_BYTE_AS_STRING, &array);
+
+	dbus_message_iter_append_fixed_array(&array, DBUS_TYPE_BYTE,
+						&chr->value, chr->vlen);
+
+	dbus_message_iter_close_container(iter, &array);
 
 	return TRUE;
 }
 
 static const GDBusPropertyTable chr_properties[] = {
 	{ "UUID",	"s",	chr_get_uuid },
+	{ "Value", "ay", chr_get_value, NULL, NULL },
 	{ }
 };
 
@@ -100,18 +126,36 @@ static const GDBusPropertyTable service_properties[] = {
 	{ }
 };
 
+static void chr_iface_destroy(gpointer user_data)
+{
+	struct characteristic *chr = user_data;
+
+	g_free(chr->uuid);
+	g_free(chr->value);
+	g_free(chr);
+}
+
 static int register_characteristic(DBusConnection *conn, const char *uuid,
+						const uint8_t *value, int vlen,
 						const char *service_path)
 {
+	struct characteristic *chr;
 	static int id = 1;
 	char *path;
 	int ret = 0;
 
 	path = g_strdup_printf("%s/characteristic%d", service_path, id++);
 
+	chr = g_new0(struct characteristic, 1);
+
+	chr->uuid = g_strdup(uuid);
+
+	chr->value = g_memdup(value, vlen);
+	chr->vlen = vlen;
+
 	if (g_dbus_register_interface(conn, path, GATT_CHR_IFACE,
 					NULL, NULL, chr_properties,
-					g_strdup(uuid), g_free) == FALSE) {
+					chr, chr_iface_destroy) == FALSE) {
 		printf("Couldn't register characteristic interface\n");
 		ret = -EIO;
 	}
@@ -141,15 +185,19 @@ static char *register_service(DBusConnection *conn, const char *uuid)
 static void create_services(DBusConnection *conn)
 {
 	char *service_path;
+	uint8_t level = 0;
 	int ret;
 
 	service_path = register_service(conn, IAS_UUID);
 	if (service_path == NULL)
 		return;
 
-	/* Add Alert Level Characteristic to Immediate Alert Service */
-	ret = register_characteristic(conn, ALERT_LEVEL_CHR_UUID,
-							service_path);
+	/* Add Alert Level Characteristic to Immediate Alert Service
+	 * According to the IAS SPEC, reading <<Alert level>> is not alloweed.
+	 * "Value" is readable for testing purpose only.
+	 */
+	ret = register_characteristic(conn, ALERT_LEVEL_CHR_UUID, &level,
+						sizeof(level), service_path);
 	if (ret < 0) {
 		printf("Couldn't register Alert Level characteristic (IAS)\n");
 		g_dbus_unregister_interface(conn, service_path,
-- 
1.8.3.1


^ permalink raw reply related

* [PATCH BlueZ v0 15/16] tools: Add setting Value property of gatt-service
From: Claudio Takahasi @ 2014-03-10 18:50 UTC (permalink / raw)
  To: linux-bluetooth; +Cc: claudio.takahasi, Alvaro Silva
In-Reply-To: <1394477445-8987-1-git-send-email-claudio.takahasi@openbossa.org>

From: Alvaro Silva <alvaro.silva@openbossa.org>

This patch extends the gatt-service.c example adding a generic callback
to allow set the characteristic Value. It doesn't check for
characteristic properties yet.
---
 tools/gatt-service.c | 33 ++++++++++++++++++++++++++++++++-
 1 file changed, 32 insertions(+), 1 deletion(-)

diff --git a/tools/gatt-service.c b/tools/gatt-service.c
index 25528ca..481495c 100644
--- a/tools/gatt-service.c
+++ b/tools/gatt-service.c
@@ -35,6 +35,8 @@
 #include <dbus/dbus.h>
 #include <gdbus/gdbus.h>
 
+#include "src/error.h"
+
 #define GATT_MGR_IFACE			"org.bluez.GattManager1"
 #define GATT_SERVICE_IFACE		"org.bluez.GattService1"
 #define GATT_CHR_IFACE			"org.bluez.GattCharacteristic1"
@@ -81,9 +83,38 @@ static gboolean chr_get_value(const GDBusPropertyTable *property,
 	return TRUE;
 }
 
+static void chr_set_value(const GDBusPropertyTable *property,
+				DBusMessageIter *iter,
+				GDBusPendingPropertySet id, void *user_data)
+{
+	struct characteristic *chr = user_data;
+	DBusMessageIter array;
+	uint8_t *value;
+	int len;
+
+	printf("Set('Value', ...)\n");
+
+	if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY) {
+		printf("Invalid value for Set('Value'...)\n");
+		g_dbus_pending_property_error(id,
+					ERROR_INTERFACE ".InvalidArguments",
+					"Invalid arguments in method call");
+		return;
+	}
+
+	dbus_message_iter_recurse(iter, &array);
+	dbus_message_iter_get_fixed_array(&array, &value, &len);
+
+	g_free(chr->value);
+	chr->value = g_memdup(value, len);
+	chr->vlen = len;
+
+	g_dbus_pending_property_success(id);
+}
+
 static const GDBusPropertyTable chr_properties[] = {
 	{ "UUID",	"s",	chr_get_uuid },
-	{ "Value", "ay", chr_get_value, NULL, NULL },
+	{ "Value", "ay", chr_get_value, chr_set_value, NULL },
 	{ }
 };
 
-- 
1.8.3.1


^ permalink raw reply related


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