• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#/usr/bin/env python3.4
2#
3# Copyright (C) 2016 The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License"); you may not
6# use this file except in compliance with the License. You may obtain a copy of
7# the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14# License for the specific language governing permissions and limitations under
15# the License.
16"""
17This test script exercises different GATT write procedures.
18"""
19
20from acts.test_utils.bt.BluetoothBaseTest import BluetoothBaseTest
21from acts.test_utils.bt.GattConnectedBaseTest import GattConnectedBaseTest
22from acts.test_utils.bt.GattEnum import GattCharacteristic
23from acts.test_utils.bt.GattEnum import GattDescriptor
24from acts.test_utils.bt.GattEnum import MtuSize
25from acts.test_utils.bt.GattEnum import GattEvent
26from acts.test_utils.bt.GattEnum import GattCbStrings
27from acts.test_utils.bt.GattEnum import GattConnectionPriority
28
29
30class GattWriteTest(GattConnectedBaseTest):
31    @BluetoothBaseTest.bt_test_wrap
32    def test_write_char(self):
33        """Test write characteristic value
34
35        Test write characteristic value using Write Request
36
37        1. Central: write WRITABLE_CHAR_UUID characteristic with char_value
38           using write request.
39        2. Peripheral: receive the written data.
40        3. Peripheral: send response with status 0 (success).
41        4. Central: make sure write callback is called.
42
43        Expected Result:
44        Verify that write request/response is properly delivered.
45
46        Returns:
47          Pass if True
48          Fail if False
49
50        TAGS: LE, GATT, Characteristic
51        Priority: 0
52        """
53        char_value = [1, 2, 3, 4, 5, 6, 7]
54        self.cen_ad.droid.gattClientCharacteristicSetValue(
55            self.bluetooth_gatt, self.discovered_services_index,
56            self.test_service_index, self.WRITABLE_CHAR_UUID, char_value)
57
58        self.cen_ad.droid.gattClientCharacteristicSetWriteType(
59            self.bluetooth_gatt, self.discovered_services_index,
60            self.test_service_index, self.WRITABLE_CHAR_UUID,
61            GattCharacteristic.WRITE_TYPE_DEFAULT.value)
62
63        self.cen_ad.droid.gattClientWriteCharacteristic(
64            self.bluetooth_gatt, self.discovered_services_index,
65            self.test_service_index, self.WRITABLE_CHAR_UUID)
66
67        event = self._server_wait(GattEvent.CHAR_WRITE_REQ)
68
69        request_id = event['data']['requestId']
70        self.assertEqual(True, event['data']['responseNeeded'],
71                         "Should need response")
72        self.assertEqual(char_value, event['data']['value'])
73        self.assertEqual(0, event['data']['offset'])
74
75        bt_device_id = 0
76        status = 0
77        #both offset and return value don't matter, just the status
78        offset = 0
79        self.per_ad.droid.gattServerGetConnectedDevices(self.gatt_server)
80        self.per_ad.droid.gattServerSendResponse(
81            self.gatt_server, bt_device_id, request_id, status, offset, [])
82
83        event = self._client_wait(GattEvent.CHAR_WRITE)
84        self.assertEqual(status, event["data"]["Status"],
85                         "Write status should be 0")
86        # Write response doesn't carry any data expcept status
87        return True
88
89    @BluetoothBaseTest.bt_test_wrap
90    def test_write_descr(self):
91        """Test write descriptor value
92
93        Test write descriptor value
94
95        1. Central: write WRITABLE_DESC_UUID descriptor with desc_value.
96        2. Peripheral: receive the written data.
97        3. Peripheral: send response with status 0 (success).
98        4. Central: make sure write callback is called.
99
100        Expected Result:
101        Verify that write request/response is properly delivered.
102
103        Returns:
104          Pass if True
105          Fail if False
106
107        TAGS: LE, GATT, Descriptor
108        Priority: 0
109        """
110        desc_value = [1, 2, 3, 4, 5, 6, 7]
111        self.cen_ad.droid.gattClientDescriptorSetValue(
112            self.bluetooth_gatt, self.discovered_services_index,
113            self.test_service_index, self.WRITABLE_CHAR_UUID,
114            self.WRITABLE_DESC_UUID, desc_value)
115
116        self.cen_ad.droid.gattClientWriteDescriptor(
117            self.bluetooth_gatt, self.discovered_services_index,
118            self.test_service_index, self.WRITABLE_CHAR_UUID,
119            self.WRITABLE_DESC_UUID)
120
121        event = self._server_wait(GattEvent.DESC_WRITE_REQ)
122
123        request_id = event['data']['requestId']
124        self.assertEqual(True, event['data']['responseNeeded'],
125                         "Should need response")
126        self.assertEqual(desc_value, event['data']['value'])
127        self.assertEqual(0, event['data']['offset'])
128
129        bt_device_id = 0
130        status = 0
131        #both offset and return value don't matter, just the status
132        offset = 0
133        self.per_ad.droid.gattServerGetConnectedDevices(self.gatt_server)
134        self.per_ad.droid.gattServerSendResponse(
135            self.gatt_server, bt_device_id, request_id, status, offset, [])
136
137        event = self._client_wait(GattEvent.DESC_WRITE)
138        self.assertEqual(status, event["data"]["Status"],
139                         "Write status should be 0")
140        # Write response doesn't carry any data except status
141        return True
142
143    @BluetoothBaseTest.bt_test_wrap
144    def test_write_char_no_resp(self):
145        """Test write characteristic value
146
147        Test write characteristic value using Write Command
148
149        1. Central: write WRITABLE_CHAR_UUID characteristic with char_value
150           using write command.
151        2. Central: make sure write callback is called.
152        3. Peripheral: receive the written data.
153
154        Expected Result:
155        Verify that write command is properly delivered.
156
157        Returns:
158          Pass if True
159          Fail if False
160
161        TAGS: LE, GATT, Characteristic
162        Priority: 0
163        """
164        char_value = [1, 2, 3, 4, 5, 6, 7]
165        self.cen_ad.droid.gattClientCharacteristicSetValue(
166            self.bluetooth_gatt, self.discovered_services_index,
167            self.test_service_index, self.WRITABLE_CHAR_UUID, char_value)
168
169        self.cen_ad.droid.gattClientCharacteristicSetWriteType(
170            self.bluetooth_gatt, self.discovered_services_index,
171            self.test_service_index, self.WRITABLE_CHAR_UUID,
172            GattCharacteristic.WRITE_TYPE_NO_RESPONSE.value)
173
174        self.cen_ad.droid.gattClientWriteCharacteristic(
175            self.bluetooth_gatt, self.discovered_services_index,
176            self.test_service_index, self.WRITABLE_CHAR_UUID)
177
178        event = self._client_wait(GattEvent.CHAR_WRITE)
179        if event["data"]["Status"] != 0:
180            self.log.error("Write status should be 0")
181            return False
182
183        event = self._server_wait(GattEvent.CHAR_WRITE_REQ)
184
185        request_id = event['data']['requestId']
186        self.assertEqual(False, event['data']['responseNeeded'],
187                         "Should not need response")
188        self.assertEqual(0, event['data']['offset'])
189        self.assertEqual(char_value, event['data']['value'])
190
191        return True
192
193    @BluetoothBaseTest.bt_test_wrap
194    def test_write_characteristic_long_no_resp(self):
195        """Test write characteristic value
196
197        Test write characteristic value using Write Command
198
199        1. Central: write WRITABLE_CHAR_UUID characteristic with char_value
200           using write command.
201        2. Central: make sure write callback is called.
202        3. Peripheral: receive the written data. Check it was properly trimmed.
203
204        Expected Result:
205        Verify that write command is properly trimmed and delivered.
206
207        Returns:
208          Pass if True
209          Fail if False
210
211        TAGS: LE, GATT, Characteristic
212        Priority: 0
213        """
214        char_value = []
215        for i in range(512):
216            char_value.append(i % 256)
217
218        self.cen_ad.droid.gattClientCharacteristicSetValue(
219            self.bluetooth_gatt, self.discovered_services_index,
220            self.test_service_index, self.WRITABLE_CHAR_UUID, char_value)
221
222        self.cen_ad.droid.gattClientCharacteristicSetWriteType(
223            self.bluetooth_gatt, self.discovered_services_index,
224            self.test_service_index, self.WRITABLE_CHAR_UUID,
225            GattCharacteristic.WRITE_TYPE_NO_RESPONSE.value)
226
227        self.cen_ad.droid.gattClientWriteCharacteristic(
228            self.bluetooth_gatt, self.discovered_services_index,
229            self.test_service_index, self.WRITABLE_CHAR_UUID)
230
231        event = self._server_wait(GattEvent.CHAR_WRITE_REQ)
232
233        request_id = event['data']['requestId']
234        self.assertEqual(False, event['data']['responseNeeded'])
235
236        # value shall be trimmed to MTU-3
237        trimmed_value = char_value[0:self.mtu - 3]
238        self.assertEqual(
239            trimmed_value, event['data']['value'],
240            "Received value should be sent value trimmed to MTU-3")
241
242        event = self._client_wait(GattEvent.CHAR_WRITE)
243        if event["data"]["Status"] != 0:
244            self.log.error("Write status should be 0")
245            return False
246        return True
247
248    @BluetoothBaseTest.bt_test_wrap
249    def test_write_characteristic_stress(self):
250        """Stress test write characteristic value
251
252        Test write characteristic value using Write Request
253
254        1. Central: write WRITABLE_CHAR_UUID characteristic with char_value
255           using write request.
256        2. Peripheral: receive the written data.
257        3. Peripheral: send response with status 0 (success).
258        4. Central: make sure write callback is called.
259        5. Repeat steps 1-4 100 times.
260
261        Expected Result:
262        Verify that write request/response is properly delivered.
263
264        Returns:
265          Pass if True
266          Fail if False
267
268        TAGS: LE, GATT, Characteristic
269        Priority: 0
270        """
271        self.cen_ad.droid.gattClientRequestConnectionPriority(
272            self.bluetooth_gatt,
273            GattConnectionPriority.CONNECTION_PRIORITY_HIGH.value)
274
275        bt_device_id = 0
276
277        self.cen_ad.droid.gattClientCharacteristicSetWriteType(
278            self.bluetooth_gatt, self.discovered_services_index,
279            self.test_service_index, self.WRITABLE_CHAR_UUID,
280            GattCharacteristic.WRITE_TYPE_DEFAULT.value)
281
282        for i in range(100):
283
284            char_value = []
285            for j in range(i, i + self.mtu - 3):
286                char_value.append(j % 256)
287
288            self.cen_ad.droid.gattClientCharacteristicSetValue(
289                self.bluetooth_gatt, self.discovered_services_index,
290                self.test_service_index, self.WRITABLE_CHAR_UUID, char_value)
291
292            self.cen_ad.droid.gattClientWriteCharacteristic(
293                self.bluetooth_gatt, self.discovered_services_index,
294                self.test_service_index, self.WRITABLE_CHAR_UUID)
295
296            event = self._server_wait(GattEvent.CHAR_WRITE_REQ)
297
298            self.log.info("{} event found: {}".format(
299                GattCbStrings.CHAR_WRITE_REQ.value.format(
300                    self.gatt_server_callback), event['data']['value']))
301            request_id = event['data']['requestId']
302            found_value = event['data']['value']
303            if found_value != char_value:
304                self.log.info("Values didn't match. Found: {}, "
305                              "Expected: {}".format(found_value, char_value))
306                return False
307
308            # only status is sent
309            status = 0
310            offset = 0
311            char_value_return = []
312            self.per_ad.droid.gattServerSendResponse(
313                self.gatt_server, bt_device_id, request_id, status, offset,
314                char_value_return)
315
316            event = self._client_wait(GattEvent.CHAR_WRITE)
317            if event["data"]["Status"] != status:
318                self.log.error("Write status should be 0")
319                return False
320
321        return True
322
323    @BluetoothBaseTest.bt_test_wrap
324    def test_write_descriptor_stress(self):
325        """Stress test write descriptor value
326
327        Stress test write descriptor value
328
329        1. Central: write WRITABLE_DESC_UUID descriptor with desc_value.
330        2. Peripheral: receive the written data.
331        3. Peripheral: send response with status 0 (success).
332        4. Central: make sure write callback is called.
333        5. Repeat 1-4 100 times
334
335        Expected Result:
336        Verify that write request/response is properly delivered.
337
338        Returns:
339          Pass if True
340          Fail if False
341
342        TAGS: LE, GATT, Descriptor
343        Priority: 0
344        """
345        self.cen_ad.droid.gattClientRequestConnectionPriority(
346            self.bluetooth_gatt,
347            GattConnectionPriority.CONNECTION_PRIORITY_HIGH.value)
348
349        for i in range(100):
350
351            desc_value = []
352            for j in range(i, i + self.mtu - 3):
353                desc_value.append(j % 256)
354
355            self.cen_ad.droid.gattClientDescriptorSetValue(
356                self.bluetooth_gatt, self.discovered_services_index,
357                self.test_service_index, self.WRITABLE_CHAR_UUID,
358                self.WRITABLE_DESC_UUID, desc_value)
359
360            self.cen_ad.droid.gattClientWriteDescriptor(
361                self.bluetooth_gatt, self.discovered_services_index,
362                self.test_service_index, self.WRITABLE_CHAR_UUID,
363                self.WRITABLE_DESC_UUID)
364
365            event = self._server_wait(GattEvent.DESC_WRITE_REQ)
366
367            self.log.info("{} event found: {}".format(
368                GattCbStrings.CHAR_WRITE_REQ.value.format(
369                    self.gatt_server_callback), event['data']['value']))
370
371            request_id = event['data']['requestId']
372            self.assertEqual(True, event['data']['responseNeeded'],
373                             "Should need response")
374            self.assertEqual(desc_value, event['data']['value'])
375            self.assertEqual(0, event['data']['offset'])
376
377            bt_device_id = 0
378            status = 0
379            #both offset and return value don't matter, just the status
380            offset = 0
381            self.per_ad.droid.gattServerGetConnectedDevices(self.gatt_server)
382            self.per_ad.droid.gattServerSendResponse(
383                self.gatt_server, bt_device_id, request_id, status, offset, [])
384
385            event = self._client_wait(GattEvent.DESC_WRITE)
386            self.assertEqual(status, event["data"]["Status"],
387                             "Write status should be 0")
388            # Write response doesn't carry any data except status
389        return True
390
391    @BluetoothBaseTest.bt_test_wrap
392    def test_write_characteristic_no_resp_stress(self):
393        """Stress test write characteristic value
394
395        Stress test write characteristic value using Write Command
396
397        1. Central: write WRITABLE_CHAR_UUID characteristic with char_value
398           using write command.
399        2. Central: make sure write callback is called.
400        3. Peripheral: receive the written data.
401        4. Repeat steps 1-3 100 times.
402
403        Expected Result:
404        Verify that write command is properly delivered.
405
406        Returns:
407          Pass if True
408          Fail if False
409
410        TAGS: LE, GATT, Characteristic
411        Priority: 0
412        """
413        self.cen_ad.droid.gattClientRequestConnectionPriority(
414            self.bluetooth_gatt,
415            GattConnectionPriority.CONNECTION_PRIORITY_HIGH.value)
416
417        bt_device_id = 0
418
419        self.cen_ad.droid.gattClientCharacteristicSetWriteType(
420            self.bluetooth_gatt, self.discovered_services_index,
421            self.test_service_index, self.WRITABLE_CHAR_UUID,
422            GattCharacteristic.WRITE_TYPE_NO_RESPONSE.value)
423
424        for i in range(100):
425            char_value = []
426            for j in range(i, i + self.mtu - 3):
427                char_value.append(j % 256)
428
429            self.cen_ad.droid.gattClientCharacteristicSetValue(
430                self.bluetooth_gatt, self.discovered_services_index,
431                self.test_service_index, self.WRITABLE_CHAR_UUID, char_value)
432
433            self.cen_ad.droid.gattClientWriteCharacteristic(
434                self.bluetooth_gatt, self.discovered_services_index,
435                self.test_service_index, self.WRITABLE_CHAR_UUID)
436
437            # client shall not wait for server, get complete event right away
438            event = self._client_wait(GattEvent.CHAR_WRITE)
439            if event["data"]["Status"] != 0:
440                self.log.error("Write status should be 0")
441                return False
442
443            event = self._server_wait(GattEvent.CHAR_WRITE_REQ)
444
445            self.log.info("{} event found: {}".format(
446                GattCbStrings.CHAR_WRITE_REQ.value.format(
447                    self.gatt_server_callback), event['data']['value']))
448            request_id = event['data']['requestId']
449            found_value = event['data']['value']
450            if found_value != char_value:
451                self.log.info("Values didn't match. Found: {}, "
452                              "Expected: {}".format(found_value, char_value))
453                return False
454
455        return True
456