Linux bluetooth development
 help / color / mirror / Atom feed
From: Andrejs Hanins <andrejs.hanins@ubnt.com>
To: Luiz Augusto von Dentz <luiz.dentz@gmail.com>
Cc: "linux-bluetooth@vger.kernel.org"
	<linux-bluetooth@vger.kernel.org>,
	Arman Uguray <armansito@chromium.org>
Subject: Re: core/gatt-db: Long writes into external GATT characteristics issue
Date: Tue, 17 Mar 2015 18:04:33 +0200	[thread overview]
Message-ID: <55085091.5030202@ubnt.com> (raw)
In-Reply-To: <CABBYNZ+EysOFUSZ12RGw-4gUOF+Yj6XyoXpQ=CX=uShn6Wur=Q@mail.gmail.com>

Hi Luiz,

On 2015.03.17. 17:15, Luiz Augusto von Dentz wrote:
> Hi Andrejs,
> 
> On Tue, Mar 17, 2015 at 1:20 PM, Andrejs Hanins 
> <andrejs.hanins@ubnt.com> wrote:
>> Hi,
>> 
>> To begin with, there is an issue with long reading/writing of 
>> external GATT characteristics registered via GattManager1. Related 
>> ATT ops are ReadBlob, PrepareWrite, ExecuteWrite etc. Reading issue
>> is easily fixed in a patch I sent yesterday. But the write case is
>> more tricky. Currently, long write into external chrc (D-Bus method
>> "WriteValue") is executed in a "chunked" fashion. Thats is, each
>> ATT PrepareWrite op eventually causes an invocation of "WriteValue"
>> with appropriate buffer (see exec_next_prep_write()). I see no easy
>> way for external D-Bus GATT service to distinguish between full and
>> partial writes, so no way to tell when the chrc is fully written.
>> 
>> I see two solutions for the issue:
>> 
>> 1. Add a new method to GattCharacteristic1 called 
>> "WriteValuePartial" with a single buffer argument, so that 
>> len(buffer)==0 denotes that all chunks have been written and 
>> service can assemble the whole buffer for further processing. Or 
>> the existing "WriteValue" method can be extended with a parameter 
>> like op_type = ["Single", "Partial", "End"]. I'm not a BlueZ
>> design expert, but IMO this approach stinks a bit... D-Bus level
>> API should be simple. I doubt that external service should have an
>>  burden related to ATT MTU fragmentation.
>> 
>> 2. Add some logic to BlueZ daemon so that "WriteValue" is always 
>> executed with fully assembled data from multiple PrepareWrite ops. 
>> Such approach will not require any D-Bus API changes, which is 
>> good. The problem is that I personally don't see a clean and easy 
>> way how to implement it in the code. Attributes are written using 
>> gatt_db_attribute_write() which has ATT opcode and write offset, 
>> but this info is not enough to understand when the last chunk of
>> an attribute value is being written to complete the operation in a
>>  single step. In case of external chrc, the 
>> gatt_db_attribute::write_func equals to chrc_write_cb() which 
>> immediately sends D-Bus calls to "WriteValue", thats it doing the 
>> "chunking". If there would be a possibility to tell when the call 
>> to gatt_db_attribute::write_func is for the last chunk of data, 
>> then chrc_write_cb() could do the assembly and invoke "WriteValue" 
>> only once. The task can be accomplished by adding an additional 
>> argument to gatt_db_write_t functor definit ion telling that write 
>> is chunked and if the chunk is last or not. Not sure, does it look 
>> like a "brutal hack" or not for BlueZ gurus :)
> 
> I guess what we should do is to queue the prepare writes and wait 
> execute to actually do the write in gatt_db,

This is exactly what is happening now. ExecuteWrite triggers all queued chunks to be written one by one into gatt_db, but not each PrepareWrite. PrepareWrite does only queuing.

> I would probably leave this to bt_gatt_server since it should be 
> doing permission checking, etc, it could handle the prepare queue. 

It looks wrong to me, because the API to write into gatt_db (gatt_db_attribute_write()) is supposed to carry the knowledge about partial writes based on the 'offset' argument. There will be no reason to have 'offset' argument if bt_gatt_server would always squash all 'prepare write' chunks into one.

> Anyway, anything that write on prepare is probably wrong since with 
> prepare there is the possibility to cancel the queue so we should 
> never call WriteValue in the first place.

As said, it is already like this.

> 
>> Maybe someone with better BlueZ design knowledge can suggest how 
>> the 2-nd solution can be implemented or maybe propose something 
>> completely different.
>> 
>> BR, Andrey -- 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
> 
> 
> 

  reply	other threads:[~2015-03-17 16:04 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-03-17 11:20 core/gatt-db: Long writes into external GATT characteristics issue Andrejs Hanins
2015-03-17 15:15 ` Luiz Augusto von Dentz
2015-03-17 16:04   ` Andrejs Hanins [this message]
2015-03-17 16:49     ` Luiz Augusto von Dentz
2015-03-17 18:15       ` Arman Uguray
2015-03-17 18:30         ` Luiz Augusto von Dentz
2015-03-17 19:05           ` Andrejs Hanins
2015-03-18 11:38             ` Luiz Augusto von Dentz

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=55085091.5030202@ubnt.com \
    --to=andrejs.hanins@ubnt.com \
    --cc=armansito@chromium.org \
    --cc=linux-bluetooth@vger.kernel.org \
    --cc=luiz.dentz@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox