Skip to content

Commit 4706ca3

Browse files
authored
Algorithms for bluetooth.descriptor commands (#662)
1 parent e4f357d commit 4706ca3

1 file changed

Lines changed: 203 additions & 31 deletions

File tree

index.bs

Lines changed: 203 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -4102,6 +4102,30 @@ slots</a> described in the following table:
41024102
has been removed or otherwise invalidated.
41034103
</td>
41044104
</tr>
4105+
<tr>
4106+
<td><dfn>\[[automatedDescriptorReadResponse]]</dfn></td>
4107+
<td><code>"not-expected"</code></td>
4108+
<td>
4109+
The simulated GATT descriptor response code for a GATT descriptor
4110+
read attempt.
4111+
</td>
4112+
</tr>
4113+
<tr>
4114+
<td><dfn>\[[automatedDescriptorReadResponseData]]</dfn></td>
4115+
<td>Empty <a>byte sequence</a></td>
4116+
<td>
4117+
The simulated GATT descriptor response data for a GATT descriptor
4118+
read attempt.
4119+
</td>
4120+
</tr>
4121+
<tr>
4122+
<td><dfn>\[[automatedDescriptorWriteResponse]]</dfn></td>
4123+
<td><code>"not-expected"</code></td>
4124+
<td>
4125+
The simulated GATT descriptor response code for a GATT descriptor
4126+
write attempt.
4127+
</td>
4128+
</tr>
41054129
</table>
41064130

41074131
<div algorithm="BluetoothRemoteGATTDescriptor constructor">
@@ -4146,27 +4170,48 @@ readValue()</dfn></code> method, when invoked, MUST run the following steps:
41464170
"{{InvalidStateError}}" {{DOMException}}.
41474171
1. Return a |gatt|-[=connection-checking wrapper=] around [=a new promise=]
41484172
|promise| and run the following steps [=in parallel=]:
4149-
1. If the UA is currently using the Bluetooth system, it MAY [=queue a
4150-
global task=] on the [=Bluetooth task source=] given |global| to
4151-
[=reject=] |promise| with a "{{NetworkError}}" {{DOMException}} and
4152-
abort these steps.
4173+
1. If |global|'s [=Window/navigable=]'s
4174+
[=navigable/top-level traversable=]'s <a>simulated Bluetooth adapter</a>
4175+
is not empty, run the following steps:
4176+
1. If [=this=].{{[[automatedDescriptorReadResponse]]}} is not `"not-expected"`,
4177+
[=queue a global task=] on the [=Bluetooth task source=] given |global| to
4178+
[=reject=] |promise| with a "{{InvalidStateError}}" {{DOMException}} and abort
4179+
these steps.
4180+
1. [=Trigger a simulated descriptor event=] given |global|'s
4181+
[=Window/navigable=], [=this=].{{BluetoothRemoteGATTServer/device}},
4182+
|descriptor|, and `read`.
4183+
1. Set [=this=].{{[[automatedDescriptorReadResponse]]}} to `"expected"`,
4184+
and wait for it to change.
4185+
1. Let |response| be [=this=].{{[[automatedDescriptorReadResponse]]}}.
4186+
1. Set [=this=].{{[[automatedDescriptorReadResponse]]}} to `"not-expected"`.
4187+
1. If |response| is not `0`, do the following sub-steps:
4188+
1. [=Queue a global task=] on the [=Bluetooth task source=] given
4189+
|global| to [=reject=] |promise| with a "{{NetworkError}}"
4190+
{{DOMException}} and abort these steps.
4191+
1. Otherwise, let |buffer| be a [=new=] {{ArrayBuffer}} containing
4192+
[=this=].{{[[automatedDescriptorReadResponseData]]}}.
4193+
1. Otherwise, run the following steps:
4194+
1. If the UA is currently using the Bluetooth system, it MAY [=queue a
4195+
global task=] on the [=Bluetooth task source=] given |global| to
4196+
[=reject=] |promise| with a "{{NetworkError}}" {{DOMException}} and
4197+
abort these steps.
41534198

4154-
Issue(188): Implementations may be able to avoid this {{NetworkError}},
4155-
but for now sites need to serialize their use of this API
4156-
and/or give the user a way to retry failed operations.
4157-
1. Use either the [=Read Characteristic Descriptors=] or the [=Read Long
4158-
Characteristic Descriptors=] sub-procedure to retrieve the value of
4159-
|descriptor|. Handle errors as described in
4160-
<a href="#error-handling"></a>.
4199+
Issue(188): Implementations may be able to avoid this {{NetworkError}},
4200+
but for now sites need to serialize their use of this API
4201+
and/or give the user a way to retry failed operations.
4202+
1. Use either the [=Read Characteristic Descriptors=] or the [=Read Long
4203+
Characteristic Descriptors=] sub-procedure to retrieve the value of
4204+
|descriptor| and let |buffer| be a [=new=] {{ArrayBuffer}} holding the
4205+
retrieved value. Handle errors as described in
4206+
<a href="#error-handling"></a>.
41614207
1. [=Queue a global task=] on the [=Bluetooth task source=] given |global|
41624208
to perform the following steps:
41634209
1. If |promise| is not in |gatt|.{{[[activeAlgorithms]]}}, [=reject=]
41644210
|promise| with a "{{NetworkError}}" {{DOMException}} and abort
41654211
these steps.
41664212
1. If the sub-procedure above returned an error, [=reject=] |promise|
41674213
with that error and abort these steps.
4168-
1. Let |buffer| be a [=new=] {{ArrayBuffer}} holding the retrieved
4169-
value, and assign a [=new=] {{DataView}} created with |buffer| to
4214+
1. Assign a [=new=] {{DataView}} created with |buffer| to
41704215
[=this=].{{BluetoothRemoteGATTDescriptor/value}}.
41714216
1. [=Resolve=] |promise| with
41724217
[=this=].{{BluetoothRemoteGATTDescriptor/value}}.
@@ -4194,18 +4239,37 @@ following steps:
41944239
"{{InvalidStateError}}" {{DOMException}}.
41954240
1. Return a |gatt|-[=connection-checking wrapper=] around [=a new promise=]
41964241
|promise| and run the following steps [=in parallel=].
4197-
1. If the UA is currently using the Bluetooth system, it MAY [=queue a
4198-
global task=] on the [=Bluetooth task source=] given |global| to
4199-
[=reject=] |promise| with a "{{NetworkError}}" {{DOMException}} and
4200-
abort these steps.
4242+
1. If |global|'s [=Window/navigable=]'s
4243+
[=navigable/top-level traversable=]'s <a>simulated Bluetooth adapter</a>
4244+
is not empty, run the following steps:
4245+
1. If [=this=].{{[[automatedDescriptorWriteResponse]]}} is not `"not-expected"`,
4246+
[=queue a global task=] on the [=Bluetooth task source=] given |global| to
4247+
[=reject=] |promise| with a "{{InvalidStateError}}" {{DOMException}} and abort
4248+
these steps.
4249+
1. [=Trigger a simulated descriptor event=] given |global|'s
4250+
[=Window/navigable=], [=this=].{{BluetoothRemoteGATTServer/device}},
4251+
|descriptor|, `write`, and |bytes|.
4252+
1. Set [=this=].{{[[automatedDescriptorWriteResponse]]}} to `"expected"`,
4253+
and wait for it to change.
4254+
1. Let |response| be [=this=].{{[[automatedDescriptorWriteResponse]]}}.
4255+
1. Set [=this=].{{[[automatedDescriptorWriteResponse]]}} to `"not-expected"`.
4256+
1. If |response| is not `0`, do the following sub-steps:
4257+
1. [=Queue a global task=] on the [=Bluetooth task source=] given
4258+
|global| to [=reject=] |promise| with a "{{NetworkError}}"
4259+
{{DOMException}} and abort these steps.
4260+
1. Otherwise, run the following steps:
4261+
1. If the UA is currently using the Bluetooth system, it MAY [=queue a
4262+
global task=] on the [=Bluetooth task source=] given |global| to
4263+
[=reject=] |promise| with a "{{NetworkError}}" {{DOMException}} and
4264+
abort these steps.
42014265

4202-
Issue(188): Implementations may be able to avoid this {{NetworkError}},
4203-
but for now sites need to serialize their use of this API
4204-
and/or give the user a way to retry failed operations.
4205-
1. Use either the [=Write Characteristic Descriptors=] or the [=Write Long
4206-
Characteristic Descriptors=] sub-procedure to write |bytes| to
4207-
|descriptor|. Handle errors as described in
4208-
<a href="#error-handling"></a>.
4266+
Issue(188): Implementations may be able to avoid this {{NetworkError}},
4267+
but for now sites need to serialize their use of this API
4268+
and/or give the user a way to retry failed operations.
4269+
1. Use either the [=Write Characteristic Descriptors=] or the [=Write Long
4270+
Characteristic Descriptors=] sub-procedure to write |bytes| to
4271+
|descriptor|. Handle errors as described in
4272+
<a href="#error-handling"></a>.
42094273
1. [=Queue a global task=] on the [=Bluetooth task source=] given |global|
42104274
to perform the following steps:
42114275
1. If |promise| is not in |gatt|.{{[[activeAlgorithms]]}}, [=reject=]
@@ -5139,11 +5203,15 @@ is an <a>ordered map</a> of Bluetooth <a>UUID</a> strings to <a>simulated GATT c
51395203

51405204
A <dfn>simulated GATT characteristic</dfn> is a software defined [=Characteristic=] that belongs to a
51415205
<a>simulated GATT service</a>, has a property of <a>UUID</a>, a property of <a>Characteristic Properties</a>,
5142-
and is known-present in the <a>Bluetooth cache</a>.
5206+
is known-present in the <a>Bluetooth cache</a>, and has a <dfn>simulated GATT descriptor mapping</dfn>, which
5207+
is an <a>ordered map</a> of Bluetooth <a>UUID</a> strings to <a>simulated GATT descriptors</a>.
51435208

51445209
<dfn>Simulated GATT characteristic properties</dfn> are software defined [=Characteristic Properties=] that belong to a
51455210
<a>simulated GATT characteristic</a> and are known-present in the <a>Bluetooth cache</a>.
51465211

5212+
A <dfn>simulated GATT descriptor</dfn> is a software defined [=Descriptor=] that belongs to a
5213+
<a>simulated GATT characteristic</a>, has a property of <a>UUID</a>, and is known-present in the <a>Bluetooth cache</a>.
5214+
51475215
Issue: CDDL snippetes use the "text" type instead of
51485216
"browsingContext.BrowsingContext" to allow indepedent programmatic
51495217
processing of CDDL snippets. Currently, other modules cannot be
@@ -5757,7 +5825,7 @@ The [=remote end steps=] with command parameters |params| are:
57575825
and add a mapping from |simulatedGattService| to the resulting {{Promise}} in
57585826
|simulatedDeviceInstance|.{{[[context]]}}.{{Bluetooth/[[attributeInstanceMap]]}}.
57595827
1. Return [=success=] with data `null`.
5760-
1. Else if |params|[`"type"`] is `"remove"`:
5828+
1. If |params|[`"type"`] is `"remove"`:
57615829
1. If |serviceMapping|[|uuid|] [=map/exists=], let |simulatedGattService| be |serviceMapping|[|uuid|].
57625830
1. Otherwise, return [=error=] with [=error code=] [=invalid element state=].
57635831
1. Remove |simulatedGattService| from |simulatedDeviceInstance|.{{[[context]]}}.{{Bluetooth/[[attributeInstanceMap]]}}.
@@ -5867,7 +5935,7 @@ The [=remote end steps=] with command parameters |params| are:
58675935
and add a mapping from |simulatedGattCharacteristic| to the resulting {{Promise}} in
58685936
|simulatedDeviceInstance|.{{[[context]]}}.{{Bluetooth/[[attributeInstanceMap]]}}.
58695937
1. Return [=success=] with data `null`.
5870-
1. Else if |params|[`"type"`] is `"remove"`:
5938+
1. If |params|[`"type"`] is `"remove"`:
58715939
1. If |params|[`"characteristicProperties"`] [=map/exists=], return [=error=] with [=error code=] [=invalid argument=].
58725940
1. If |characteristicMapping|[|characteristicUuid|] [=map/exists=], let |simulatedGattCharacteristic|
58735941
be |characteristicMapping|[|characteristicUuid|].
@@ -6025,7 +6093,46 @@ bluetooth.SimulateDescriptorParameters = {
60256093

60266094
<div algorithm="remote end steps for bluetooth.simulateDescriptor">
60276095

6028-
Issue: TODO: Finish the algorithm of bluetooth.simulateDescriptor.
6096+
1. Let |contextId| be |params|[`"context"`].
6097+
1. Let |navigable| be the result of [=trying=] to [=get a navigable=] with |contextId|.
6098+
1. Let |deviceAddress| be |params|[`"address"`].
6099+
1. Let |simulatedBluetoothAdapter| be |navigable|'s <a>simulated Bluetooth adapter</a>.
6100+
1. If |simulatedBluetoothAdapter| is empty, return [=error=] with [=error code=] [=invalid argument=].
6101+
1. Let |deviceMapping| be |simulatedBluetoothAdapter|'s <a>simulated Bluetooth device mapping</a>.
6102+
1. If |deviceMapping|[|deviceAddress|] [=map/exists=], let |simulatedDevice| be |deviceMapping|[|deviceAddress|].
6103+
1. Otherwise, return [=error=] with [=error code=] [=invalid argument=].
6104+
1. Let |simulatedDeviceInstance| be the result of <a>get the <code>BluetoothDevice</code> representing</a>
6105+
|simulatedDevice| inside |navigable|'s <a>active window</a>'s <a spec=HTML>associated <code>Navigator</code></a>'s
6106+
[=associated Bluetooth=].
6107+
1. Let |serviceMapping| be |simulatedDevice|'s <a>simulated GATT service mapping</a>.
6108+
1. Let |serviceUuid| be |params|[`"serviceUuid"`].
6109+
1. If |serviceMapping|[|serviceUuid|] [=map/exists=], let |simulatedService| be |serviceMapping|[|serviceUuid|].
6110+
1. Otherwise, return [=error=] with [=error code=] [=invalid argument=].
6111+
1. Let |characteristicMapping| be |simulatedService|'s <a>simulated GATT characteristic mapping</a>.
6112+
1. Let |characteristicUuid| be |params|[`"characteristicUuid"`].
6113+
1. If |characteristicMapping|[|characteristicUuid|] [=map/exists=], let |simulatedCharacteristic| be
6114+
|characteristicMapping|[|characteristicUuid|].
6115+
1. Otherwise, return [=error=] with [=error code=] [=invalid argument=].
6116+
1. Let |descriptorMapping| be |simulatedCharacteristic|'s <a>simulated GATT descriptor mapping</a>.
6117+
1. Let |descriptorUuid| be |params|[`"descriptorUuid"`].
6118+
1. If |params|[`"type"`] is `"add"`:
6119+
1. If |descriptorMapping|[|descriptorUuid|] [=map/exists=], return [=error=] with
6120+
[=error code=] [=invalid element state=].
6121+
1. Let |simulatedGattDescriptor| be a new <a>simulated GATT descriptor</a>.
6122+
1. Set |simulatedGattDescriptor|'s <a>UUID</a> to |descriptorUuid|.
6123+
1. Set |descriptorMapping|[|descriptorUuid|] to |simulatedGattDescriptor|.
6124+
1. <a>Create a <code>BluetoothRemoteGATTDescriptor</code> representing</a> |simulatedGattDescriptor|
6125+
and add a mapping from |simulatedGattDescriptor| to the resulting {{Promise}} in
6126+
|simulatedDeviceInstance|.{{[[context]]}}.{{Bluetooth/[[attributeInstanceMap]]}}.
6127+
1. Return [=success=] with data `null`.
6128+
1. If |params|[`"type"`] is `"remove"`:
6129+
1. If |descriptorMapping|[|descriptorUuid|] [=map/exists=], let |simulatedGattDescriptor|
6130+
be |descriptorMapping|[|descriptorUuid|].
6131+
1. Otherwise, return [=error=] with [=error code=] [=invalid element state=].
6132+
1. Remove |simulatedGattDescriptor| from |simulatedDeviceInstance|.{{[[context]]}}.{{Bluetooth/[[attributeInstanceMap]]}}.
6133+
1. Remove |descriptorUuid| from |descriptorMapping|.
6134+
1. Return [=success=] with data `null`.
6135+
1. Return [=error=] with [=error code=] [=invalid argument=].
60296136

60306137
</div>
60316138

@@ -6087,7 +6194,44 @@ bluetooth.SimulateDescriptorResponseParameters = {
60876194

60886195
<div algorithm="remote end steps for bluetooth.simulateDescriptorResponse">
60896196

6090-
Issue: TODO: Finish the algorithm of bluetooth.simulateDescriptorResponse.
6197+
1. Let |contextId| be |params|[`"context"`].
6198+
1. Let |navigable| be the result of [=trying=] to [=get a navigable=] with |contextId|.
6199+
1. Let |deviceAddress| be |params|[`"address"`].
6200+
1. Let |simulatedBluetoothAdapter| be |navigable|'s <a>simulated Bluetooth adapter</a>.
6201+
1. If |simulatedBluetoothAdapter| is empty, return [=error=] with [=error code=] [=invalid argument=].
6202+
1. Let |deviceMapping| be |simulatedBluetoothAdapter|'s <a>simulated Bluetooth device mapping</a>.
6203+
1. If |deviceMapping|[|deviceAddress|] [=map/exists=], let |simulatedDevice| be |deviceMapping|[|deviceAddress|].
6204+
Otherwise, return [=error=] with [=error code=] [=invalid argument=].
6205+
1. Let |serviceMapping| be |simulatedDevice|'s <a>simulated GATT service mapping</a>.
6206+
1. Let |serviceUuid| be |params|[`"serviceUuid"`].
6207+
1. If |serviceMapping|[|serviceUuid|] [=map/exists=], let |simulatedService| be |serviceMapping|[|serviceUuid|].
6208+
1. Otherwise, return [=error=] with [=error code=] [=invalid argument=].
6209+
1. Let |characteristicMapping| be |simulatedService|'s <a>simulated GATT characteristic mapping</a>.
6210+
1. Let |characteristicUuid| be |params|[`"characteristicUuid"`].
6211+
1. If |characteristicMapping|[|characteristicUuid|] [=map/exists=], let |simulatedCharacteristic|
6212+
be |characteristicMapping|[|characteristicUuid|].
6213+
1. Otherwise, return [=error=] with [=error code=] [=invalid element state=].
6214+
1. Let |descriptorMapping| be |simulatedCharacteristic|'s <a>simulated GATT descriptor mapping</a>.
6215+
1. Let |descriptorUuid| be |params|[`"descriptorUuid"`].
6216+
1. If |descriptorMapping|[|descriptorUuid|] [=map/exists=], let |simulatedDescriptor|
6217+
be |descriptorMapping|[|descriptorUuid|].
6218+
1. Otherwise, return [=error=] with [=error code=] [=invalid element state=].
6219+
1. Let |simulatedDeviceInstance| be the result of <a>get the <code>BluetoothDevice</code> representing</a>
6220+
|simulatedDevice| inside |navigable|'s <a>active window</a>'s <a spec=HTML>associated <code>Navigator</code></a>'s
6221+
[=associated Bluetooth=].
6222+
1. Let |promise| be |simulatedDeviceInstance|.{{[[context]]}}.{{Bluetooth/[[attributeInstanceMap]]}}[|simulatedDescriptor|].
6223+
1. <a>Upon fulfillment</a> of |promise| with |descriptor|, run the following steps:
6224+
1. If |params|[`"type"`] is `read`, run the following steps:
6225+
1. If |descriptor|.{{[[automatedDescriptorReadResponse]]}} is `expected`,
6226+
set |descriptor|.{{[[automatedDescriptorReadResponse]]}} to |params|[`"code"`] and
6227+
|descriptor|.{{[[automatedDescriptorReadResponseData]]}} to [=a copy of the bytes held=]
6228+
by |params|[`"data"`].
6229+
1. Otherwise, return [=error=] with [=error code=] [=invalid element state=].
6230+
1. If |params|[`"type"`] is `write`, run the following steps:
6231+
1. If |characteristic|.{{[[automatedDescriptorWriteResponse]]}} is `expected`,
6232+
set |characteristic|.{{[[automatedDescriptorWriteResponse]]}} to |params|[`"code"`].
6233+
1. Otherwise, return [=error=] with [=error code=] [=invalid element state=].
6234+
1. Otherwise, return [=error=] with [=error code=] [=invalid argument=].
60916235

60926236
</div>
60936237

@@ -6212,7 +6356,11 @@ To <dfn>trigger a simulated characteristic event </dfn> given a [=navigable=] |n
62126356
1. Set |params|[`"serviceUuid"`] to |service|'s <a>UUID</a>.
62136357
1. Set |params|[`"characteristicUuid"`] to |characteristic|'s <a>UUID</a>.
62146358
1. Set |params|[`"type"`] to |type|.
6215-
1. If |type| is `write`, set |params|[`"data"`] to a [=new=] {{Uint8Array}} wrapping a [=new=] {{ArrayBuffer}} containing |bytes|.
6359+
1. If |type| is `write`, run the following steps:
6360+
1. Let |data| be an empty list.
6361+
1. For each |byte| in |bytes|:
6362+
1. Append |byte|'s [=byte/value=] to |data|.
6363+
1. Set |params|[`"data"`] to |data|.
62166364
1. Let |body| be a [=map=] matching the <code>bluetooth.CharacteristicEventGenerated</code> production, with the
62176365
<code>params</code> field set to |params|.
62186366
1. Let |relatedNavigables| be a [=/set=] containing |navigable|.
@@ -6243,7 +6391,31 @@ bluetooth.DescriptorEventGeneratedParameters = {
62436391

62446392
<div algorithm="remote end event trigger for bluetooth.descriptorEventGenerated">
62456393

6246-
Issue: TODO: Finish the algorithm of bluetooth.descriptorEventGenerated.
6394+
To <dfn>trigger a simulated descriptor event </dfn> given a [=navigable=] |navigable|, a {{BluetoothDevice}} |device|, a
6395+
<a>simulated GATT descriptor</a> |descriptor|, <a>string</a> |type|, and an optional <a>byte sequence</a> |bytes|:
6396+
6397+
1. Let |navigableId| be |navigable|'s [=navigable id=].
6398+
1. Let |params| be a [=map=] matching the <code>bluetooth.DescriptorEventGeneratedParameters</code> production and run
6399+
the following steps:
6400+
1. Set |params|[`"context"`] to |navigableId|.
6401+
1. Set |params|[`"address"`] to |device|.{{[[representedDevice]]}}'s address.
6402+
1. Let |characteristic| be the <a>simulated GATT characteristic</a> containing |descriptor|.
6403+
1. Let |service| be the <a>simulated GATT service</a> containing |characteristic|.
6404+
1. Set |params|[`"serviceUuid"`] to |service|'s <a>UUID</a>.
6405+
1. Set |params|[`"characteristicUuid"`] to |characteristic|'s <a>UUID</a>.
6406+
1. Set |params|[`"descriptorUuid"`] to |descriptor|'s <a>UUID</a>.
6407+
1. Set |params|[`"type"`] to |type|.
6408+
1. If |type| is `write`, run the following steps:
6409+
1. Let |data| be an empty list.
6410+
1. For each |byte| in |bytes|:
6411+
1. Append |byte|'s [=byte/value=] to |data|.
6412+
1. Set |params|[`"data"`] to |data|.
6413+
1. Let |body| be a [=map=] matching the <code>bluetooth.DescriptorEventGenerated</code> production, with the
6414+
<code>params</code> field set to |params|.
6415+
1. Let |relatedNavigables| be a [=/set=] containing |navigable|.
6416+
1. For each |session| in the [=set of sessions for which an event is enabled=] given
6417+
"<code>bluetooth.descriptorEventGenerated</code>" and |relatedNavigables|:
6418+
1. [=Emit an event=] with |session| and |body|.
62476419

62486420
</div>
62496421

0 commit comments

Comments
 (0)