1# -*- coding: utf-8 -*-
2# Copyright 2019 Oticon A/S
3# SPDX-License-Identifier: Apache-2.0
4
5from numpy import random;
6import statistics;
7import os;
8import numpy;
9from enum import IntEnum;
10from components.utils import *;
11from components.basic_commands import *;
12from components.address import *;
13from components.events import *;
14from components.resolvable import *;
15from components.advertiser import *;
16from components.scanner import *;
17from components.initiator import *;
18from components.preambles import *;
19from components.addata import *;
20from components.attdata import *;
21from components.smpdata import *;
22from components.pairing import *;
23from components.gattdata import *;
24from components.test_spec import TestSpec;
25
26global lowerIRK, upperIRK, lowerRandomAddress, upperRandomAddress;
27
28"""
29    Send an ATT Profile request...
30"""
31def attRequest(transport, initiator, txData, trace):
32    status = le_data_write(transport, initiator.initiator, initiator.handles[0], 0, 0, txData, 100);
33    trace.trace(10, "LE Data Write Command returns status: 0x%02X" % status);
34    success = status == 0;
35    dataSent = False;
36
37    while success and not dataSent:
38        dataSent = has_event(transport, initiator.initiator, 200)[0];
39        success = success and dataSent;
40        if dataSent:
41            event = get_event(transport, initiator.initiator, 100);
42            trace.trace(7, str(event));
43            dataSent = event.event == Events.BT_HCI_EVT_NUM_COMPLETED_PACKETS;
44
45    return dataSent;
46
47"""
48    Receive an ATT Profile response...
49"""
50def attResponse(transport, initiator, trace, timeout=100):
51    success, rxData, cid = True, [], None;
52
53    while success:
54        dataReady = le_data_ready(transport, initiator.initiator, timeout);
55        timeout = 99;
56        success = success and dataReady;
57        if dataReady:
58            rxPBFlags, rxBCFlags, rxDataPart = le_data_read(transport, initiator.initiator, 100)[2:];
59            trace.trace(10, "LE Data Read Command returns PB=%d BC=%d - %2d data bytes: %s" % \
60                (rxPBFlags, rxBCFlags, len(rxDataPart), formatArray(rxDataPart)));
61            if rxPBFlags & 0x2:
62                cid = struct.unpack("<H", bytes(rxDataPart[2:4]))[0]
63            if cid != 4:
64                trace.trace(6, "Dropping data for non-ATT CID: %d" % cid);
65                continue
66            rxData += rxDataPart;
67
68    return (len(rxData) > 0), rxData;
69
70"""
71    Exchange MTU sizes...
72"""
73def exchangeMTU(transport, initiator, mtuSize, trace):
74    attData = ATTData();
75
76    mtuReply = 0;
77    txData = attData.encode( ATTOpcode.ATT_EXCH_MTU_REQUEST, mtuSize );
78    trace.trace(7, str(attData));
79    success = attRequest( transport, initiator, txData, trace );
80    if success:
81        success, rxData = attResponse( transport, initiator, trace );
82        if success:
83            reply = attData.decode( rxData );
84            trace.trace(7, str(attData));
85            success = reply['opcode'] == ATTOpcode.ATT_EXCH_MTU_RESPONSE;
86            if success:
87                mtuReply = reply['mtu'];
88
89    return success, min(mtuSize, mtuReply);
90
91def __nextByType(transport, initiator, uuid, firstHandle, lastHandle, trace):
92    reply = { 'opcode': ATTOpcode.ATT_ERROR_RESPONSE, 'error': ATTError.ATT_ERROR_ATTRIBUTE_NOT_FOUND };
93    attData = ATTData();
94
95    txData = attData.encode( ATTOpcode.ATT_READ_BY_TYPE_REQUEST, firstHandle, lastHandle, uuid );
96    trace.trace(7, str(attData));
97    success = attRequest( transport, initiator, txData, trace );
98    if success:
99        success, rxData = attResponse( transport, initiator, trace );
100        if success:
101            reply = attData.decode( rxData );
102            trace.trace(7, str(attData));
103            success = reply['opcode'] == ATTOpcode.ATT_READ_BY_TYPE_RESPONSE;
104
105    return success, reply
106
107def __nextFindInformation(transport, initiator, firstHandle, lastHandle, trace):
108    reply = { 'opcode': ATTOpcode.ATT_ERROR_RESPONSE, 'error': ATTError.ATT_ERROR_ATTRIBUTE_NOT_FOUND };
109    attData = ATTData();
110
111    txData = attData.encode( ATTOpcode.ATT_FIND_INFORMATION_REQUEST, firstHandle, lastHandle );
112    trace.trace(7, str(attData));
113    success = attRequest( transport, initiator, txData, trace );
114    if success:
115        success, rxData = attResponse( transport, initiator, trace );
116        if success:
117            reply = attData.decode( rxData );
118            trace.trace(7, str(attData));
119            success = reply['opcode'] == ATTOpcode.ATT_FIND_INFORMATION_RESPONSE;
120
121    return success, reply
122
123"""
124    Discover Primary Services by using ATT_Find_By_Type_Value_Requests
125"""
126def discoverPrimaryService(transport, initiator, serviceUUID, trace):
127    services = { 'handles': [], 'uuids': [] };
128    attData = ATTData();
129
130    success, handle = True, 1;
131    while success:
132        txData = attData.encode( ATTOpcode.ATT_FIND_BY_TYPE_VALUE_REQUEST, handle, 0xffff, 0x2800, toArray( serviceUUID, \
133                                 2 if serviceUUID <= 0xFFFF else 16 ) );
134        success = attRequest( transport, initiator, txData, trace );
135        if not success:
136            break;
137        success, rxData = attResponse( transport, initiator, trace );
138        if not success:
139            break;
140
141        reply = attData.decode( rxData );
142        success = reply['opcode'] == ATTOpcode.ATT_FIND_BY_TYPE_VALUE_RESPONSE;
143        if not success:
144            success = (reply['opcode'] == ATTOpcode.ATT_ERROR_RESPONSE) and \
145                      (reply['error'] == ATTError.ATT_ERROR_ATTRIBUTE_NOT_FOUND) and (len(services['handles']) > 0);
146            break;
147
148        for first, last in zip(reply['handle'][0::2], reply['handle'][1::2]):
149            services['handles'] += [ [ first, last ] ];
150            services['uuids'] += [ serviceUUID ];
151
152        handle = reply['handle'][-1] + 1;
153        if handle > 0xFFFF:
154            break;
155
156    return success, services;
157
158"""
159    Discover Services by using ATT_Read_By_Group_Type_Requests
160"""
161def __discoverServices(transport, initiator, first, last, uuid, trace):
162    services = { 'handles': [], 'uuids': [] };
163    attData = ATTData();
164
165    success, handle = True, first;
166    while success:
167        txData = attData.encode( ATTOpcode.ATT_READ_BY_GROUP_TYPE_REQUEST, handle, last, uuid );
168        trace.trace(7, str(attData));
169        success = attRequest( transport, initiator, txData, trace );
170        if not success:
171            break;
172        success, rxData = attResponse( transport, initiator, trace );
173        if not success:
174            break;
175
176        reply = attData.decode( rxData );
177        trace.trace(7, str(attData));
178        success = reply['opcode'] == ATTOpcode.ATT_READ_BY_GROUP_TYPE_RESPONSE;
179        if not success:
180            success = (reply['opcode'] == ATTOpcode.ATT_ERROR_RESPONSE) and \
181                      (reply['error'] == ATTError.ATT_ERROR_ATTRIBUTE_NOT_FOUND) and (len(services['handles']) > 0);
182            break;
183
184        for _first, _last, _uuid in zip(reply['first_handle'], reply['last_handle'], reply['value']):
185            services['handles'] += [ [ _first, _last ] ];
186            services['uuids'] += [ toNumber(_uuid) ];
187
188        handle = reply['last_handle'][-1] + 1;
189        if handle > last:
190            break;
191
192    return success, services;
193
194"""
195    Discover Primary Services by using ATT_Read_By_Group_Type_Requests
196"""
197def discoverPrimaryServices(transport, initiator, trace):
198    return __discoverServices(transport, initiator, 0x0001, 0xffff, 0x2800, trace);
199
200"""
201    Discover Secondary Services by using ATT_Read_By_Group_Type_Requests
202"""
203def discoverSecondaryServices(transport, initiator, trace):
204    return __discoverServices(transport, initiator, 0x0001, 0xffff, 0x2801, trace);
205
206"""
207    Discover Secondary Services by using ATT_Read_By_Type_Requests
208"""
209def secondaryServicesByType(transport, initiator, trace):
210    services = { 'handle': [], 'uuid': [] };
211    uuid, attData = 0x2801, ATTData();
212
213    success, handle = True, 1;
214    while success:
215        success, reply = __nextByType(transport, initiator, uuid, handle, 0xffff, trace);
216        if not success:
217            success = (reply['opcode'] == ATTOpcode.ATT_ERROR_RESPONSE) and \
218                      (reply['error'] == ATTError.ATT_ERROR_ATTRIBUTE_NOT_FOUND) and (len(services['handle']) > 0);
219            break;
220
221        for _handle, _value in zip(reply['handle'], reply['value']):
222            services['handle'] += [ _handle ];
223            if len(_value) > 0:
224                services['uuid'] += [ toNumber(_value) ];
225            else:
226                """
227                    NOTE: Test Specification suggest to issue a ATT_READ_REQUEST to get the 128-bit UUID,
228                          but the ATT_READ_RESPONSE will only contain the handle range.
229                """
230                success, _service = __discoverServices(transport, initiator, _handle, _handle, uuid, trace);
231                if success:
232                    services['uuid'] += _service['uuids'];
233
234        handle = reply['handle'][-1] + 1;
235        if handle > 0xFFFF:
236            break;
237
238    return success, services;
239
240"""
241    Discover Included Services by using ATT_Read_By_Type_Requests
242"""
243def includedServicesByType(transport, initiator, trace):
244    services = { 'handles': [], 'uuids': [] };
245    uuid, attData = 0x2802, ATTData();
246
247    success, handle = True, 1;
248    while success:
249        success, reply = __nextByType(transport, initiator, uuid, handle, 0xffff, trace);
250        if not success:
251            success = (reply['opcode'] == ATTOpcode.ATT_ERROR_RESPONSE) and \
252                      (reply['error'] == ATTError.ATT_ERROR_ATTRIBUTE_NOT_FOUND) and (len(services['handles']) > 0);
253            break;
254
255        for _handle, _value in zip(reply['handle'], reply['value']):
256            services['handles'] += [ [ toNumber(_value[:2]), toNumber(_value[2:4]) ] ];
257            if len(_value) > 4:
258                services['uuids'] += [ toNumber(_value[4:]) ];
259            else:
260                """
261
262                    NOTE: Test Specification suggest to issue a ATT_READ_REQUEST to get the 128-bit UUID,
263                          but the ATT_READ_RESPONSE will only contain the handle range.
264                """
265                success, _service = __discoverServices(transport, initiator, toNumber(_value[:2]), toNumber(_value[2:4]), 0x2800, trace);
266                if success:
267                    services['uuids'] += _service['uuids'];
268
269        handle = reply['handle'][-1] + 1;
270        if handle > 0xFFFF:
271            break;
272
273    return success, services;
274
275"""
276    Discover Characteristic by using ATT_Read_By_Type_Requests
277"""
278def characteristicByType(transport, initiator, handles, characteristicUUID, ignoreErrors, trace):
279    characteristics = { 'handle': [], 'value': [] };
280    reply = {};
281    attData = ATTData();
282
283    success, handle = True, handles[0];
284    while success:
285        success, reply = __nextByType(transport, initiator, characteristicUUID, handle, handles[1], trace);
286        if success:
287            for _handle, _value in zip(reply['handle'], reply['value']):
288                characteristics['handle'] += [ _handle ];
289                characteristics['value'] += [ _value ];
290
291        elif reply['opcode'] == ATTOpcode.ATT_ERROR_RESPONSE:
292            if reply['error'] == ATTError.ATT_ERROR_ATTRIBUTE_NOT_FOUND:
293                success = len(characteristics['handle']) > 0;
294                break;
295            elif attData.isPermissionError(reply['error']):
296                success = ignoreErrors;
297
298        handle = reply['handle'][-1] + 1;
299        if handle > handles[1]:
300            break;
301
302    return success, characteristics if success else reply;
303
304"""
305    Discover Characteristics by using ATT_Read_By_Type_Requests
306"""
307def characteristicsByType(transport, initiator, handles, trace):
308    characteristics = { 'handle': [], 'property': [], 'value_handle': [], 'uuid': [] };
309    attData = ATTData();
310
311    success, handle, uuid = True, handles[0], 0x2803;
312    while success:
313        success, reply = __nextByType(transport, initiator, uuid, handle, handles[1], trace);
314        if success:
315            for _handle, _value in zip(reply['handle'], reply['value']):
316                characteristics['handle'] += [ _handle ];
317                characteristics['property'] += [ _value[0] ];
318                characteristics['value_handle'] += [ toNumber(_value[1:3]) ];
319                characteristics['uuid'] += [ toNumber(_value[3:]) ];
320
321        elif reply['opcode'] == ATTOpcode.ATT_ERROR_RESPONSE:
322            if reply['error'] == ATTError.ATT_ERROR_ATTRIBUTE_NOT_FOUND:
323                success = len(characteristics['handle']) > 0;
324                break;
325            elif reply['error'] == ATTError.ATT_ERROR_READ_NOT_PERMITTED:
326                success = True;
327
328        handle = reply['handle'][-1] + 1;
329        if handle > handles[1]:
330            break;
331
332    return success, characteristics;
333
334"""
335    Discover Descriptors by using ATT_Find_Information_Requests
336"""
337def discoverDescriptors(transport, initiator, handles, trace):
338    characteristics = { 'handle': [], 'uuid': [] };
339    attData = ATTData();
340
341    success, handle, bCharacteristic, bValue, bDescriptor = True, handles[0], False, False, False;
342    while success:
343        success, reply = __nextFindInformation(transport, initiator, handle, handles[1], trace);
344        if not success:
345            success = (reply['opcode'] == ATTOpcode.ATT_ERROR_RESPONSE) and \
346                      (reply['error'] == ATTError.ATT_ERROR_ATTRIBUTE_NOT_FOUND) and (len(characteristics['handle']) > 0);
347            break;
348        """
349            The hirachy is:
350                CHARACTERIISTIC
351                    VALUE
352                    DESCRIPTOR...
353        """
354        for _handle, _uuid in zip(reply['handle'], reply['uuid']):
355            bCharacteristic = _uuid == 0x2803;
356            bDescriptor = bDescriptor and not bCharacteristic;
357            if bDescriptor:
358                characteristics['handle'] += [ _handle ];
359                characteristics['uuid'] += [ _uuid ];
360            bDescriptor = bDescriptor or bValue;
361            bValue = bCharacteristic;
362
363        handle = reply['handle'][-1] + 1;
364        if handle > handles[1]:
365            break;
366
367    return success, characteristics;
368
369"""
370    Discover Descriptors by using ATT_Find_Information_Requests
371"""
372def specificDescriptors(transport, initiator, handles, uuid, trace):
373    characteristics = { 'handle': [], 'uuid': [] };
374    attData = ATTData();
375
376    success, handle, bCharacteristic, bValue, bDescriptor = True, handles[0], False, False, False;
377    while success:
378        success, reply = __nextFindInformation(transport, initiator, handle, handles[1], trace);
379        if not success:
380            success = (reply['opcode'] == ATTOpcode.ATT_ERROR_RESPONSE) and \
381                      (reply['error'] == ATTError.ATT_ERROR_ATTRIBUTE_NOT_FOUND) and (len(characteristics['handle']) > 0);
382            break;
383
384        for _handle, _uuid in zip(reply['handle'], reply['uuid']):
385            bDescriptor = _uuid == uuid;
386            if bDescriptor:
387                characteristics['handle'] += [ _handle ];
388                characteristics['uuid'] += [ _uuid ];
389
390        handle = reply['handle'][-1] + 1;
391        if handle > handles[1]:
392            break;
393
394    return success, characteristics;
395
396"""
397    Partial Read Blob passing handle and offset
398"""
399def __readBlob(transport, initiator, handle, offset, trace):
400    attData = ATTData();
401    reply = { 'error': -1 };
402
403    txData = attData.encode( ATTOpcode.ATT_READ_BLOB_REQUEST, handle, offset );
404    trace.trace(7, str(attData));
405    success = attRequest( transport, initiator, txData, trace );
406    if success:
407        success, rxData = attResponse( transport, initiator, trace );
408        if success:
409            reply = attData.decode( rxData );
410            trace.trace(7, str(attData));
411            success = reply['opcode'] == ATTOpcode.ATT_READ_BLOB_RESPONSE;
412
413    return success, reply;
414
415"""
416    Read Blob passing handle and MTU size
417"""
418def readBlob(transport, initiator, handle, mtuSize, trace):
419    attData = ATTData();
420
421    value, offset, success = [], 0, True;
422    while success:
423        success, reply = __readBlob(transport, initiator, handle, offset, trace);
424        if success and len(reply['value']) > 0:
425            value += reply['value'];
426            offset += len(reply['value']);
427            if len(reply['value']) < mtuSize-1:
428                break;
429        else:
430            break;
431
432    return success, value if success else reply['error'];
433
434"""
435    Read Characteristic passing handle
436"""
437def readCharacteristic(transport, initiator, handle, trace):
438    attData = ATTData();
439
440    txData = attData.encode( ATTOpcode.ATT_READ_REQUEST, handle );
441    trace.trace(7, str(attData));
442    success = attRequest( transport, initiator, txData, trace );
443    if success:
444        success, rxData = attResponse( transport, initiator, trace );
445        if success:
446            reply = attData.decode( rxData );
447            trace.trace(7, str(attData));
448            success = reply['opcode'] == ATTOpcode.ATT_READ_RESPONSE;
449
450    return success, reply['value'] if success else reply['error'];
451
452"""
453    Read Multiple Characteristics passing handles
454"""
455def readMultipleCharacteristics(transport, initiator, handles, trace):
456    attData = ATTData();
457
458    txData = attData.encode( ATTOpcode.ATT_READ_MULTIPLE_REQUEST, handles );
459    trace.trace(7, str(attData));
460    success = attRequest( transport, initiator, txData, trace );
461    if success:
462        success, rxData = attResponse( transport, initiator, trace );
463        if success:
464            reply = attData.decode( rxData );
465            trace.trace(7, str(attData));
466            success = reply['opcode'] == ATTOpcode.ATT_READ_MULTIPLE_RESPONSE;
467
468    return success, reply['value'] if success else reply['error'];
469
470"""
471    Read Characteristics as a String passing handles
472"""
473def readStringCharacteristic(transport, initiator, handle, trace):
474    success, data = readCharacteristic(transport, initiator, handle, trace);
475
476    return success, bytes(data).decode('utf-8') if success else '';
477
478"""
479    Writing Characteristic passing handle
480"""
481def writeCharacteristic(transport, initiator, handle, data, trace):
482    attData = ATTData();
483    reply = { 'opcode': ATTOpcode.ATT_WRITE_RESPONSE };
484
485    txData = attData.encode( ATTOpcode.ATT_WRITE_REQUEST, handle, data );
486    trace.trace(7, str(attData));
487    success = attRequest( transport, initiator, txData, trace );
488    """
489        Receive the response ATT_WRITE_RESPONSE or ATT_ERROR_RESPONSE...
490    """
491    if success:
492        success, rxData = attResponse( transport, initiator, trace );
493        if success:
494            reply = attData.decode( rxData );
495            trace.trace(7, str(attData));
496            success = reply['opcode'] == ATTOpcode.ATT_WRITE_RESPONSE;
497
498    return success, reply;
499
500"""
501    Writing Characteristic with No Response
502"""
503def writeNoResponse(transport, initiator, handle, data, trace):
504    attData = ATTData();
505    reply = { 'opcode': ATTOpcode.ATT_ERROR_RESPONSE, 'error': 0 };
506
507    txData = attData.encode( ATTOpcode.ATT_WRITE_COMMAND, handle, data );
508    success = attRequest( transport, initiator, txData, trace );
509    """
510        Check for a response, could be an ATT_ERROR_RESPONSE...
511    """
512    if success:
513        success, rxData = attResponse( transport, initiator, trace );
514        if success:
515            reply = attData.decode( rxData );
516            success = False;
517        else:
518            success = True;
519
520    return success, reply;
521
522"""
523    Partial Writing Long Characteristic passing handle, offset and data (ATT_Prepare_Write_Request)
524"""
525def __writeLong(transport, initiator, handle, data, offset, trace):
526    attData = ATTData();
527    reply = { 'opcode': ATTOpcode.ATT_ERROR_RESPONSE, 'error': -1 };
528
529    txData = attData.encode( ATTOpcode.ATT_PREPARE_WRITE_REQUEST, handle, offset, data );
530    success = attRequest( transport, initiator, txData, trace );
531    """
532        Check for a response, could be an ATT_ERROR_RESPONSE...
533    """
534    if success:
535        success, rxData = attResponse( transport, initiator, trace );
536        if success:
537            reply = attData.decode( rxData );
538            success = reply['opcode'] == ATTOpcode.ATT_PREPARE_WRITE_RESPONSE;
539
540    return success, reply;
541
542"""
543    Partial Writing Long Characteristic (ATT_Execute_Write_Request)
544"""
545def __writeExecute(transport, initiator, trace):
546    attData = ATTData();
547    reply = { 'opcode': ATTOpcode.ATT_ERROR_RESPONSE, 'error': -1 };
548
549    txData = attData.encode( ATTOpcode.ATT_EXECUTE_WRITE_REQUEST, 1 );
550    success = attRequest( transport, initiator, txData, trace );
551    if success:
552        success, rxData = attResponse( transport, initiator, trace );
553        if success:
554            reply = attData.decode( rxData );
555            success = reply['opcode'] == ATTOpcode.ATT_EXECUTE_WRITE_RESPONSE;
556
557    return success, reply;
558
559"""
560    Writing Long Characteristic passing handle, data and MTU size
561"""
562def writeLong(transport, initiator, handle, data, mtuSize, trace):
563    offset, success, attData = 0, True, ATTData();
564    reply = { 'opcode': ATTOpcode.ATT_ERROR_RESPONSE, 'error': 0 };
565
566    while success:
567        success, reply = __writeLong(transport, initiator, handle, \
568                                     data[offset:offset+mtuSize-5 if offset+mtuSize-5 < len(data) else len(data)], offset, trace);
569        if not success:
570            break;
571        offset += len(reply['value']);
572        if offset >= len(data):
573            break;
574
575    if success:
576        success, reply = __writeExecute(transport, initiator, trace);
577
578    return success, reply;
579
580"""
581    Receive Notification...
582"""
583def notification(transport, initiator, trace):
584    attData = ATTData();
585    reply = { 'opcode': ATTOpcode.ATT_HANDLE_VALUE_NOTIFICATION, 'value': [] };
586
587    success, rxData = attResponse( transport, initiator, trace );
588    if success:
589        reply = attData.decode( rxData );
590        trace.trace(7, str(attData));
591        success = reply['opcode'] == ATTOpcode.ATT_HANDLE_VALUE_NOTIFICATION;
592
593    return success, reply;
594
595"""
596    Receive Indication and issue Indication Confirmation...
597"""
598def indication(transport, initiator, trace):
599    attData = ATTData();
600    reply = { 'opcode': ATTOpcode.ATT_HANDLE_VALUE_INDICATION, 'value': [] };
601
602    success, rxData = attResponse( transport, initiator, trace, 200 );
603    if success:
604        reply = attData.decode( rxData );
605        trace.trace(7, str(attData));
606        success = reply['opcode'] == ATTOpcode.ATT_HANDLE_VALUE_INDICATION;
607        if success:
608            txData = attData.encode( ATTOpcode.ATT_HANDLE_VALUE_CONFIRMATION );
609            trace.trace(7, str(attData));
610            success = attRequest( transport, initiator, txData, trace );
611
612    return success, reply;
613
614"""
615    Obtain the value handle for a Characteristic given its UUID
616"""
617def valueHandle(characteristics, uuid):
618    handle = -1;
619    for value_handle, char_uuid in zip(characteristics['value_handle'], characteristics['uuid']):
620        if char_uuid == uuid:
621            handle = value_handle;
622            break;
623    return handle;
624
625def filterCharacteristics(characteristics, uuid):
626    _characteristics = { 'uuid': [], 'handle': [] };
627    for _uuid, _handle in zip(characteristics['uuid'], characteristics['handle']):
628        if _uuid == uuid:
629            _characteristics['uuid'] += [ _uuid ];
630            _characteristics['handle'] += [ _handle ];
631    return _characteristics;
632
633"""
634    Obtain the peer Bluetooth address by starting a scanner...
635"""
636def peerAddress(transport, upperTester, trace):
637    success, address = False, Address( None, None );
638
639    try:
640        ownAddress = Address( ExtendedAddressType.PUBLIC );
641        scanner = Scanner(transport, upperTester, trace, ScanType.PASSIVE, AdvertisingReport.ADV_IND, ownAddress, ScanningFilterPolicy.FILTER_NONE, 1);
642        """
643            Start Scanner to obtain address of peer
644        """
645        success = scanner.enable();
646        scanner.monitor();
647        success = success and scanner.disable();
648        success = success and scanner.qualifyReports( 1 );
649        """
650            Obtain address of Advertiser
651        """
652        if success:
653            address = scanner.reportAddress;
654
655    except Exception as e:
656        trace.trace(3, "Failed to obtain peer Address: %s" % str(e));
657        success = False;
658
659    return success, address;
660
661"""
662    Obtain address of peer, connect to peer and exchange MTU sizes
663"""
664def preambleConnected(transport, idx, mtuSizeRequested, trace):
665    mtuSize = -1;
666    """
667        Obtain address of Advertiser
668    """
669    success, address = peerAddress(transport, idx, trace);
670    if not success:
671        raise UnboundLocalError('Failed to obtain peer Address');
672
673    trace.trace(6, "Advertiser address: %s" % str(address));
674    """
675        Initiate connection with Advertiser
676    """
677    initiator = Initiator(transport, idx, None, trace, Address( ExtendedAddressType.PUBLIC, 0x123456789ABC ), address );
678    connected = initiator.connect();
679    success = success and connected;
680    if connected:
681        """
682            Exchange MTU Size
683        """
684        success, mtuSize = exchangeMTU(transport, initiator, mtuSizeRequested, trace);
685        trace.trace(6,"MTU Size: %d" % mtuSize);
686
687    return success, mtuSize, initiator;
688
689"""
690    Trial Pairing and Pairing pause
691"""
692def pairing_bv_01_c(transport, upperTester, trace):
693    success, mtuSize, initiator = preambleConnected(transport, upperTester, 92, trace);
694    if success:
695        pairing = Pairing(transport, trace, initiator, toNumber(upperIRK));
696        paired = pairing.pair();
697        if paired:
698            trace.trace(6,"Link Encrypted!");
699            success = pairing.pause();
700            if success:
701                trace.trace(6, "Link re-encrypted!");
702            else:
703                trace.trace(6, "Failed to re-encrypt link!");
704
705        success = success and paired;
706
707        connected = not initiator.disconnect(0x13)
708        success = success and not connected;
709
710    return success;
711
712"""
713    GAP/GAT/BV-01-C [Mandatory Characteristics]
714"""
715def gap_gat_bv_01_c(transport, upperTester, trace):
716    success, mtuSize, initiator = preambleConnected(transport, upperTester, 92, trace);
717    if success:
718        """
719            Lookup the Generic Access Service (0x1800)
720        """
721        success, service = discoverPrimaryService(transport, initiator, 0x1800, trace);
722        if success:
723            """
724                Fetch the Characteristics
725            """
726            sset, attData, gattData = 1, ATTData(), GATTData.instance();
727            success, characteristics = characteristicsByType(transport, initiator, service["handles"][0], trace);
728            if success:
729                for c_uuid, c_handle, c_property, c_vhandle in zip(characteristics["uuid"], characteristics["handle"], \
730                                                                   characteristics["property"], characteristics["value_handle"]):
731                    trace.trace(6, "Characteristic %s handle %02X value-handle %02X properties %s" % \
732                                   (attData.uuid(c_uuid), c_handle, c_vhandle, attData.property(c_property)));
733
734                _characteristics = gattData.characteristics(sset, service["handles"][0][0]);
735                _characteristics.pop("permission");
736                """
737                    Verify Characteristics outline...
738                """
739                success = characteristics == _characteristics
740                trace.trace(6, "GAP Characteristics structure verified %s" % success);
741                if success:
742                    """
743                        Verify Characteristic values...
744                    """
745                    for c_uuid, c_handle, c_vhandle in zip(characteristics["uuid"], characteristics["handle"], characteristics["value_handle"]):
746                        if c_uuid == 0x2A00:
747                            _value = gattData.characteristicString(sset, c_handle);
748                            ok, reply = readStringCharacteristic(transport, initiator, c_vhandle, trace);
749                            trace.trace(6, "Read Characteristic with handle #%d - %s" % (c_vhandle, reply));
750                        else:
751                            _value = gattData.characteristicValue(sset, c_handle);
752                            ok, reply = readCharacteristic(transport, initiator, c_vhandle, trace);
753                            trace.trace(6, "Read Characteristic with handle #%d - %s" % (c_vhandle, formatArray(reply)));
754                        success = success and ok and reply == _value;
755                else:
756                    trace.trace(6, "Failed to verify GAP Characteristics structure!");
757            else:
758                trace.trace(6, "Failed to read GAP Service Characteristics!");
759        else:
760            trace.trace(6, "Failed to locate GAP Service!");
761
762        success = initiator.disconnect(0x13) and success;
763
764    return success;
765
766"""
767    GAP/GAT/BV-02-C [Peripheral Privacy Flag Characteristic]
768"""
769def gap_gat_bv_02_c(transport, upperTester, trace):
770    success, mtuSize, initiator = preambleConnected(transport, upperTester, 92, trace);
771    if success:
772        """
773            Lookup the Generic Access Service (0x1800)
774        """
775        success, service = discoverPrimaryService(transport, initiator, 0x1800, trace);
776        """
777            Fetch the Peripheral Privacy Flag Characteristic
778        """
779        success, characteristic = characteristicByType(transport, initiator, service["handles"][0], 0x2A02, False, trace);
780        if success:
781            flag = characteristic["value"][0]
782            trace.trace(6,"Peripheral Privacy Flag: %d" % flag);
783        else:
784            trace.trace(6,"Peripheral Privacy Flag: Not present!");
785
786        success = initiator.disconnect(0x13) and success;
787
788    return success;
789
790"""
791    GAP/GAT/BV-03-C [Reconnection Address Characteristic]
792"""
793def gap_gat_bv_03_c(transport, upperTester, trace):
794    success, mtuSize, initiator = preambleConnected(transport, upperTester, 92, trace);
795    if success:
796        """
797            Lookup the Generic Access Service (0x1800)
798        """
799        success, service = discoverPrimaryService(transport, initiator, 0x1800, trace);
800        """
801            Fetch the Reconnection Address Characteristic
802        """
803        success, characteristic = characteristicByType(transport, initiator, service["handles"][0], 0x2A03, False, trace);
804        if success:
805            data = characteristic["value"][0];
806            trace.trace(6,"Reconnection Address: %s" % formatAddress( data ));
807        else:
808            trace.trace(6,"Reconnection Address: Not present!");
809
810        success = initiator.disconnect(0x13) and success;
811
812    return success;
813
814"""
815    GAP/GAT/BV-04-C [Peripheral Preferred Connection Parameters Characteristic]
816"""
817def gap_gat_bv_04_c(transport, upperTester, trace):
818    success, mtuSize, initiator = preambleConnected(transport, upperTester, 512, trace);
819    if success:
820        """
821            Lookup the Generic Access Service (0x1800)
822        """
823        success, service = discoverPrimaryService(transport, initiator, 0x1800, trace);
824        """
825            Fetch the Peripheral Preferred Connection Parameters Characteristic
826        """
827        success, characteristic = characteristicByType(transport, initiator, service["handles"][0], 0x2A04, False, trace);
828        if success:
829            data = characteristic["value"][0];
830            trace.trace(6,"Peripheral Preferred Connection Parameters:");
831            trace.trace(6,"Minimum Connection Interval: %d" % toNumber( data[0:2] ));
832            trace.trace(6,"Maximum Connection Interval: %d" % toNumber( data[2:4] ));
833            trace.trace(6,"              Peripheral Latency: %d" % toNumber( data[4:6] ));
834            trace.trace(6,"Connection Supervision Timeout Multiplier: %d" % toNumber( data[6:8] ));
835        else:
836            trace.trace(6,"Peripheral Preferred Connection Parameters: Not present!");
837
838        connected = not initiator.disconnect(0x13)
839        success = success and not connected;
840        if not connected:
841            """
842                Attempt to reconnect with proposed connection parameters
843            """
844            initiator.intervalMin = toNumber( data[0:2] );
845            initiator.intervalMax = toNumber( data[2:4] );
846            initiator.latency     = toNumber( data[4:6] );
847            initiator.supervisionTimeout = toNumber( data[6:8] );
848
849            connected = initiator.connect();
850            success = success and connected;
851            if connected:
852                transport.wait(200);
853                success = initiator.disconnect(0x13) and success;
854
855    return success;
856
857"""
858    GAP/GAT/BV-05-C [Changing Device Name]
859"""
860def gap_gat_bv_05_c(transport, upperTester, trace):
861    success, mtuSize, initiator = preambleConnected(transport, upperTester, 512, trace);
862    if success:
863        """
864            Lookup the Generic Access Service (0x1800)
865        """
866        success, service = discoverPrimaryService(transport, initiator, 0x1800, trace);
867        """
868            Fetch the Device Name Characteristic
869        """
870        success, characteristic = characteristicByType(transport, initiator, service["handles"][0], 0x2A00, False, trace);
871        if success:
872            handle = characteristic["handle"][0];
873            data = characteristic["value"][0];
874            name = ''.join([chr(_) for _ in data]).decode('utf-8');
875            trace.trace(6,"Device Name: %s" % name);
876
877            setName = 'Rødgrød & Blåbær med fløde'.encode('UTF-8');
878            data = [ ord(_) for _ in setName ];
879            success, reply = writeCharacteristic(transport, initiator, handle, data, trace);
880
881            if success:
882                success, gotName = readStringCharacteristic(transport, initiator, handle, trace);
883                trace.trace(6,"Device Name: %s" % gotName);
884                success = success and (gotName == setName);
885            else:
886                if reply["opcode"] == ATTOpcode.ATT_ERROR_RESPONSE:
887                    trace.trace(6,"Failed to write Device Name - error code: %d - %s" % (reply["error"], ATTData().error(reply["error"])) );
888                else:
889                    trace.trace(6,"Failed to write Device Name - unknown reply: %d" % reply["opcode"]);
890        else:
891            trace.trace(6,"Device Name: Not present!");
892
893        success = initiator.disconnect(0x13) and success;
894
895    return success;
896
897"""
898    GAP/GAT/BX-01-C [Discover All Services]
899"""
900def gap_gat_bx_01_c(transport, upperTester, trace):
901    try:
902        success, mtuSize, initiator = preambleConnected(transport, upperTester, 512, trace);
903        if success:
904            """
905                Discover all Services
906            """
907            attData = ATTData();
908            success, services = discoverPrimaryServices(transport, initiator, trace);
909            for uuid, handles in zip(services["uuids"], services["handles"]):
910                trace.trace(6, "Service %s covers [%02X, %02X]" % (attData.uuid(uuid), handles[0], handles[1]));
911
912                success, characteristics = characteristicsByType(transport, initiator, handles, trace);
913                for c_uuid, c_handle, c_property, c_vhandle in zip(characteristics["uuid"], characteristics["handle"], \
914                                                                   characteristics["property"], characteristics["value_handle"]):
915                    trace.trace(6, "    Characteristic %s handle %02X value-handle %02X properties %s" % \
916                                   (attData.uuid(c_uuid), c_handle, c_vhandle, attData.property(c_property)));
917
918            success = initiator.disconnect(0x13) and success;
919
920    except Exception as e:
921        trace.trace(3, "Discover All Services test failed: %s" % str(e));
922        success = False;
923
924    return success;
925
926"""
927    GAP/IDLE/NAMP/BV-01-C [Name Discovery Procedure GATT Client]
928"""
929def gap_idle_namp_bv_01_c(transport, upperTester, trace):
930    success, mtuSize, initiator = preambleConnected(transport, upperTester, 512, trace);
931    if success:
932        """
933            Lookup the Generic Access Service (0x1800)
934        """
935        success, service = discoverPrimaryService(transport, initiator, 0x1800, trace);
936        """
937            Fetch the Device Name Characteristic
938        """
939        success, characteristic = characteristicByType(transport, initiator, service["handles"][0], 0x2A00, False, trace);
940        if success:
941            data = characteristic["value"][0];
942            name = bytes(data).decode('utf-8');
943            trace.trace(6,"Device Name: %s" % name);
944        else:
945            trace.trace(6,"Device Name: Not present!");
946
947        success = initiator.disconnect(0x13) and success;
948
949    return success;
950
951"""
952    GATT/SR/GAC/BV-01-C [Server accepts Server Configuration]
953"""
954def gatt_sr_gac_bv_01_c(transport, upperTester, lowerTester, trace):
955    for mtuSize in [ 23, 512 ]:
956        success, mtuSize, initiator = preambleConnected(transport, upperTester, mtuSize, trace);
957        if success:
958            """
959                Switch to Service Set #1
960            """
961            sset, attData, gattData = 1, ATTData(), GATTData.instance();
962            switch_gatt_service_set(transport, lowerTester, sset, 200);
963            """
964                Collect all Characteristics that have READ permission
965            """
966            characteristics = gattData.characteristics(sset, None, ATTPermission.ATT_PERM_READ);
967            """
968                Find the ones that is longer than (MTU-1) if MTU < 512 else the ones that is 512 if MTU = 512
969            """
970            for _uuid, _handle, _value_handle in zip(characteristics['uuid'], characteristics['handle'], characteristics['value_handle']):
971                _value = gattData.characteristicValue(sset, _handle);
972                if len(_value) > mtuSize-1:
973                    trace.trace(6, "Read Characteristic %s handle #%d length %d" % (attData.uuid(_uuid), _value_handle, len(_value)));
974                    ok, reply = readCharacteristic(transport, initiator, _value_handle, trace);
975                    success = success and ok and reply == _value[:mtuSize-1];
976
977            success = initiator.disconnect(0x13) and success;
978
979    return success;
980
981"""
982    GATT/SR/GAD/BV-01-C [Server Discovers All Primary Services]
983"""
984def gatt_sr_gad_bv_01_c(transport, upperTester, lowerTester, trace):
985    success, mtuSize, initiator = preambleConnected(transport, upperTester, 92, trace);
986    if success:
987        attData, gattData = ATTData(), GATTData.instance();
988
989        for sset in range(4):
990            """
991                Switching Service Set
992            """
993            trace.trace(6, "Switching to Service Set #%d" % sset);
994            switch_gatt_service_set(transport, lowerTester, sset, 200);
995            """
996                Discover all Primary Services
997            """
998            success, services = discoverPrimaryServices(transport, initiator, trace);
999            if success:
1000                for _uuid, _handles in zip(services["uuids"], services["handles"]):
1001                    trace.trace(6, "Service %s covers handles [0x%02X, 0x%02X]" % (attData.uuid(_uuid), _handles[0], _handles[1]));
1002                success = services == gattData.primaryServices(sset)
1003                trace.trace(6, "Verified Service Set: %s" % success);
1004            else:
1005                trace.trace(6, "Unable to discover Primary Services!");
1006
1007        success = initiator.disconnect(0x13) and success;
1008
1009    return success;
1010
1011"""
1012    GATT/SR/GAD/BV-02-C [Server Discovers Primary Services by Service UUID]
1013"""
1014def gatt_sr_gad_bv_02_c(transport, upperTester, lowerTester, trace):
1015    success, mtuSize, initiator = preambleConnected(transport, upperTester, 92, trace);
1016    if success:
1017        attData, gattData = ATTData(), GATTData.instance();
1018
1019        for sset in range(4):
1020            """
1021                Switching Service Set
1022            """
1023            trace.trace(6, "Switching to Service Set #%d" % sset);
1024            switch_gatt_service_set(transport, lowerTester, sset, 200);
1025            """
1026                Iterate over the unique Service UUIDs in the Service Set...
1027            """
1028            trace.trace(6, "Service Set #%d:" % sset);
1029            for uuid in sorted(list(set(gattData.primaryServices(sset)['uuids']))):
1030                found, services = discoverPrimaryService(transport, initiator, uuid, trace);
1031                if found:
1032                    for _uuid, _handles in zip(services["uuids"], services["handles"]):
1033                        trace.trace(6, "Service %s covers handles [0x%02X, 0x%02X]" % (attData.uuid(_uuid), _handles[0], _handles[1]));
1034                else:
1035                    trace.trace(6, "Couldn't find Service %s" % attData.uuid(uuid));
1036
1037                success = success and found;
1038                success = success and (services == gattData.primaryServices(sset, uuid));
1039                trace.trace(6, "Verified Services: %s" % success);
1040
1041        success = initiator.disconnect(0x13) and success;
1042
1043    return success;
1044
1045"""
1046    GATT/SR/GAD/BV-03-C [Server Finds Included Services]
1047"""
1048def gatt_sr_gad_bv_03_c(transport, upperTester, lowerTester, trace):
1049    success, mtuSize, initiator = preambleConnected(transport, upperTester, 92, trace);
1050    if success:
1051        attData, gattData = ATTData(), GATTData.instance();
1052
1053        for sset in range(4):
1054            """
1055                Switching Service Set
1056            """
1057            trace.trace(6, "Switching to Service Set #%d" % sset);
1058            switch_gatt_service_set(transport, lowerTester, sset, 200);
1059            """
1060                Discover Included Services in the selected Service Set...
1061            """
1062            found, services = includedServicesByType(transport, initiator, trace);
1063            if found:
1064                for uuid, handles in zip(services["uuids"], services["handles"]):
1065                    trace.trace(6, "Service %s covers handles [0x%02X, 0x%02X]" % (attData.uuid(uuid), handles[0], handles[1]));
1066
1067            if sset == 0:
1068                success = success and not found;
1069            else:
1070                success = success and found;
1071                success = success and (services == gattData.includedServices(sset))
1072            trace.trace(6, "Verified Included Services: %s" % success);
1073
1074        success = initiator.disconnect(0x13) and success;
1075
1076    return success;
1077
1078"""
1079    GATT/SR/GAD/BV-04-C [Server Discovers All Characteristics of a Service]
1080"""
1081def gatt_sr_gad_bv_04_c(transport, upperTester, lowerTester, trace):
1082    success, mtuSize, initiator = preambleConnected(transport, upperTester, 92, trace);
1083    if success:
1084        attData, gattData = ATTData(), GATTData.instance();
1085
1086        for sset in range(4):
1087            """
1088                Switching Service Set
1089            """
1090            trace.trace(6, "Switching to Service Set #%d" % sset);
1091            switch_gatt_service_set(transport, lowerTester, sset, 200);
1092            """
1093                Discover all Primary Services...
1094            """
1095            found, services = discoverPrimaryServices(transport, initiator, trace);
1096            success = success and found;
1097            for uuid, handles in zip(services["uuids"], services["handles"]):
1098                trace.trace(6, "Service %s covers handles [0x%02X, 0x%02X]" % (attData.uuid(uuid), handles[0], handles[1]));
1099
1100                _characteristics = gattData.characteristics(sset, handles[0]);
1101                _characteristics.pop("permission");
1102
1103                found, characteristics = characteristicsByType(transport, initiator, handles, trace);
1104                if found:
1105                    for c_uuid, c_handle, c_property, c_vhandle in zip(characteristics["uuid"], characteristics["handle"], \
1106                                                                       characteristics["property"], characteristics["value_handle"]):
1107                        trace.trace(6, "    Characteristic %s handle 0x%02X value-handle 0x%02X properties %s" % \
1108                                       (attData.uuid(c_uuid), c_handle, c_vhandle, attData.property(c_property)));
1109                    success = success and (characteristics == _characteristics)
1110                else:
1111                    success = success and len(_characteristics["uuid"]) == 0;
1112                trace.trace(6, "Characteristics for Service %s Verified: %s" % (attData.uuid(uuid), success));
1113
1114        success = initiator.disconnect(0x13) and success;
1115
1116    return success;
1117
1118"""
1119    GATT/SR/GAD/BV-05-C [Server Discovers Characteristics by UUID]
1120"""
1121def gatt_sr_gad_bv_05_c(transport, upperTester, lowerTester, trace):
1122    success, mtuSize, initiator = preambleConnected(transport, upperTester, 92, trace);
1123    if success:
1124        attData, gattData = ATTData(), GATTData.instance();
1125
1126        for sset in range(4):
1127            """
1128                Switching Service Set
1129            """
1130            trace.trace(6, "Switching to Service Set #%d" % sset);
1131            switch_gatt_service_set(transport, lowerTester, sset, 200);
1132            """
1133                Discover all Primary Services
1134            """
1135            found, services = discoverPrimaryServices(transport, initiator, trace);
1136            success = success and found;
1137            for uuid, handles in zip(services["uuids"], services["handles"]):
1138                trace.trace(6, "Service %s covers handles [0x%02X, 0x%02X]" % (attData.uuid(uuid), handles[0], handles[1]));
1139
1140                _characteristics = gattData.characteristics(sset, handles[0]);
1141                _characteristics.pop("permission");
1142
1143                found, characteristics = characteristicsByType(transport, initiator, handles, trace);
1144                if found:
1145                    for c_uuid, c_handle, c_property, c_vhandle in zip(characteristics["uuid"], characteristics["handle"], \
1146                                                                       characteristics["property"], characteristics["value_handle"]):
1147                        trace.trace(6, "    Characteristic %s handle 0x%02X value-handle 0x%02X properties %s" % \
1148                                       (attData.uuid(c_uuid), c_handle, c_vhandle, attData.property(c_property)));
1149                    success = success and (characteristics == _characteristics)
1150                else:
1151                    success = success and len(_characteristics["uuid"]) == 0;
1152                trace.trace(6, "Characteristics for Service %s Verified: %s" % (attData.uuid(uuid), success));
1153
1154        success = initiator.disconnect(0x13) and success;
1155
1156    return success;
1157
1158"""
1159    GATT/SR/GAD/BV-06-C [Server Discovers All Characteristic Descriptors]
1160"""
1161def gatt_sr_gad_bv_06_c(transport, upperTester, lowerTester, trace):
1162    success, mtuSize, initiator = preambleConnected(transport, upperTester, 92, trace);
1163    if success:
1164        attData, gattData = ATTData(), GATTData.instance();
1165
1166        for sset in range(4):
1167            """
1168                Switching Service Set
1169            """
1170            trace.trace(6, "Switching to Service Set #%d" % sset);
1171            switch_gatt_service_set(transport, lowerTester, sset, 200);
1172            """
1173                Discover all Primary Services
1174            """
1175            found, services = discoverPrimaryServices(transport, initiator, trace);
1176            success = success and found;
1177            for uuid, handles in zip(services["uuids"], services["handles"]):
1178                trace.trace(6, "Service %s covers handles [0x%02X, 0x%02X]" % (attData.uuid(uuid), handles[0], handles[1]));
1179
1180                _descriptors = gattData.descriptors(sset, handles[0]);
1181
1182                found, descriptors = discoverDescriptors(transport, initiator, handles, trace);
1183                if found:
1184                    for c_uuid, c_handle in zip(descriptors["uuid"], descriptors["handle"]):
1185                        trace.trace(6, "    Descriptor %s handle 0x%02X" % (attData.uuid(c_uuid), c_handle));
1186                    success = success and (descriptors == _descriptors)
1187                else:
1188                    success = success and len(_descriptors["uuid"]) == 0;
1189                trace.trace(6, "Descriptors for Service %s Verified: %s" % (attData.uuid(uuid), success));
1190
1191        success = initiator.disconnect(0x13) and success;
1192
1193    return success;
1194
1195"""
1196    GATT/SR/GAR/BV-01-C [Server Reads Characteristic Value]
1197"""
1198def gatt_sr_gar_bv_01_c(transport, upperTester, lowerTester, trace):
1199    success, mtuSize, initiator = preambleConnected(transport, upperTester, 92, trace);
1200    if success:
1201        sset, attData, gattData = 2, ATTData(), GATTData.instance();
1202        """
1203            Switch to Service Set #2
1204        """
1205        trace.trace(6, "Switching to Service Set #%d" % sset);
1206        switch_gatt_service_set(transport, lowerTester, sset, 200);
1207        """
1208            Get all Characteristics that have READ permission
1209        """
1210        characteristics = gattData.characteristics(sset, None, ATTPermission.ATT_PERM_READ);
1211        for c_uuid, c_handle, c_property, c_vhandle in zip(characteristics["uuid"], characteristics["handle"], \
1212                                                           characteristics["property"], characteristics["value_handle"]):
1213            trace.trace(6, "Characteristic %s handle 0x%02X value-handle 0x%02X properties %s" % \
1214                           (attData.uuid(c_uuid), c_handle, c_vhandle, attData.property(c_property)));
1215            success, data = readCharacteristic(transport, initiator, c_vhandle, trace);
1216            trace.trace(6, "   Characteristic Value: %s" % formatArray(data));
1217            match = data == gattData.characteristicValue(sset, c_handle);
1218            success = success and match;
1219            trace.trace(6, "   Characteristic Value Verified: %s" % success);
1220
1221        success = initiator.disconnect(0x13) and success;
1222
1223    return success;
1224
1225"""
1226    GATT/SR/GAR/BI-01-C [Read Not Permitted error - Reading Characteristic Value]
1227"""
1228def gatt_sr_gar_bi_01_c(transport, upperTester, lowerTester, trace):
1229    success, mtuSize, initiator = preambleConnected(transport, upperTester, 92, trace);
1230    if success:
1231        sset, prevLast, attData, gattData = 2, 0, ATTData(), GATTData.instance();
1232        """
1233            Switch to Service Set #2
1234        """
1235        trace.trace(6, "Switching to Service Set #%d" % sset);
1236        switch_gatt_service_set(transport, lowerTester, sset, 200);
1237        """
1238            Collect all Services
1239        """
1240        services = gattData.allServices(sset);
1241        for uuid, handles in zip(services["uuids"], services["handles"]):
1242            trace.trace(6, "Service %s covers handles [%02d, %02d]" % (attData.uuid(uuid), handles[0], handles[1]));
1243
1244            if handles[0] > (prevLast+1):
1245                ok, data = readCharacteristic(transport, initiator, (handles[0] + prevLast)//2, trace);
1246                success = success and not ok and data == ATTError.ATT_ERROR_INVALID_HANDLE;
1247                trace.trace(6, "Attempted to read Characteristic @ handle %02d - %s" % ((handles[0] + prevLast)//2, attData.error(data)));
1248            prevLast = handles[1];
1249
1250        success = initiator.disconnect(0x13) and success;
1251
1252    return success;
1253
1254"""
1255    GATT/SR/GAR/BI-02-C [Invalid Handle error - Reading Characteristic Value]
1256"""
1257def gatt_sr_gar_bi_02_c(transport, upperTester, lowerTester, trace):
1258    success, mtuSize, initiator = preambleConnected(transport, upperTester, 92, trace);
1259    if success:
1260        sset, attData, gattData = 2, ATTData(), GATTData.instance();
1261        """
1262            Switch to Service Set #2
1263        """
1264        trace.trace(6, "Switching to Service Set #%d" % sset);
1265        switch_gatt_service_set(transport, lowerTester, sset, 200);
1266        """
1267            Get all Characteristics that doesn't have READ permission
1268        """
1269        characteristics = gattData.characteristics(sset, None, ATTPermission.ATT_PERM_ANY_READ, True);
1270        for c_uuid, c_handle, c_property, c_vhandle in zip(characteristics["uuid"], characteristics["handle"], \
1271                                                           characteristics["property"], characteristics["value_handle"]):
1272            trace.trace(6, "Characteristic %s handle 0x%02X value-handle 0x%02X properties %s" % \
1273                           (attData.uuid(c_uuid), c_handle, c_vhandle, attData.property(c_property)));
1274            ok, data = readCharacteristic(transport, initiator, c_vhandle, trace);
1275            success = success and not ok and data == ATTError.ATT_ERROR_READ_NOT_PERMITTED;
1276            trace.trace(6, "Attempted to read Characteristic @ handle %02d - %s" % (c_vhandle, attData.error(data)));
1277
1278        success = initiator.disconnect(0x13) and success;
1279
1280    return success;
1281
1282"""
1283    GATT/SR/GAR/BI-03-C [Insufficient Authorization error - Reading Characteristic Value]
1284"""
1285def gatt_sr_gar_bi_03_c(transport, upperTester, lowerTester, trace):
1286    success, mtuSize, initiator = preambleConnected(transport, upperTester, 92, trace);
1287    if success:
1288        sset, attData, gattData = 1, ATTData(), GATTData.instance();
1289        """
1290            Switch to Service Set #1
1291        """
1292        trace.trace(6, "Switching to Service Set #%d" % sset);
1293        switch_gatt_service_set(transport, lowerTester, sset, 200);
1294        """
1295            Collect all Characteristics that have Authorized READ permission
1296        """
1297        characteristics = gattData.characteristics(sset, None, ATTPermission.ATT_PERM_READ_AUTHOR);
1298        for c_uuid, c_handle, c_property, c_permission, c_vhandle in zip(characteristics["uuid"], characteristics["handle"], \
1299                                                                         characteristics["property"], characteristics["permission"], \
1300                                                                         characteristics["value_handle"]):
1301            trace.trace(6, "Characteristic %s handle 0x%02X value-handle 0x%02X properties %s permissions %s" % \
1302                           (attData.uuid(c_uuid), c_handle, c_vhandle, attData.property(c_property), attData.permission(c_permission)));
1303            ok, data = readCharacteristic(transport, initiator, c_vhandle, trace);
1304            success = success and not ok and data == ATTError.ATT_ERROR_INSUFFICIENT_AUTHORIZATION;
1305            trace.trace(6, "Attempted to read Characteristic @ handle 0x%02X - %s" % (c_vhandle, attData.error(data)));
1306
1307        success = initiator.disconnect(0x13) and success;
1308
1309    return success;
1310
1311"""
1312    GATT/SR/GAR/BI-04-C [Insufficient Authentication error - Reading Characteristic Value]
1313"""
1314def gatt_sr_gar_bi_04_c(transport, upperTester, lowerTester, trace):
1315    success, mtuSize, initiator = preambleConnected(transport, upperTester, 512, trace);
1316    if success:
1317        sset, found, attData, gattData = 1, False, ATTData(), GATTData.instance();
1318        """
1319            Switch to Service Set #1
1320        """
1321        trace.trace(6, "Switching to Service Set #%d" % sset);
1322        switch_gatt_service_set(transport, lowerTester, sset, 200);
1323        """
1324            Collect all Characteristics that have Authenticated READ permission
1325        """
1326        characteristics = gattData.characteristics(sset, None, ATTPermission.ATT_PERM_READ_AUTHEN);
1327        for c_uuid, c_handle, c_property, c_permission, c_vhandle in zip(characteristics["uuid"], characteristics["handle"], \
1328                                                                         characteristics["property"], characteristics["permission"], \
1329                                                                         characteristics["value_handle"]):
1330            trace.trace(6, "Characteristic %s handle 0x%02X value-handle 0x%02X properties %s permissions %s" % \
1331                           (attData.uuid(c_uuid), c_handle, c_vhandle, attData.property(c_property), attData.permission(c_permission)));
1332            ok, data = readCharacteristic(transport, initiator, c_vhandle, trace);
1333            success = success and not ok and data == ATTError.ATT_ERROR_INSUFFICIENT_AUTHENTICATION;
1334            trace.trace(6, "Attempted to read Characteristic @ handle 0x%02X - %s" % (c_vhandle, attData.error(data)));
1335            found = True;
1336
1337        if not found:
1338            trace.trace(6, "Didn't find any characteristics that require Authentication for reading...");
1339        success = success and found;
1340
1341        success = initiator.disconnect(0x13) and success;
1342
1343    return success;
1344
1345"""
1346    GATT/SR/GAR/BV-03-C [Server Reads using Characteristic UUID]
1347"""
1348def gatt_sr_gar_bv_03_c(transport, upperTester, lowerTester, trace):
1349    success, mtuSize, initiator = preambleConnected(transport, upperTester, 92, trace);
1350    if success:
1351        sset, attData, gattData = 1, ATTData(), GATTData.instance();
1352        """
1353            Switch to Service Set #1
1354        """
1355        trace.trace(6, "Switching to Service Set #%d" % sset);
1356        switch_gatt_service_set(transport, lowerTester, sset, 200);
1357        """
1358            Collect a set of unique Characteristics UUIDs
1359        """
1360        uuids = set(gattData.characteristics(sset)['uuid']);
1361        for uuid in list(uuids):
1362            s_uuid = attData.uuid(uuid);
1363            """
1364                Select one 16-bit UUID and one 128-bit UUID
1365            """
1366            if s_uuid == '0000B006-0000-1000-8000-00805F9B34FB' or s_uuid == '0000B009-0000-0000-0123-456789ABCDEF':
1367                trace.trace(6, "Read Characteristics matching %s" % attData.uuid(uuid));
1368                found, characteristics = characteristicByType(transport, initiator, [ 0x0001, 0xFFFF ], uuid, True, trace);
1369                success = success and found;
1370                for c_handle, c_value in zip(characteristics["handle"], characteristics["value"]):
1371                    trace.trace(6, "    Characteristic %s handle 0x%02X value %s" % (attData.uuid(uuid), c_handle, formatArray(c_value)));
1372                    e_value = gattData.characteristicValue(sset, c_handle-1);
1373                    match = (c_value == e_value) if len(e_value) < mtuSize-3 else (c_value == e_value[:mtuSize-4]);
1374                    success = success and match;
1375                    trace.trace(6, "    Characteristic Value Verified: %s" % success);
1376
1377        success = initiator.disconnect(0x13) and success;
1378
1379    return success;
1380
1381"""
1382    GATT/SR/GAR/BI-06-C [Read Not Permitted error - Reading Characteristic by UUID]
1383"""
1384def gatt_sr_gar_bi_06_c(transport, upperTester, lowerTester, trace):
1385    success, mtuSize, initiator = preambleConnected(transport, upperTester, 92, trace);
1386    if success:
1387        sset, attData, gattData = 1, ATTData(), GATTData.instance();
1388        """
1389            Switch to Service Set #1
1390        """
1391        trace.trace(6, "Switching to Service Set #%d" % sset);
1392        switch_gatt_service_set(transport, lowerTester, sset, 200);
1393        """
1394            Filter out all Characteristics which doesn't have READ permission
1395        """
1396        characteristics = gattData.characteristics(sset, None, ATTPermission.ATT_PERM_ANY_READ, True);
1397        for _uuid, _handle, in zip(characteristics['uuid'], characteristics['handle']):
1398            _service = gattData.serviceCovering(sset, _handle);
1399            trace.trace(6, "Read Characteristics matching %s [%d, %d]" % (attData.uuid(_uuid), _service['handles'][0], _service['handles'][1]));
1400            found, reply = characteristicByType(transport, initiator, _service['handles'], _uuid, False, trace);
1401            if found and reply['handle'] != _handle+1:
1402                continue;
1403            success = success and not found and reply['error'] == ATTError.ATT_ERROR_READ_NOT_PERMITTED;
1404            trace.trace(6, "Reply: %s" % attData.error(reply['error']));
1405
1406        success = initiator.disconnect(0x13) and success;
1407
1408    return success;
1409
1410"""
1411    GATT/SR/GAR/BI-07-C [Attribute Not Found error - Reading Characteristic by UUID]
1412"""
1413def gatt_sr_gar_bi_07_c(transport, upperTester, lowerTester, trace):
1414    success, mtuSize, initiator = preambleConnected(transport, upperTester, 512, trace);
1415    if success:
1416        sset, attData, gattData = 1, ATTData(), GATTData.instance();
1417        """
1418            Switch to Service Set #1
1419        """
1420        trace.trace(6, "Switching to Service Set #%d" % sset);
1421        switch_gatt_service_set(transport, lowerTester, sset, 200);
1422
1423        for _uuid in [ 0xB018, 0xB019 ]:
1424            trace.trace(6, "Read Characteristics matching %s [%d, %d]" % (attData.uuid(_uuid), 1, 0xFFFF));
1425            found, reply = characteristicByType(transport, initiator, [ 0x0001, 0xFFFF ], _uuid, False, trace);
1426            success = success and not found and reply['error'] == ATTError.ATT_ERROR_ATTRIBUTE_NOT_FOUND;
1427            trace.trace(6, "Reply: %s" % attData.error(reply['error']));
1428
1429        success = initiator.disconnect(0x13) and success;
1430
1431    return success;
1432
1433"""
1434    GATT/SR/GAR/BI-09-C [Insufficient Authorization error - Reading Using Characteristic UUID]
1435"""
1436def gatt_sr_gar_bi_09_c(transport, upperTester, lowerTester, trace):
1437    success, mtuSize, initiator = preambleConnected(transport, upperTester, 512, trace);
1438    if success:
1439        sset, attData, gattData = 1, ATTData(), GATTData.instance();
1440        """
1441            Switch to Service Set #1
1442        """
1443        trace.trace(6, "Switching to Service Set #%d" % sset);
1444        switch_gatt_service_set(transport, lowerTester, sset, 200);
1445        """
1446            Filter out all Characteristics which have READ AUTHORIZED permission
1447        """
1448        characteristics = gattData.characteristics(sset, None, ATTPermission.ATT_PERM_READ_AUTHOR);
1449        for _uuid, _handle, in zip(characteristics['uuid'], characteristics['handle']):
1450            trace.trace(6, "Read Characteristics matching %s [%d, %d]" % (attData.uuid(_uuid), _handle, 0xFFFF));
1451            found, reply = characteristicByType(transport, initiator, [_handle, 0xFFFF], _uuid, False, trace);
1452            success = success and not found and reply['error'] == ATTError.ATT_ERROR_INSUFFICIENT_AUTHORIZATION;
1453            trace.trace(6, "Reply: %s" % attData.error(reply['error']));
1454
1455        success = initiator.disconnect(0x13) and success;
1456
1457    return success;
1458
1459"""
1460    GATT/SR/GAR/BI-10-C [Insufficient Authentication error - Reading Using Characteristic UUID]
1461"""
1462def gatt_sr_gar_bi_10_c(transport, upperTester, lowerTester, trace):
1463    success, mtuSize, initiator = preambleConnected(transport, upperTester, 512, trace);
1464    if success:
1465        sset, attData, gattData = 1, ATTData(), GATTData.instance();
1466        """
1467            Switch to Service Set #1
1468        """
1469        trace.trace(6, "Switching to Service Set #%d" % sset);
1470        switch_gatt_service_set(transport, lowerTester, sset, 200);
1471        """
1472            Filter out all Characteristics which have READ AUTHENTICATION permission
1473        """
1474        characteristics = gattData.characteristics(sset, None, ATTPermission.ATT_PERM_READ_AUTHEN);
1475        for _uuid, _handle, in zip(characteristics['uuid'], characteristics['handle']):
1476            trace.trace(6, "Read Characteristics matching %s [%d, %d]" % (attData.uuid(_uuid), _handle, 0xFFFF));
1477            found, reply = characteristicByType(transport, initiator, [_handle, 0xFFFF], _uuid, False, trace);
1478            success = success and not found and reply['error'] == ATTError.ATT_ERROR_INSUFFICIENT_AUTHENTICATION;
1479            trace.trace(6, "Reply: %s" % attData.error(reply['error']));
1480
1481        success = initiator.disconnect(0x13) and success;
1482
1483    return success;
1484
1485"""
1486    GATT/SR/GAR/BI-11-C [Insufficient Encryption Key Size error - Reading Using Characteristic UUID]
1487"""
1488def gatt_sr_gar_bi_11_c(transport, upperTester, lowerTester, trace):
1489    success, mtuSize, initiator = preambleConnected(transport, upperTester, 512, trace);
1490    if success:
1491        sset, attData, gattData = 1, ATTData(), GATTData.instance();
1492        """
1493            Switch to Service Set #1
1494        """
1495        trace.trace(6, "Switching to Service Set #%d" % sset);
1496        switch_gatt_service_set(transport, lowerTester, sset, 200);
1497        """
1498            Filter out all Characteristics which have READ ENCRYPTED permission
1499        """
1500        characteristics = gattData.characteristics(sset, None, ATTPermission.ATT_PERM_READ_ENCRYPT);
1501        for _uuid, _handle, in zip(characteristics['uuid'], characteristics['handle']):
1502            trace.trace(6, "Read Characteristics matching %s [%d, %d]" % (attData.uuid(_uuid), _handle, 0xFFFF));
1503            found, reply = characteristicByType(transport, initiator, [_handle, 0xFFFF], _uuid, False, trace);
1504            success = success and not found and reply['error'] == ATTError.ATT_ERROR_INSUFFICIENT_ENCRYPTION;
1505            trace.trace(6, "Reply: %s" % attData.error(reply['error']));
1506
1507        success = initiator.disconnect(0x13) and success;
1508
1509    return success;
1510
1511"""
1512    GATT/SR/GAR/BV-04-C [Server Reads Long Characteristic Value]
1513"""
1514def gatt_sr_gar_bv_04_c(transport, upperTester, lowerTester, trace):
1515    success, mtuSize, initiator = preambleConnected(transport, upperTester, 23, trace);
1516    if success:
1517        sset, attData, gattData = 1, ATTData(), GATTData.instance();
1518        """
1519            Switch to Service Set #1
1520        """
1521        trace.trace(6, "Switching to Service Set #%d" % sset);
1522        switch_gatt_service_set(transport, lowerTester, sset, 200);
1523        """
1524            Filter out all Characteristics which have READ permission
1525        """
1526        characteristics = gattData.characteristics(sset, None, ATTPermission.ATT_PERM_READ);
1527
1528        prevSize = 513;
1529        for m,n in zip([2,2,1,0], [mtuSize//2,0,0,mtuSize//2]):
1530            _characteristics = { 'uuid': [], 'handle': [], 'value_handle': [] };
1531            for _uuid, _handle, _value_handle in zip(characteristics['uuid'], characteristics['handle'], characteristics['value_handle']):
1532                _size = len(gattData.characteristicValue(sset, _handle));
1533                if m*mtuSize-1+n <= _size and _size < prevSize:
1534                    _characteristics['uuid']         += [ _uuid ];
1535                    _characteristics['handle']       += [ _handle ];
1536                    _characteristics['value_handle'] += [ _value_handle ];
1537                    prevSize = _size;
1538
1539            for _uuid, _handle, _value_handle in zip(_characteristics['uuid'], _characteristics['handle'], _characteristics['value_handle']):
1540                trace.trace(6, "Read Characteristic %s [#%d]" % (attData.uuid(_uuid), _handle));
1541                found, reply = readCharacteristic(transport, initiator, _value_handle, trace);
1542                success = success and found and reply == gattData.characteristicValue(sset, _handle)[:mtuSize-1];
1543                if found:
1544                    trace.trace(6, "Data: %s" % formatArray(reply));
1545                found, reply = readBlob(transport, initiator, _value_handle, mtuSize, trace);
1546                success = success and found and reply == gattData.characteristicValue(sset, _handle);
1547                if found:
1548                    trace.trace(6, "Data: %s" % formatArray(reply));
1549
1550        success = initiator.disconnect(0x13) and success;
1551
1552    return success;
1553
1554"""
1555    GATT/SR/GAR/BI-12-C [Read Not Permitted error - Reading Long Characteristic Value]
1556"""
1557def gatt_sr_gar_bi_12_c(transport, upperTester, lowerTester, trace):
1558    success, mtuSize, initiator = preambleConnected(transport, upperTester, 92, trace);
1559    if success:
1560        sset, attData, gattData = 1, ATTData(), GATTData.instance();
1561        """
1562            Switch to Service Set #1
1563        """
1564        trace.trace(6, "Switching to Service Set #%d" % sset);
1565        switch_gatt_service_set(transport, lowerTester, sset, 200);
1566        """
1567            Filter out all Characteristics which doesn't have READ permission
1568        """
1569        characteristics = gattData.characteristics(sset, None, ATTPermission.ATT_PERM_ANY_READ, True);
1570        for _uuid, _handle, _value_handle in zip(characteristics['uuid'], characteristics['handle'], characteristics['value_handle']):
1571            trace.trace(6, "Read Characteristic %s [#%d]" % (attData.uuid(_uuid), _handle));
1572            found, reply = readBlob(transport, initiator, _value_handle, mtuSize, trace);
1573            success = success and not found and reply == ATTError.ATT_ERROR_READ_NOT_PERMITTED;
1574            if not found:
1575                trace.trace(6, "Reply: %s" % attData.error(reply));
1576
1577        success = initiator.disconnect(0x13) and success;
1578
1579    return success;
1580
1581"""
1582    GATT/SR/GAR/BI-13-C [Invalid Offset error - Reading Long Characteristic Value]
1583"""
1584def gatt_sr_gar_bi_13_c(transport, upperTester, lowerTester, trace):
1585    success, mtuSize, initiator = preambleConnected(transport, upperTester, 92, trace);
1586    if success:
1587        sset, attData, gattData = 1, ATTData(), GATTData.instance();
1588        """
1589            Switch to Service Set #1
1590        """
1591        trace.trace(6, "Switching to Service Set #%d" % sset);
1592        switch_gatt_service_set(transport, lowerTester, sset, 200);
1593        """
1594            Filter out all Characteristics which have READ permission
1595        """
1596        characteristics = gattData.characteristics(sset, None, ATTPermission.ATT_PERM_READ);
1597        for _uuid, _handle, _value_handle in zip(characteristics['uuid'], characteristics['handle'], characteristics['value_handle']):
1598            trace.trace(6, "Read Characteristic %s [#%d]" % (attData.uuid(_uuid), _handle));
1599            found, reply = __readBlob(transport, initiator, _value_handle, len(gattData.characteristicValue(sset, _handle))+1, trace);
1600            success = success and not found and reply['error'] == ATTError.ATT_ERROR_INVALID_OFFSET;
1601            if not found:
1602                trace.trace(6, "Reply: %s" % attData.error(reply['error']));
1603
1604        success = initiator.disconnect(0x13) and success;
1605
1606    return success;
1607
1608"""
1609    GATT/SR/GAR/BI-14-C [Invalid Handle error - Reading Long Characteristic Value]
1610"""
1611def gatt_sr_gar_bi_14_c(transport, upperTester, lowerTester, trace):
1612    success, mtuSize, initiator = preambleConnected(transport, upperTester, 92, trace);
1613    if success:
1614        sset, prevLast, attData, gattData = 1, 0, ATTData(), GATTData.instance();
1615        """
1616            Switch to Service Set #1
1617        """
1618        trace.trace(6, "Switching to Service Set #%d" % sset);
1619        switch_gatt_service_set(transport, lowerTester, sset, 200);
1620        """
1621            Collect all Services
1622        """
1623        services = gattData.allServices(sset);
1624        for uuid, handles in zip(services["uuids"], services["handles"]):
1625            trace.trace(6, "Service %s covers [%02d, %02d]" % (attData.uuid(uuid), handles[0], handles[1]));
1626
1627            if handles[0] > (prevLast+1):
1628                trace.trace(6, "Read Blob @[#%d]" % ((handles[0] + prevLast)//2));
1629                found, reply = __readBlob(transport, initiator, (handles[0] + prevLast)//2, 0, trace);
1630                success = success and not found and reply['error'] == ATTError.ATT_ERROR_INVALID_HANDLE;
1631                if not found:
1632                    trace.trace(6, "Reply: %s" % attData.error(reply['error']));
1633            prevLast = handles[1];
1634
1635        success = initiator.disconnect(0x13) and success;
1636
1637    return success;
1638
1639"""
1640    GATT/SR/GAR/BI-15-C [Insufficient Authorization error - Reading Long Characteristic Value]
1641"""
1642def gatt_sr_gar_bi_15_c(transport, upperTester, lowerTester, trace):
1643    success, mtuSize, initiator = preambleConnected(transport, upperTester, 92, trace);
1644    if success:
1645        sset, attData, gattData = 1, ATTData(), GATTData.instance();
1646        """
1647            Switch to Service Set #1
1648        """
1649        trace.trace(6, "Switching to Service Set #%d" % sset);
1650        switch_gatt_service_set(transport, lowerTester, sset, 200);
1651        """
1652            Collect all Characteristics that require READ AUTHORIZATION
1653        """
1654        characteristics = gattData.characteristics(sset, None, ATTPermission.ATT_PERM_READ_AUTHOR);
1655        for _uuid, _handle, _value_handle in zip(characteristics['uuid'], characteristics['handle'], characteristics['value_handle']):
1656            trace.trace(6, "Read Blob @[#%d]" % _value_handle);
1657            found, reply = readBlob(transport, initiator, _value_handle, mtuSize, trace);
1658            success = success and not found and (reply == ATTError.ATT_ERROR_INSUFFICIENT_AUTHORIZATION);
1659            trace.trace(6, "Reply: %s" % attData.error(reply));
1660
1661        success = initiator.disconnect(0x13) and success;
1662
1663    return success;
1664
1665"""
1666    GATT/SR/GAR/BI-16-C [Insufficient Authentication error - Reading Long Characteristic Value]
1667"""
1668def gatt_sr_gar_bi_16_c(transport, upperTester, lowerTester, trace):
1669    success, mtuSize, initiator = preambleConnected(transport, upperTester, 92, trace);
1670    if success:
1671        sset, attData, gattData = 1, ATTData(), GATTData.instance();
1672        """
1673            Switch to Service Set #1
1674        """
1675        trace.trace(6, "Switching to Service Set #%d" % sset);
1676        switch_gatt_service_set(transport, lowerTester, sset, 200);
1677        """
1678            Collect all Characteristics that require READ AUTHENTICATION
1679        """
1680        characteristics = gattData.characteristics(sset, None, ATTPermission.ATT_PERM_READ_AUTHEN);
1681        for _uuid, _handle, _value_handle in zip(characteristics['uuid'], characteristics['handle'], characteristics['value_handle']):
1682            trace.trace(6, "Read Blob @[#%d]" % _value_handle);
1683            found, reply = readBlob(transport, initiator, _value_handle, mtuSize, trace);
1684            success = success and not found and (reply == ATTError.ATT_ERROR_INSUFFICIENT_AUTHENTICATION);
1685            trace.trace(6, "Reply: %s" % attData.error(reply));
1686
1687        success = initiator.disconnect(0x13) and success;
1688
1689    return success;
1690
1691"""
1692    GATT/SR/GAR/BI-17-C [Insufficient Encryption Key Size error - Reading Long Characteristic Value]
1693"""
1694def gatt_sr_gar_bi_17_c(transport, upperTester, lowerTester, trace):
1695    success, mtuSize, initiator = preambleConnected(transport, upperTester, 92, trace);
1696    if success:
1697        sset, attData, gattData = 1, ATTData(), GATTData.instance();
1698        """
1699            Switch to Service Set #1
1700        """
1701        trace.trace(6, "Switching to Service Set #%d" % sset);
1702        switch_gatt_service_set(transport, lowerTester, sset, 200);
1703        """
1704            Collect all Characteristics that require READ ENCRYPTED
1705        """
1706        characteristics = gattData.characteristics(sset, None, ATTPermission.ATT_PERM_READ_ENCRYPT);
1707        for _uuid, _handle, _value_handle in zip(characteristics['uuid'], characteristics['handle'], characteristics['value_handle']):
1708            trace.trace(6, "Read Blob @[#%d]" % _value_handle);
1709            found, reply = readBlob(transport, initiator, _value_handle, mtuSize, trace);
1710            success = success and not found and (reply == ATTError.ATT_ERROR_INSUFFICIENT_ENCRYPTION);
1711            trace.trace(6, "Reply: %s" % attData.error(reply));
1712
1713        success = initiator.disconnect(0x13) and success;
1714
1715    return success;
1716
1717"""
1718    GATT/SR/GAR/BV-05-C [Server Reads Multiple Characteristic Values]
1719
1720    NOTE: If the Request is fragmented - no reponse is received.
1721"""
1722def gatt_sr_gar_bv_05_c(transport, upperTester, lowerTester, trace):
1723    success, mtuSize, initiator = preambleConnected(transport, upperTester, 46, trace);
1724    if success:
1725        sset, gattData = 2, GATTData.instance();
1726        """
1727            Switch to Service Set #2
1728        """
1729        trace.trace(6, "Switching to Service Set #%d" % sset);
1730        switch_gatt_service_set(transport, lowerTester, sset, 200);
1731        """
1732            Collect all Characteristics that can be READ
1733        """
1734        characteristics = gattData.characteristics(sset, None, ATTPermission.ATT_PERM_READ);
1735        _size = 0; _handles = []; _values = [];
1736        for _handle, _value_handle in zip(characteristics['handle'], characteristics['value_handle']):
1737            _value = gattData.characteristicValue(sset, _handle);
1738            if (_size + len(_value)) < (mtuSize-1):
1739                _size += len(_value);
1740                _handles += [ _value_handle ];
1741                _values += _value;
1742
1743        trace.trace(6, "Read Multiple Characteristics @[%s]" % formatArray(_handles));
1744        found, values = readMultipleCharacteristics(transport, initiator, _handles, trace);
1745        success = success and found and values == _values;
1746
1747        success = initiator.disconnect(0x13) and success;
1748
1749    return success;
1750
1751"""
1752    GATT/SR/GAR/BI-18-C [Read Not Permitted error - Reading Multiple Characteristic Values]
1753"""
1754def gatt_sr_gar_bi_18_c(transport, upperTester, lowerTester, trace):
1755    success, mtuSize, initiator = preambleConnected(transport, upperTester, 92, trace);
1756    if success:
1757        sset, attData, gattData = 2, ATTData(), GATTData.instance();
1758        """
1759            Switch to Service Set #2
1760        """
1761        trace.trace(6, "Switching to Service Set #%d" % sset);
1762        switch_gatt_service_set(transport, lowerTester, sset, 200);
1763        """
1764            Collect all Characteristics that can be READ
1765        """
1766        characteristics = gattData.characteristics(sset, None, ATTPermission.ATT_PERM_ANY_READ, True);
1767        _size = 0; _handles = []; _values = [];
1768        for _handle, _value_handle in zip(characteristics['handle'], characteristics['value_handle']):
1769            _value = gattData.characteristicValue(sset, _handle);
1770            if (_size + len(_value)) < (mtuSize-1):
1771                _size += len(_value);
1772                _handles += [ _value_handle ];
1773                _values += _value;
1774
1775        trace.trace(6, "Read Multiple Characteristics @[%s]" % formatArray(_handles));
1776        found, values = readMultipleCharacteristics(transport, initiator, _handles, trace);
1777        success = success and not found and values == ATTError.ATT_ERROR_READ_NOT_PERMITTED;
1778        if not found:
1779            trace.trace(6, "Reply: %s" % attData.error(values));
1780
1781        success = initiator.disconnect(0x13) and success;
1782
1783    return success;
1784
1785"""
1786    GATT/SR/GAR/BI-19-C [Invalid Handle error - Reading Multiple Characteristic Values]
1787"""
1788def gatt_sr_gar_bi_19_c(transport, upperTester, lowerTester, trace):
1789    success, mtuSize, initiator = preambleConnected(transport, upperTester, 92, trace);
1790    if success:
1791        sset, prevLast, attData, gattData = 2, 0, ATTData(), GATTData.instance();
1792        """
1793            Switch to Service Set #2
1794        """
1795        trace.trace(6, "Switching to Service Set #%d" % sset);
1796        switch_gatt_service_set(transport, lowerTester, sset, 200);
1797        """
1798            Collect all Services
1799        """
1800        services = gattData.allServices(sset);
1801        _handles = [];
1802        for handles in services["handles"]:
1803            if handles[0] > (prevLast+1):
1804                _handles += [ (handles[0] + prevLast)//2 ];
1805            prevLast = handles[1];
1806
1807        trace.trace(6, "Read Multiple Characteristics @[%s]" % formatArray(_handles));
1808        found, values = readMultipleCharacteristics(transport, initiator, _handles, trace);
1809        success = success and not found and values == ATTError.ATT_ERROR_INVALID_HANDLE;
1810        if not found:
1811            trace.trace(6, "Reply: %s" % attData.error(values));
1812
1813        success = initiator.disconnect(0x13) and success;
1814
1815    return success;
1816
1817"""
1818    GATT/SR/GAR/BI-20-C [Insufficient Authorization error - Reading Multiple Characteristic Values]
1819"""
1820def gatt_sr_gar_bi_20_c(transport, upperTester, lowerTester, trace):
1821    success, mtuSize, initiator = preambleConnected(transport, upperTester, 92, trace);
1822    if success:
1823        sset, attData, gattData = 1, ATTData(), GATTData.instance();
1824        """
1825            Switch to Service Set #1
1826        """
1827        trace.trace(6, "Switching to Service Set #%d" % sset);
1828        switch_gatt_service_set(transport, lowerTester, sset, 200);
1829        """
1830            Collect all Characteristics that require READ AUTHORIZATION
1831        """
1832        characteristics = gattData.characteristics(sset, None, ATTPermission.ATT_PERM_READ_AUTHOR);
1833        _handles = [];
1834        for _handle, _value_handle in zip(characteristics['handle'], characteristics['value_handle']):
1835            _handles += [ _value_handle ];
1836
1837        trace.trace(6, "Read Multiple Characteristics @[%s]" % formatArray(_handles));
1838        found, values = readMultipleCharacteristics(transport, initiator, _handles, trace);
1839        success = success and not found and values == ATTError.ATT_ERROR_INSUFFICIENT_AUTHORIZATION;
1840        if not found:
1841            trace.trace(6, "Reply: %s" % attData.error(values));
1842
1843        success = initiator.disconnect(0x13) and success;
1844
1845    return success;
1846
1847"""
1848    GATT/SR/GAR/BI-21-C [Insufficient Authentication error - Reading Multiple Characteristic Values]
1849"""
1850def gatt_sr_gar_bi_21_c(transport, upperTester, lowerTester, trace):
1851    success, mtuSize, initiator = preambleConnected(transport, upperTester, 92, trace);
1852    if success:
1853        sset, attData, gattData = 1, ATTData(), GATTData.instance();
1854        """
1855            Switch to Service Set #1
1856        """
1857        trace.trace(6, "Switching to Service Set #%d" % sset);
1858        switch_gatt_service_set(transport, lowerTester, sset, 200);
1859        """
1860            Collect all Characteristics that require READ AUTHENTICATION
1861        """
1862        characteristics = gattData.characteristics(sset, None, ATTPermission.ATT_PERM_READ_AUTHEN);
1863        _handles = [];
1864        for _handle, _value_handle in zip(characteristics['handle'], characteristics['value_handle']):
1865            _handles += [ _value_handle ];
1866
1867        trace.trace(6, "Read Multiple Characteristics @[%s]" % formatArray(_handles));
1868        found, values = readMultipleCharacteristics(transport, initiator, _handles, trace);
1869        success = success and not found and values == ATTError.ATT_ERROR_INSUFFICIENT_AUTHENTICATION;
1870        if not found:
1871            trace.trace(6, "Reply: %s" % attData.error(values));
1872
1873        success = initiator.disconnect(0x13) and success;
1874
1875    return success;
1876
1877"""
1878    GATT/SR/GAR/BI-22-C [Insufficient Encryption Key Size error - Reading Multiple Characteristic Values]
1879"""
1880def gatt_sr_gar_bi_22_c(transport, upperTester, lowerTester, trace):
1881    success, mtuSize, initiator = preambleConnected(transport, upperTester, 92, trace);
1882    if success:
1883        sset, attData, gattData = 1, ATTData(), GATTData.instance();
1884        """
1885            Switch to Service Set #1
1886        """
1887        trace.trace(6, "Switching to Service Set #%d" % sset);
1888        switch_gatt_service_set(transport, lowerTester, sset, 200);
1889        """
1890            Collect all Characteristics that require READ ENCRYPTED
1891        """
1892        characteristics = gattData.characteristics(sset, None, ATTPermission.ATT_PERM_READ_ENCRYPT);
1893        _handles = [];
1894        for _handle, _value_handle in zip(characteristics['handle'], characteristics['value_handle']):
1895            _handles += [ _value_handle ];
1896
1897        trace.trace(6, "Read Multiple Characteristics @[%s]" % formatArray(_handles));
1898        found, values = readMultipleCharacteristics(transport, initiator, _handles, trace);
1899        success = success and not found and values == ATTError.ATT_ERROR_INSUFFICIENT_ENCRYPTION;
1900        if not found:
1901            trace.trace(6, "Reply: %s" % attData.error(values));
1902
1903        success = initiator.disconnect(0x13) and success;
1904
1905    return success;
1906
1907"""
1908    GATT/SR/GAR/BV-06-C [Server Reads Characteristic Descriptors]
1909"""
1910def gatt_sr_gar_bv_06_c(transport, upperTester, lowerTester, trace):
1911    success, mtuSize, initiator = preambleConnected(transport, upperTester, 92, trace);
1912    if success:
1913        sset, gattData = 1, GATTData.instance();
1914        """
1915            Switch to Service Set #1
1916        """
1917        trace.trace(6, "Switching to Service Set #%d" % sset);
1918        switch_gatt_service_set(transport, lowerTester, sset, 200);
1919        """
1920            Collect all Descriptors that have READ access
1921        """
1922        descriptors = gattData.descriptors(sset, None, ATTPermission.ATT_PERM_READ);
1923        for _handle in descriptors['handle']:
1924            trace.trace(6, "Read Descriptor @[#%d]" % _handle);
1925            success, data = readCharacteristic(transport, initiator, _handle, trace);
1926            trace.trace(6, "Descriptor Value: %s" % formatArray(data));
1927            match = data == gattData.descriptorValue(sset, _handle);
1928            if not match:
1929                trace.trace(6, "    GATT Database  Value: %s" % formatArray(gattData.descriptorValue(sset, _handle)));
1930            success = success and match;
1931
1932        success = initiator.disconnect(0x13) and success;
1933
1934    return success;
1935
1936"""
1937    GATT/SR/GAR/BV-07-C [Server Reads Long Characteristic Descriptor]
1938"""
1939def gatt_sr_gar_bv_07_c(transport, upperTester, lowerTester, trace):
1940    success, mtuSize, initiator = preambleConnected(transport, upperTester, 23, trace);
1941    if success:
1942        sset, attData, gattData = 1, ATTData(), GATTData.instance();
1943        """
1944            Switch to Service Set #1
1945        """
1946        trace.trace(6, "Switching to Service Set #%d" % sset);
1947        switch_gatt_service_set(transport, lowerTester, sset, 200);
1948        """
1949            Collect all Descriptors that have READ access
1950        """
1951        descriptors = gattData.descriptors(sset, None, ATTPermission.ATT_PERM_READ);
1952        prevSize = 513;
1953        for m,n in zip([2,2,1,0], [mtuSize/2,0,0,mtuSize/2]):
1954            _descriptors = { 'uuid': [], 'handle': [] };
1955            for _uuid, _handle in zip(descriptors['uuid'], descriptors['handle']):
1956                _size = len(gattData.descriptorValue(sset, _handle));
1957                if m*mtuSize-1+n <= _size and _size < prevSize:
1958                    _descriptors['uuid']         += [ _uuid ];
1959                    _descriptors['handle']       += [ _handle ];
1960                    prevSize = _size;
1961
1962            for _uuid, _handle in zip(_descriptors['uuid'], _descriptors['handle']):
1963                trace.trace(6, "Read Descriptor %s [#%d]" % (attData.uuid(_uuid), _handle));
1964                found, reply = readCharacteristic(transport, initiator, _handle, trace);
1965                success = success and found and reply == gattData.descriptorValue(sset, _handle)[:mtuSize-1];
1966                if found:
1967                    trace.trace(6, "Data: %s" % formatArray(reply));
1968                found, reply = readBlob(transport, initiator, _handle, mtuSize, trace);
1969                success = success and found and reply == gattData.descriptorValue(sset, _handle);
1970                if found:
1971                    trace.trace(6, "Data: %s" % formatArray(reply));
1972
1973        success = initiator.disconnect(0x13) and success;
1974
1975    return success;
1976
1977"""
1978    GATT/SR/GAW/BV-01-C [Server Writes Without Response]
1979"""
1980def gatt_sr_gaw_bv_01_c(transport, upperTester, lowerTester, trace):
1981    success, mtuSize, initiator = preambleConnected(transport, upperTester, 46, trace);
1982    if success:
1983        sset, attData, gattData = 2, ATTData(), GATTData.instance();
1984        """
1985            Switch to Service Set #2
1986        """
1987        trace.trace(6, "Switching to Service Set #%d" % sset);
1988        switch_gatt_service_set(transport, lowerTester, sset, 200);
1989        """
1990            Collect all Characteristics that have WRITE access
1991        """
1992        characteristics = gattData.characteristics(sset, None, ATTPermission.ATT_PERM_WRITE);
1993        for _uuid, _handle, _value_handle, _permission in zip(characteristics['uuid'], characteristics['handle'], \
1994                                                              characteristics['value_handle'], characteristics['permission']):
1995            _value = gattData.characteristicValue(sset, _handle);
1996            if 1 < len(_value) and len(_value) < mtuSize-4:
1997                trace.trace(6, "Write Characteristic %s [#%d]" % (attData.uuid(_uuid), _value_handle));
1998                ok, reply = writeNoResponse(transport, initiator, _value_handle, _value[::-1], trace);
1999                success = success and ok;
2000                if not ok:
2001                    trace.trace(6, "Write failed: %s" % attData.error(reply['error']));
2002                else:
2003                    if (_permission & ATTPermission.ATT_PERM_READ) == ATTPermission.ATT_PERM_READ:
2004                        ok, value = readCharacteristic(transport, initiator, _value_handle, trace);
2005                        success = success and ok and value == _value[::-1];
2006                        trace.trace(6, "Write Verified: %s" % success);
2007                    if _value != _value[::-1]:
2008                        ok, reply = writeNoResponse(transport, initiator, _value_handle, _value, trace);
2009                        success = success and ok;
2010
2011        success = initiator.disconnect(0x13) and success;
2012
2013    return success;
2014
2015"""
2016    GATT/SR/GAW/BV-03-C [Server Writes Characteristic Value]
2017"""
2018def gatt_sr_gaw_bv_03_c(transport, upperTester, lowerTester, trace):
2019    success, mtuSize, initiator = preambleConnected(transport, upperTester, 92, trace);
2020    if success:
2021        sset, attData, gattData = 2, ATTData(), GATTData.instance();
2022        """
2023            Switch to Service Set #2
2024        """
2025        trace.trace(6, "Switching to Service Set #%d" % sset);
2026        switch_gatt_service_set(transport, lowerTester, sset, 200);
2027        """
2028            Collect all Characteristics that have WRITE access
2029        """
2030        characteristics = gattData.characteristics(sset, None, ATTPermission.ATT_PERM_WRITE);
2031        for _uuid, _handle, _value_handle, _permission in zip(characteristics['uuid'], characteristics['handle'], \
2032                                                              characteristics['value_handle'], characteristics['permission']):
2033            _value = gattData.characteristicValue(sset, _handle);
2034            if 2 < len(_value) and len(_value) < mtuSize-4:
2035                trace.trace(6, "Write Characteristic %s [#%d]" % (attData.uuid(_uuid), _value_handle));
2036                ok, reply = writeCharacteristic(transport, initiator, _value_handle, _value[::-1], trace);
2037                success = success and ok;
2038                if not ok:
2039                    trace.trace(6, "Write failed: %s" % attData.error(reply['error']));
2040                else:
2041                    if (_permission & ATTPermission.ATT_PERM_READ) == ATTPermission.ATT_PERM_READ:
2042                        ok, value = readCharacteristic(transport, initiator, _value_handle, trace);
2043                        success = success and ok and value == _value[::-1];
2044                        trace.trace(6, "Write Verified: %s" % success);
2045                    if _value != _value[::-1]:
2046                        ok, reply = writeCharacteristic(transport, initiator, _value_handle, _value, trace);
2047                        success = success and ok;
2048
2049        success = initiator.disconnect(0x13) and success;
2050
2051    return success;
2052
2053"""
2054    GATT/SR/GAW/BI-02-C [Invalid Handle error - Writing Characteristic Value]
2055"""
2056def gatt_sr_gaw_bi_02_c(transport, upperTester, lowerTester, trace):
2057    success, mtuSize, initiator = preambleConnected(transport, upperTester, 92, trace);
2058    if success:
2059        sset, prevLast, attData, gattData = 2, 0, ATTData(), GATTData.instance();
2060        """
2061            Switch to Service Set #2
2062        """
2063        trace.trace(6, "Switching to Service Set #%d" % sset);
2064        switch_gatt_service_set(transport, lowerTester, sset, 200);
2065        """
2066            Collect all Services
2067        """
2068        services = gattData.allServices(sset);
2069        for uuid, handles in zip(services["uuids"], services["handles"]):
2070            trace.trace(6, "Service %s covers [%02d, %02d]" % (attData.uuid(uuid), handles[0], handles[1]));
2071
2072            if handles[0] > (prevLast+1):
2073                trace.trace(6, "Write Characteristic @[#%d]" % ((handles[0] + prevLast)//2));
2074                ok, reply = writeCharacteristic(transport, initiator, (handles[0] + prevLast)//2, [ 0x00 ], trace);
2075                success = success and not ok and reply['error'] == ATTError.ATT_ERROR_INVALID_HANDLE;
2076                if not ok:
2077                    trace.trace(6, "Write failed: %s" % attData.error(reply['error']));
2078            prevLast = handles[1];
2079
2080        success = initiator.disconnect(0x13) and success;
2081
2082    return success;
2083
2084"""
2085    GATT/SR/GAW/BI-03-C [Write Not Permitted error - Writing Characteristic Value]
2086"""
2087def gatt_sr_gaw_bi_03_c(transport, upperTester, lowerTester, trace):
2088    success, mtuSize, initiator = preambleConnected(transport, upperTester, 92, trace);
2089    if success:
2090        sset, attData, gattData = 1, ATTData(), GATTData.instance();
2091        """
2092            Switch to Service Set #1
2093        """
2094        trace.trace(6, "Switching to Service Set #%d" % sset);
2095        switch_gatt_service_set(transport, lowerTester, sset, 200);
2096        """
2097            Collect all Characteristics that doesn't allow WRITE access
2098        """
2099        characteristics = gattData.characteristics(sset, None, ATTPermission.ATT_PERM_ANY_WRITE, True);
2100        for _uuid, _handle, _value_handle in zip(characteristics['uuid'], characteristics['handle'], characteristics['value_handle']):
2101            _value = gattData.characteristicValue(sset, _handle);
2102            if len(_value) < mtuSize-4:
2103                trace.trace(6, "Write Characteristic %s [#%d]" % (attData.uuid(_uuid), _value_handle));
2104                ok, reply = writeCharacteristic(transport, initiator, _value_handle, _value[::-1], trace);
2105                success = success and not ok and reply['error'] == ATTError.ATT_ERROR_WRITE_NOT_PERMITTED;
2106                if not ok:
2107                    trace.trace(6, "Write failed: %s" % attData.error(reply['error']));
2108
2109        success = initiator.disconnect(0x13) and success;
2110
2111    return success;
2112
2113"""
2114    GATT/SR/GAW/BI-04-C [Insufficient Authorization error - Writing Characteristic Value]
2115"""
2116def gatt_sr_gaw_bi_04_c(transport, upperTester, lowerTester, trace):
2117    success, mtuSize, initiator = preambleConnected(transport, upperTester, 92, trace);
2118    if success:
2119        sset, attData, gattData = 1, ATTData(), GATTData.instance();
2120        """
2121            Switch to Service Set #1
2122        """
2123        trace.trace(6, "Switching to Service Set #%d" % sset);
2124        switch_gatt_service_set(transport, lowerTester, sset, 200);
2125        """
2126            Collect all Characteristics that require WRITE Authorization
2127        """
2128        characteristics = gattData.characteristics(sset, None, ATTPermission.ATT_PERM_WRITE_AUTHOR);
2129        for _uuid, _handle, _value_handle in zip(characteristics['uuid'], characteristics['handle'], characteristics['value_handle']):
2130            _value = gattData.characteristicValue(sset, _handle);
2131            if len(_value) < mtuSize-4:
2132                trace.trace(6, "Write Characteristic %s [#%d]" % (attData.uuid(_uuid), _value_handle));
2133                ok, reply = writeCharacteristic(transport, initiator, _value_handle, _value[::-1], trace);
2134                success = success and not ok and reply['error'] == ATTError.ATT_ERROR_INSUFFICIENT_AUTHORIZATION;
2135                if not ok:
2136                    trace.trace(6, "Write failed: %s" % attData.error(reply['error']));
2137                else:
2138                    ok, reply = writeCharacteristic(transport, initiator, _value_handle, _value, trace);
2139
2140        success = initiator.disconnect(0x13) and success;
2141
2142    return success;
2143
2144"""
2145    GATT/SR/GAW/BI-05-C [Insufficient Authentication error - Writing Characteristic Value]
2146"""
2147def gatt_sr_gaw_bi_05_c(transport, upperTester, lowerTester, trace):
2148    success, mtuSize, initiator = preambleConnected(transport, upperTester, 92, trace);
2149    if success:
2150        sset, attData, gattData = 1, ATTData(), GATTData.instance();
2151        """
2152            Switch to Service Set #1
2153        """
2154        trace.trace(6, "Switching to Service Set #%d" % sset);
2155        switch_gatt_service_set(transport, lowerTester, sset, 200);
2156        """
2157            Collect all Characteristics that require WRITE Authentication
2158        """
2159        characteristics = gattData.characteristics(sset, None, ATTPermission.ATT_PERM_WRITE_AUTHEN);
2160        for _uuid, _handle, _value_handle in zip(characteristics['uuid'], characteristics['handle'], characteristics['value_handle']):
2161            _value = gattData.characteristicValue(sset, _handle);
2162            if len(_value) < mtuSize-4:
2163                trace.trace(6, "Write Characteristic %s [#%d]" % (attData.uuid(_uuid), _value_handle));
2164                ok, reply = writeCharacteristic(transport, initiator, _value_handle, _value[::-1], trace);
2165                success = success and not ok and reply['error'] == ATTError.ATT_ERROR_INSUFFICIENT_AUTHENTICATION;
2166                if not ok:
2167                    trace.trace(6, "Write failed: %s" % attData.error(reply['error']));
2168                else:
2169                    ok, reply = writeCharacteristic(transport, initiator, _value_handle, _value, trace);
2170
2171        success = initiator.disconnect(0x13) and success;
2172
2173    return success;
2174
2175"""
2176    GATT/SR/GAW/BI-06-C [Insufficient Encryption Key Size error - Writing Characteristic Value]
2177"""
2178def gatt_sr_gaw_bi_06_c(transport, upperTester, lowerTester, trace):
2179    success, mtuSize, initiator = preambleConnected(transport, upperTester, 92, trace);
2180    if success:
2181        sset, attData, gattData = 1, ATTData(), GATTData.instance();
2182        """
2183            Switch to Service Set #1
2184        """
2185        trace.trace(6, "Switching to Service Set #%d" % sset);
2186        switch_gatt_service_set(transport, lowerTester, sset, 200);
2187        """
2188            Collect all Characteristics that require WRITE Authentication
2189        """
2190        characteristics = gattData.characteristics(sset, None, ATTPermission.ATT_PERM_WRITE_ENCRYPT);
2191        for _uuid, _handle, _value_handle in zip(characteristics['uuid'], characteristics['handle'], characteristics['value_handle']):
2192            _value = gattData.characteristicValue(sset, _handle);
2193            if len(_value) < mtuSize-4:
2194                trace.trace(6, "Write Characteristic %s [#%d]" % (attData.uuid(_uuid), _value_handle));
2195                ok, reply = writeCharacteristic(transport, initiator, _value_handle, _value[::-1], trace);
2196                success = success and not ok and reply['error'] == ATTError.ATT_ERROR_INSUFFICIENT_ENCRYPTION;
2197                if not ok:
2198                    trace.trace(6, "Write failed: %s" % attData.error(reply['error']));
2199                else:
2200                    ok, reply = writeCharacteristic(transport, initiator, _value_handle, _value, trace);
2201
2202        success = initiator.disconnect(0x13) and success;
2203
2204    return success;
2205
2206"""
2207    GATT/SR/GAW/BV-05-C [Server Writes Long Characteristic Value]
2208
2209    NOTE: Attempting to execute this test with an MTU size of 23 bytes will fail with an error ATT_ERROR_PREPARE_QUEUE_FULL.
2210"""
2211def gatt_sr_gaw_bv_05_c(transport, upperTester, lowerTester, trace):
2212    success, mtuSize, initiator = preambleConnected(transport, upperTester, 46, trace);
2213    if success:
2214        sset, attData, gattData = 2, ATTData(), GATTData.instance();
2215        """
2216            Switch to Service Set #2
2217        """
2218        trace.trace(6, "Switching to Service Set #%d" % sset);
2219        switch_gatt_service_set(transport, lowerTester, sset, 200);
2220        """
2221            Collect all Characteristics that have WRITE access
2222        """
2223        characteristics = gattData.characteristics(sset, None, ATTPermission.ATT_PERM_WRITE);
2224        for _uuid, _handle, _value_handle, _permission in zip(characteristics['uuid'], characteristics['handle'], \
2225                                                              characteristics['value_handle'], characteristics['permission']):
2226            _value = gattData.characteristicValue(sset, _handle);
2227            if len(_value) > mtuSize-5:
2228                trace.trace(6, "Write Characteristic %s [#%d]" % (attData.uuid(_uuid), _value_handle));
2229                ok, reply = writeLong(transport, initiator, _value_handle, _value[::-1], mtuSize, trace);
2230                success = success and ok;
2231                if not ok:
2232                    trace.trace(6, "Write Long failed: %s" % attData.error(reply['error']));
2233                else:
2234                    if (_permission & ATTPermission.ATT_PERM_READ) == ATTPermission.ATT_PERM_READ:
2235                        ok, value = readBlob(transport, initiator, _value_handle, mtuSize, trace);
2236                        success = success and ok and value == _value[::-1];
2237                        trace.trace(6, "Write Verified: %s" % success);
2238                    if _value != _value[::-1]:
2239                        ok, reply = writeLong(transport, initiator, _value_handle, _value, mtuSize, trace);
2240                        success = success and ok;
2241
2242        success = initiator.disconnect(0x13) and success;
2243
2244    return success;
2245
2246"""
2247    GATT/SR/GAW/BI-07-C [Invalid Handle error - Writing Long Characteristic Value]
2248"""
2249def gatt_sr_gaw_bi_07_c(transport, upperTester, lowerTester, trace):
2250    success, mtuSize, initiator = preambleConnected(transport, upperTester, 92, trace);
2251    if success:
2252        sset, prevLast, attData, gattData = 2, 0, ATTData(), GATTData.instance();
2253        """
2254            Switch to Service Set #2
2255        """
2256        trace.trace(6, "Switching to Service Set #%d" % sset);
2257        switch_gatt_service_set(transport, lowerTester, sset, 200);
2258        """
2259            Collect all Services
2260        """
2261        services = gattData.allServices(sset);
2262        for uuid, handles in zip(services["uuids"], services["handles"]):
2263            trace.trace(6, "Service %s covers [%02d, %02d]" % (attData.uuid(uuid), handles[0], handles[1]));
2264
2265            if handles[0] > (prevLast+1):
2266                trace.trace(6, "Write Long Characteristic @[#%d]" % ((handles[0] + prevLast)//2));
2267                ok, reply = writeLong(transport, initiator, (handles[0] + prevLast)//2, [ 0x00 ], mtuSize, trace);
2268                success = success and not ok and reply['error'] == ATTError.ATT_ERROR_INVALID_HANDLE;
2269                if not ok:
2270                    trace.trace(6, "Write failed: %s" % attData.error(reply['error']));
2271            prevLast = handles[1];
2272
2273        success = initiator.disconnect(0x13) and success;
2274
2275    return success;
2276
2277"""
2278    GATT/SR/GAW/BI-08-C [Write Not Permitted error - Writing Long Characteristic Value]
2279"""
2280def gatt_sr_gaw_bi_08_c(transport, upperTester, lowerTester, trace):
2281    success, mtuSize, initiator = preambleConnected(transport, upperTester, 92, trace);
2282    if success:
2283        sset, attData, gattData = 1, ATTData(), GATTData.instance();
2284        """
2285            Switch to Service Set #1
2286        """
2287        trace.trace(6, "Switching to Service Set #%d" % sset);
2288        switch_gatt_service_set(transport, lowerTester, sset, 200);
2289        """
2290            Collect all Characteristics that doesn't allow WRITE access
2291        """
2292        characteristics = gattData.characteristics(sset, None, ATTPermission.ATT_PERM_ANY_WRITE, True);
2293        for _uuid, _handle, _value_handle in zip(characteristics['uuid'], characteristics['handle'], characteristics['value_handle']):
2294            _value = gattData.characteristicValue(sset, _handle);
2295            if len(_value) > mtuSize-5:
2296                trace.trace(6, "Write Long Characteristic %s [#%d]" % (attData.uuid(_uuid), _value_handle));
2297                ok, reply = writeLong(transport, initiator, _value_handle, _value[::-1], mtuSize, trace);
2298                success = success and not ok and reply['error'] == ATTError.ATT_ERROR_WRITE_NOT_PERMITTED;
2299                if not ok:
2300                    trace.trace(6, "Write failed: %s" % attData.error(reply['error']));
2301                else:
2302                    ok, reply = writeLong(transport, initiator, _value_handle, _value, mtuSize, trace);
2303
2304        success = initiator.disconnect(0x13) and success;
2305
2306    return success;
2307
2308"""
2309    GATT/SR/GAW/BI-09-C [Invalid Offset error - Writing Long Characteristic Value]
2310"""
2311def gatt_sr_gaw_bi_09_c(transport, upperTester, lowerTester, trace):
2312    success, mtuSize, initiator = preambleConnected(transport, upperTester, 43, trace);
2313    if success:
2314        sset, attData, gattData = 2, ATTData(), GATTData.instance();
2315        """
2316            Switch to Service Set #2
2317        """
2318        trace.trace(6, "Switching to Service Set #%d" % sset);
2319        switch_gatt_service_set(transport, lowerTester, sset, 200);
2320        """
2321            Filter out all Characteristics which have WRITE permission
2322        """
2323        characteristics = gattData.characteristics(sset, None, ATTPermission.ATT_PERM_WRITE);
2324        for _uuid, _handle, _value_handle in zip(characteristics['uuid'], characteristics['handle'], characteristics['value_handle']):
2325            _value = gattData.characteristicValue(sset, _handle);
2326            if len(_value) > mtuSize-5:
2327                trace.trace(6, "Write Long Characteristic %s [#%d]" % (attData.uuid(_uuid), _handle));
2328                ok, reply = __writeLong(transport, initiator, _value_handle, [ 0x00 ], len(_value)+1, trace);
2329                success = success and ok;
2330                if not ok:
2331                    trace.trace(6, "Reply: %s" % attData.error(reply['error']));
2332                else:
2333                    ok, reply = __writeExecute(transport, initiator, trace);
2334                    success = success and not ok and reply['error'] == ATTError.ATT_ERROR_INVALID_OFFSET;
2335                    if not ok:
2336                        trace.trace(6, "Reply: %s" % attData.error(reply['error']));
2337
2338        success = initiator.disconnect(0x13) and success;
2339
2340    return success;
2341
2342"""
2343    GATT/SR/GAW/BI-11-C [Insufficient Authorization error - Writing Long Characteristic Value]
2344"""
2345def gatt_sr_gaw_bi_11_c(transport, upperTester, lowerTester, trace):
2346    success, mtuSize, initiator = preambleConnected(transport, upperTester, 43, trace);
2347    if success:
2348        sset, attData, gattData = 1, ATTData(), GATTData.instance();
2349        """
2350            Switch to Service Set #1
2351        """
2352        trace.trace(6, "Switching to Service Set #%d" % sset);
2353        switch_gatt_service_set(transport, lowerTester, sset, 200);
2354        """
2355            Collect all Characteristics that require WRITE Authorization
2356        """
2357        characteristics = gattData.characteristics(sset, None, ATTPermission.ATT_PERM_WRITE_AUTHOR);
2358        for _uuid, _handle, _value_handle in zip(characteristics['uuid'], characteristics['handle'], characteristics['value_handle']):
2359            _value = gattData.characteristicValue(sset, _handle);
2360            trace.trace(6, "Write Characteristic %s [#%d]" % (attData.uuid(_uuid), _value_handle));
2361            ok, reply = writeLong(transport, initiator, _value_handle, _value[::-1], mtuSize, trace);
2362            success = success and not ok and reply['error'] == ATTError.ATT_ERROR_INSUFFICIENT_AUTHORIZATION;
2363            if not ok:
2364                trace.trace(6, "Write failed: %s" % attData.error(reply['error']));
2365            else:
2366                ok, reply = writeLong(transport, initiator, _value_handle, _value, mtuSize, trace);
2367
2368        success = initiator.disconnect(0x13) and success;
2369
2370    return success;
2371
2372"""
2373    GATT/SR/GAW/BI-12-C [Insufficient Authentication error - Writing Long Characteristic Value]
2374"""
2375def gatt_sr_gaw_bi_12_c(transport, upperTester, lowerTester, trace):
2376    success, mtuSize, initiator = preambleConnected(transport, upperTester, 43, trace);
2377    if success:
2378        sset, attData, gattData = 1, ATTData(), GATTData.instance();
2379        """
2380            Switch to Service Set #1
2381        """
2382        trace.trace(6, "Switching to Service Set #%d" % sset);
2383        switch_gatt_service_set(transport, lowerTester, sset, 200);
2384        """
2385            Collect all Characteristics that require WRITE Authentication
2386        """
2387        characteristics = gattData.characteristics(sset, None, ATTPermission.ATT_PERM_WRITE_AUTHEN);
2388        for _uuid, _handle, _value_handle in zip(characteristics['uuid'], characteristics['handle'], characteristics['value_handle']):
2389            _value = gattData.characteristicValue(sset, _handle);
2390            trace.trace(6, "Write Characteristic %s [#%d]" % (attData.uuid(_uuid), _value_handle));
2391            ok, reply = writeLong(transport, initiator, _value_handle, _value[::-1], mtuSize, trace);
2392            success = success and not ok and reply['error'] == ATTError.ATT_ERROR_INSUFFICIENT_AUTHENTICATION;
2393            if not ok:
2394                trace.trace(6, "Write failed: %s" % attData.error(reply['error']));
2395            else:
2396                ok, reply = writeLong(transport, initiator, _value_handle, _value, mtuSize, trace);
2397
2398        success = initiator.disconnect(0x13) and success;
2399
2400    return success;
2401
2402"""
2403    GATT/SR/GAW/BI-13-C [Insufficient Encryption Key Size error - Writing Long Characteristic Value]
2404"""
2405def gatt_sr_gaw_bi_13_c(transport, upperTester, lowerTester, trace):
2406    success, mtuSize, initiator = preambleConnected(transport, upperTester, 43, trace);
2407    if success:
2408        sset, attData, gattData = 1, ATTData(), GATTData.instance();
2409        """
2410            Switch to Service Set #1
2411        """
2412        trace.trace(6, "Switching to Service Set #%d" % sset);
2413        switch_gatt_service_set(transport, lowerTester, sset, 200);
2414        """
2415            Collect all Characteristics that require WRITE Authentication
2416        """
2417        characteristics = gattData.characteristics(sset, None, ATTPermission.ATT_PERM_WRITE_ENCRYPT);
2418        for _uuid, _handle, _value_handle in zip(characteristics['uuid'], characteristics['handle'], characteristics['value_handle']):
2419            _value = gattData.characteristicValue(sset, _handle);
2420            trace.trace(6, "Write Characteristic %s [#%d]" % (attData.uuid(_uuid), _value_handle));
2421            ok, reply = writeLong(transport, initiator, _value_handle, _value[::-1], mtuSize, trace);
2422            success = success and not ok and reply['error'] == ATTError.ATT_ERROR_INSUFFICIENT_ENCRYPTION;
2423            if not ok:
2424                trace.trace(6, "Write failed: %s" % attData.error(reply['error']));
2425            else:
2426                ok, reply = writeLong(transport, initiator, _value_handle, _value, mtuSize, trace);
2427
2428        success = initiator.disconnect(0x13) and success;
2429
2430    return success;
2431
2432"""
2433    GATT/SR/GAW/BV-08-C [Server Writes Characteristic Descriptors]
2434"""
2435def gatt_sr_gaw_bv_08_c(transport, upperTester, lowerTester, trace):
2436    success, mtuSize, initiator = preambleConnected(transport, upperTester, 92, trace);
2437    if success:
2438        sset, attData, gattData = 1, ATTData(), GATTData.instance();
2439        """
2440            Switch to Service Set #1
2441        """
2442        trace.trace(6, "Switching to Service Set #%d" % sset);
2443        switch_gatt_service_set(transport, lowerTester, sset, 200);
2444        """
2445            Collect all Descriptors that have WRITE access
2446        """
2447        descriptors = gattData.descriptors(sset, None, ATTPermission.ATT_PERM_WRITE);
2448        for _handle in descriptors['handle']:
2449            _value = gattData.descriptorValue(sset, _handle);
2450            if len(_value) < mtuSize-3:
2451                trace.trace(6, "Write Descriptor @[#%d]" % _handle);
2452                ok, reply = writeCharacteristic(transport, initiator, _handle, _value[::-1], trace);
2453                success = success and ok;
2454                if not ok:
2455                    trace.trace(6, "Write failed: %s" % attData.error(reply['error']));
2456                else:
2457                    ok, reply = writeCharacteristic(transport, initiator, _handle, _value, trace);
2458                    success = success and ok;
2459
2460        success = initiator.disconnect(0x13) and success;
2461
2462    return success;
2463
2464"""
2465    GATT/SR/GAW/BV-09-C [Server Writes Long Characteristic Descriptors]
2466"""
2467def gatt_sr_gaw_bv_09_c(transport, upperTester, lowerTester, trace):
2468    success, mtuSize, initiator = preambleConnected(transport, upperTester, 46, trace);
2469    if success:
2470        sset, attData, gattData = 1, ATTData(), GATTData.instance();
2471        """
2472            Switch to Service Set #1
2473        """
2474        trace.trace(6, "Switching to Service Set #%d" % sset);
2475        switch_gatt_service_set(transport, lowerTester, sset, 200);
2476        """
2477            Collect all Descriptors that have WRITE access
2478        """
2479        descriptors = gattData.descriptors(sset, None, ATTPermission.ATT_PERM_WRITE);
2480        for _handle in descriptors['handle']:
2481            _value = gattData.descriptorValue(sset, _handle);
2482            if len(_value) > mtuSize-5:
2483                trace.trace(6, "Write Descriptor @[#%d]" % _handle);
2484                ok, reply = writeLong(transport, initiator, _handle, _value[::-1], mtuSize, trace);
2485                success = success and ok;
2486                if not ok:
2487                    trace.trace(6, "Write failed: %s" % attData.error(reply['error']));
2488                else:
2489                    ok, reply = writeLong(transport, initiator, _handle, _value, mtuSize, trace);
2490                    success = success and ok;
2491
2492        success = initiator.disconnect(0x13) and success;
2493
2494    return success;
2495
2496"""
2497    GATT/SR/GAW/BV-11-C [No Pending Prepared Write Requests error - Characteristic Value Reliable Writes]
2498"""
2499def gatt_sr_gaw_bv_11_c(transport, upperTester, lowerTester, trace):
2500    success, mtuSize, initiator = preambleConnected(transport, upperTester, 92, trace);
2501    if success:
2502        sset = 1;
2503        """
2504            Switch to Service Set #1
2505        """
2506        trace.trace(6, "Switching to Service Set #%d" % sset);
2507        switch_gatt_service_set(transport, lowerTester, sset, 200);
2508        """
2509            Issue a WRITE EXECUTE command without any pending PREPARED WRITES
2510        """
2511        ok, reply = __writeExecute(transport, initiator, trace);
2512        success = success and ok;
2513
2514        success = initiator.disconnect(0x13) and success;
2515
2516    return success;
2517
2518"""
2519    GATT/SR/GAW/BI-32-C [Invalid Attribute Value Length error - Writing Characteristic Value]
2520"""
2521def gatt_sr_gaw_bi_32_c(transport, upperTester, lowerTester, trace):
2522    success, mtuSize, initiator = preambleConnected(transport, upperTester, 92, trace);
2523    if success:
2524        sset, attData, gattData = 1, ATTData(), GATTData.instance();
2525        """
2526            Switch to Service Set #1
2527        """
2528        trace.trace(6, "Switching to Service Set #%d" % sset);
2529        switch_gatt_service_set(transport, lowerTester, sset, 200);
2530        """
2531            Collect all Characteristics that have WRITE access
2532        """
2533        characteristics = gattData.characteristics(sset, None, ATTPermission.ATT_PERM_WRITE);
2534        for _uuid, _handle, _value_handle, _permission in zip(characteristics['uuid'], characteristics['handle'], \
2535                                                              characteristics['value_handle'], characteristics['permission']):
2536            _value = gattData.characteristicValue(sset, _handle);
2537            if 4 < len(_value) and len(_value) < mtuSize-6:
2538                trace.trace(6, "Write Characteristic %s [#%d]" % (attData.uuid(_uuid), _value_handle));
2539                ok, reply = writeCharacteristic(transport, initiator, _value_handle, _value + [ 0x00, 0x00 ], trace);
2540                success = success and not ok and reply['error'] == ATTError.ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LENGTH;
2541                if not ok:
2542                    trace.trace(6, "Write failed: %s" % attData.error(reply['error']));
2543
2544        success = initiator.disconnect(0x13) and success;
2545
2546    return success;
2547
2548"""
2549    GATT/SR/GAW/BI-33-C [Invalid Attribute Value Length error - Writing Long Characteristic Value]
2550"""
2551def gatt_sr_gaw_bi_33_c(transport, upperTester, lowerTester, trace):
2552    success, mtuSize, initiator = preambleConnected(transport, upperTester, 46, trace);
2553    if success:
2554        sset, attData, gattData = 2, ATTData(), GATTData.instance();
2555        """
2556            Switch to Service Set #2
2557        """
2558        trace.trace(6, "Switching to Service Set #%d" % sset);
2559        switch_gatt_service_set(transport, lowerTester, sset, 200);
2560        """
2561            Collect all Characteristics that have WRITE access
2562        """
2563        characteristics = gattData.characteristics(sset, None, ATTPermission.ATT_PERM_WRITE);
2564        for _uuid, _handle, _value_handle, _permission in zip(characteristics['uuid'], characteristics['handle'], \
2565                                                              characteristics['value_handle'], characteristics['permission']):
2566            _value = gattData.characteristicValue(sset, _handle);
2567            if len(_value) > mtuSize-5:
2568                trace.trace(6, "Write Characteristic %s [#%d]" % (attData.uuid(_uuid), _value_handle));
2569                ok, reply = writeLong(transport, initiator, _value_handle, _value + [ 0x00, 0x00 ], mtuSize, trace);
2570                success = success and not ok and reply['error'] == ATTError.ATT_ERROR_INVALID_ATTRIBUTE_VALUE_LENGTH;
2571                if not ok:
2572                    trace.trace(6, "Write failed: %s" % attData.error(reply['error']));
2573
2574        success = initiator.disconnect(0x13) and success;
2575
2576    return success;
2577
2578"""
2579    GATT/SR/GAN/BV-01-C [Server generates Characteristic Value Notification]
2580"""
2581def gatt_sr_gan_bv_01_c(transport, upperTester, lowerTester, trace):
2582    success, mtuSize, initiator = preambleConnected(transport, upperTester, 46, trace);
2583    if success:
2584        sset, attData, gattData = 1, ATTData(), GATTData.instance();
2585        """
2586            Switch to Service Set #1
2587        """
2588        trace.trace(6, "Switching to Service Set #%d" % sset);
2589        switch_gatt_service_set(transport, lowerTester, sset, 200);
2590        """
2591            Collect all Descriptors that have WRITE access
2592        """
2593        descriptors = gattData.descriptors(sset, None, ATTPermission.ATT_PERM_WRITE);
2594        for _uuid, _handle in zip(descriptors['uuid'], descriptors['handle']):
2595            if _uuid == 0x2902 and _handle >= 16:
2596                trace.trace(7, "Descriptor %s @[#%d]" %(attData.uuid(_uuid), _handle));
2597                ok, reply = writeCharacteristic(transport, initiator, _handle, [ 0x01, 0x00 ], trace);
2598                success = success and ok;
2599                if success:
2600                    gatt_service_notify(transport, lowerTester, 100);
2601                    ok, reply = notification(transport, initiator, trace);
2602                    success = success and ok;
2603                    if ok:
2604                        trace.trace(7, "Notification @[#%d] %s" %(reply['handle'], formatArray(reply['value'])));
2605                    ok, reply = writeCharacteristic(transport, initiator, _handle, [ 0x00, 0x00 ], trace);
2606                    success = success and ok;
2607
2608        success = initiator.disconnect(0x13) and success;
2609
2610    return success;
2611
2612"""
2613    GATT/SR/GAI/BV-01-C [Server generates Characteristic Value Indication]
2614"""
2615def gatt_sr_gai_bv_01_c(transport, upperTester, lowerTester, trace):
2616    success, mtuSize, initiator = preambleConnected(transport, upperTester, 46, trace);
2617    if success:
2618        sset, attData, gattData = 2, ATTData(), GATTData.instance();
2619        """
2620            Switch to Service Set #2
2621        """
2622        trace.trace(6, "Switching to Service Set #%d" % sset);
2623        switch_gatt_service_set(transport, lowerTester, sset, 200);
2624        """
2625            Collect all Descriptors that have WRITE access
2626        """
2627        descriptors = gattData.descriptors(sset, None, ATTPermission.ATT_PERM_WRITE);
2628        for _uuid, _handle in zip(descriptors['uuid'], descriptors['handle']):
2629            if _uuid == 0x2902 and _handle >= 16:
2630                trace.trace(7, "Descriptor %s @[#%d]" %(attData.uuid(_uuid), _handle));
2631                ok, reply = writeCharacteristic(transport, initiator, _handle, [ 0x02, 0x00 ], trace);
2632                success = success and ok;
2633                if success:
2634                    gatt_service_indicate(transport, lowerTester, 100);
2635                    ok, reply = indication(transport, initiator, trace);
2636                    success = success and ok;
2637                    if ok:
2638                        trace.trace(7, "Indication @[#%d] %s" %(reply['handle'], formatArray(reply['value'])));
2639                    ok, reply = writeCharacteristic(transport, initiator, _handle, [ 0x00, 0x00 ], trace);
2640                    success = success and ok;
2641
2642        success = initiator.disconnect(0x13) and success;
2643
2644    return success;
2645
2646"""
2647    GATT/SR/GAS/BV-01-C [Server accepts Service Changed Characteristic Indication]
2648"""
2649def gatt_sr_gas_bv_01_c(transport, upperTester, lowerTester, trace):
2650    success, mtuSize, initiator = preambleConnected(transport, upperTester, 46, trace);
2651    if success:
2652        sset, attData, gattData = 1, ATTData(), GATTData.instance();
2653        """
2654        Switch to Service Set #1
2655        """
2656        trace.trace(6, "Switching to Service Set #%d" % sset);
2657        switch_gatt_service_set(transport, lowerTester, sset, 200);
2658        """
2659        Collect all Descriptors that have WRITE access
2660        """
2661        descriptors = gattData.descriptors(sset, None, ATTPermission.ATT_PERM_WRITE);
2662        for _uuid, _handle in zip(descriptors['uuid'], descriptors['handle']):
2663            if _uuid == 0x2902 and _handle < 16:
2664	            trace.trace(7, "Descriptor %s @[#%d]" %(attData.uuid(_uuid), _handle));
2665	            ok, reply = writeCharacteristic(transport, initiator, _handle, [ 0x02, 0x00 ], trace);
2666	            success = success and ok;
2667	            if success:
2668	                sset = 2;
2669	                """
2670	                    Switch to Service Set #2
2671	                """
2672	                trace.trace(6, "Switching to Service Set #%d" % sset);
2673	                switch_gatt_service_set(transport, lowerTester, sset, 200);
2674	                ok, reply = indication(transport, initiator, trace);
2675	                success = success and ok;
2676	                if ok:
2677	                    trace.trace(7, "Indication @[#%d] %s" %(reply['handle'], formatArray(reply['value'])));
2678	                ok, reply = writeCharacteristic(transport, initiator, _handle, [ 0x00, 0x00 ], trace);
2679	                success = success and ok;
2680
2681        success = initiator.disconnect(0x13) and success;
2682
2683    return success;
2684
2685"""
2686    GATT/SR/UNS/BI-01-C [Server sends Unsupported ATT Requests]
2687"""
2688def gatt_sr_uns_bi_01_c(transport, upperTester, lowerTester, trace):
2689    success, mtuSize, initiator = preambleConnected(transport, upperTester, 46, trace);
2690    if success:
2691        attData = ATTData();
2692        """
2693        Generate an Invalid ATT Request
2694        """
2695        txData = attData.encode( ATTOpcode.ATT_INVALID_REQUEST, [ random.randint(0,255) for _ in range(mtuSize-4) ] );
2696        trace.trace(7, str(attData));
2697        success = attRequest( transport, initiator, txData, trace );
2698        if success:
2699            success, rxData = attResponse( transport, initiator, trace );
2700            if success:
2701                reply = attData.decode( rxData );
2702                trace.trace(7, str(attData));
2703                success = reply['opcode'] == ATTOpcode.ATT_ERROR_RESPONSE;
2704                if success:
2705                    success = reply['error'] == ATTError.ATT_ERROR_REQUEST_NOT_SUPPORTED;
2706
2707        success = initiator.disconnect(0x13) and success;
2708
2709    return success;
2710
2711"""
2712    GATT/SR/UNS/BI-02-C [Server sends Unsupported ATT Commands]
2713"""
2714def gatt_sr_uns_bi_02_c(transport, upperTester, lowerTester, trace):
2715    success, mtuSize, initiator = preambleConnected(transport, upperTester, 46, trace);
2716    if success:
2717        attData = ATTData();
2718        """
2719        Generate an Invalid ATT Command
2720        """
2721        txData = attData.encode( ATTOpcode.ATT_INVALID_COMMAND, [ random.randint(0,255) for _ in range(mtuSize-4) ] );
2722        trace.trace(7, str(attData));
2723        success = attRequest( transport, initiator, txData, trace );
2724        if success:
2725            success, rxData = attResponse( transport, initiator, trace );
2726            if success:
2727                reply = attData.decode( rxData );
2728                trace.trace(7, str(attData));
2729            success = not success;
2730
2731        success = initiator.disconnect(0x13) and success;
2732
2733    return success;
2734
2735"""
2736    GATT/SR/GPA/BV-01-C [Server Reads Primary Service Declaration]
2737"""
2738def gatt_sr_gpa_bv_01_c(transport, upperTester, lowerTester, trace):
2739    success, mtuSize, initiator = preambleConnected(transport, upperTester, 46, trace);
2740    if success:
2741        attData, gattData = ATTData(), GATTData.instance();
2742
2743        for sset in range(4):
2744            """
2745                Switching Service Set
2746            """
2747            trace.trace(6, "Switching to Service Set #%d" % sset);
2748            switch_gatt_service_set(transport, lowerTester, sset, 200);
2749            """
2750                Discover all Primary Services
2751            """
2752            ok, services = discoverPrimaryServices(transport, initiator, trace);
2753            if ok:
2754                for _uuid, _handles in zip(services["uuids"], services["handles"]):
2755                    trace.trace(6, "Service %s covers handles [0x%02X, 0x%02X]" % (attData.uuid(_uuid), _handles[0], _handles[1]));
2756                ok = services == gattData.primaryServices(sset)
2757                trace.trace(6, "Verified Service Set: %s" % ok);
2758            else:
2759                trace.trace(6, "Unable to discover Primary Services!");
2760            success = success and ok;
2761
2762        success = initiator.disconnect(0x13) and success;
2763
2764    return success;
2765
2766"""
2767    GATT/SR/GPA/BV-02-C [Server Reads Secondary Service Declaration]
2768"""
2769def gatt_sr_gpa_bv_02_c(transport, upperTester, lowerTester, trace):
2770    success, mtuSize, initiator = preambleConnected(transport, upperTester, 46, trace);
2771    if success:
2772        attData, gattData = ATTData(), GATTData.instance();
2773
2774        for sset in range(4):
2775            """
2776                Switching Service Set
2777            """
2778            trace.trace(6, "Switching to Service Set #%d" % sset);
2779            switch_gatt_service_set(transport, lowerTester, sset, 200);
2780            """
2781                Discover all Secondary Services
2782            """
2783            ok, services = secondaryServicesByType(transport, initiator, trace);
2784            if ok:
2785                for _uuid, _handle in zip(services["uuid"], services["handle"]):
2786                    trace.trace(6, "Service %s at handle 0x%02X" % (attData.uuid(_uuid), _handle));
2787                ok = services == gattData.secondaryServices(sset)
2788                trace.trace(6, "Verified Service Set: %s" % ok);
2789            elif sset == 0:
2790                ok = services == gattData.secondaryServices(sset)
2791                trace.trace(6, "Verified Service Set: %s" % ok);
2792            else:
2793                trace.trace(6, "Unable to discover Secondary Services!");
2794            success = success and ok;
2795
2796        success = initiator.disconnect(0x13) and success;
2797
2798    return success;
2799
2800"""
2801    GATT/SR/GPA/BV-03-C [Server Reads Include Declaration]
2802"""
2803def gatt_sr_gpa_bv_03_c(transport, upperTester, lowerTester, trace):
2804    success, mtuSize, initiator = preambleConnected(transport, upperTester, 46, trace);
2805    if success:
2806        attData, gattData = ATTData(), GATTData.instance();
2807
2808        for sset in range(4):
2809            """
2810                Switching Service Set
2811            """
2812            trace.trace(6, "Switching to Service Set #%d" % sset);
2813            switch_gatt_service_set(transport, lowerTester, sset, 200);
2814            """
2815                Discover all Included Services
2816            """
2817            ok, services = includedServicesByType(transport, initiator, trace);
2818            if ok:
2819                for _uuid, _handles in zip(services["uuids"], services["handles"]):
2820                    trace.trace(6, "Service %s covers handles [0x%02X, 0x%02X]" % (attData.uuid(_uuid), _handles[0], _handles[1]));
2821                ok = services == gattData.includedServices(sset)
2822                trace.trace(6, "Verified Service Set: %s" % ok);
2823            elif sset == 0:
2824                ok = services == gattData.includedServices(sset)
2825                trace.trace(6, "Verified Service Set: %s" % ok);
2826            else:
2827                trace.trace(6, "Unable to discover Included Services!");
2828            success = success and ok;
2829
2830        success = initiator.disconnect(0x13) and success;
2831
2832    return success;
2833
2834"""
2835    GATT/SR/GPA/BV-04-C [Server Reads Characteristic Declaration]
2836"""
2837def gatt_sr_gpa_bv_04_c(transport, upperTester, lowerTester, trace):
2838    success, mtuSize, initiator = preambleConnected(transport, upperTester, 46, trace);
2839    if success:
2840        attData, gattData = ATTData(), GATTData.instance();
2841
2842        for sset in range(4):
2843            """
2844                Switching Service Set
2845
2846            """
2847            trace.trace(6, "Switching to Service Set #%d" % sset);
2848            switch_gatt_service_set(transport, lowerTester, sset, 200);
2849            """
2850                Discover all Characteristic Declarations
2851            """
2852            ok, characteristics = characteristicsByType(transport, initiator, [0x0001, 0xffff], trace);
2853            if ok:
2854                for _uuid, _handle, _value_handle, _property in zip(characteristics['uuid'], characteristics['handle'], \
2855                                                                    characteristics['value_handle'], characteristics['property']):
2856                    trace.trace(6, "Characteristic %s handle 0x%02X value handle 0x%02X properties %s" % \
2857                                   (attData.uuid(_uuid), _handle, _value_handle, attData.property(_property)));
2858
2859                _characteristics = gattData.characteristics(sset);
2860                _characteristics.pop("permission");
2861
2862                ok = characteristics == _characteristics
2863                trace.trace(6, "Verified Characteristics: %s" % ok);
2864            else:
2865                trace.trace(6, "Unable to discover Characteristic Declarations!");
2866            success = success and ok;
2867
2868        success = initiator.disconnect(0x13) and success;
2869
2870    return success;
2871
2872"""
2873    GATT/SR/GPA/BV-05-C [Server Reads Characteristic Extended Properties Declaration]
2874"""
2875def gatt_sr_gpa_bv_05_c(transport, upperTester, lowerTester, trace):
2876    success, mtuSize, initiator = preambleConnected(transport, upperTester, 46, trace);
2877    if success:
2878        attData, gattData = ATTData(), GATTData.instance();
2879
2880        for sset in range(4):
2881            """
2882                Switching Service Set
2883
2884            """
2885            trace.trace(6, "Switching to Service Set #%d" % sset);
2886            switch_gatt_service_set(transport, lowerTester, sset, 200);
2887
2888            _descriptors = filterCharacteristics(gattData.descriptors(sset), 0x2900);
2889
2890            """
2891                Discover all Characteristic Declarations for Extended Properties
2892            """
2893            ok, descriptors = specificDescriptors(transport, initiator, [0x0001, 0xffff], 0x2900, trace);
2894            if ok:
2895                for _uuid, _handle in zip(descriptors['uuid'], descriptors['handle']):
2896                    _success, value = readCharacteristic(transport, initiator, _handle, trace);
2897                    _value = gattData.descriptorValue(sset, _handle);
2898                    if _success:
2899                        _success = value == _value;
2900                        trace.trace(6, "Descriptor %s handle 0x%02X value %s - %s" % (attData.uuid(_uuid), _handle, formatArray(value), _success));
2901                    else:
2902                        trace.trace(6, "Descriptor %s handle 0x%02X value %s" % (attData.uuid(_uuid), _handle, attData.error(value)));
2903                    success = success and _success;
2904
2905                ok = descriptors == _descriptors
2906                trace.trace(6, "Verified Descriptors: %s" % ok);
2907            elif sset == 0:
2908                ok = descriptors == _descriptors
2909                trace.trace(6, "Verified Descriptors: %s" % ok);
2910            else:
2911                trace.trace(6, "Unable to discover Extended Properties Descriptors!");
2912            success = success and ok;
2913
2914        success = initiator.disconnect(0x13) and success;
2915
2916    return success;
2917
2918"""
2919    GATT/SR/GPA/BV-06-C [Server Reads Characteristic User Description Descriptor]
2920"""
2921def gatt_sr_gpa_bv_06_c(transport, upperTester, lowerTester, trace):
2922    success, mtuSize, initiator = preambleConnected(transport, upperTester, 46, trace);
2923    if success:
2924        attData, gattData = ATTData(), GATTData.instance();
2925
2926        for sset in range(4):
2927            """
2928                Switching Service Set
2929
2930            """
2931            trace.trace(6, "Switching to Service Set #%d" % sset);
2932            switch_gatt_service_set(transport, lowerTester, sset, 200);
2933
2934            _descriptors = filterCharacteristics(gattData.descriptors(sset), 0x2901);
2935
2936            """
2937                Discover all Characteristic Declarations for Extended Properties
2938            """
2939            ok, descriptors = specificDescriptors(transport, initiator, [0x0001, 0xffff], 0x2901, trace);
2940            if ok:
2941                for _uuid, _handle in zip(descriptors['uuid'], descriptors['handle']):
2942                    _success, value = readStringCharacteristic(transport, initiator, _handle, trace);
2943                    _value = gattData.descriptorString(sset, _handle);
2944                    if _success:
2945                        _success = value == _value;
2946                        trace.trace(6, "Descriptor %s handle 0x%02X value %s - %s" % (attData.uuid(_uuid), _handle, value, _success));
2947                    else:
2948                        trace.trace(6, "Descriptor %s handle 0x%02X value %s" % (attData.uuid(_uuid), _handle, attData.error(value)));
2949                    success = success and _success;
2950
2951                ok = descriptors == _descriptors
2952                trace.trace(6, "Verified Descriptors: %s" % ok);
2953            elif sset == 0:
2954                ok = descriptors == _descriptors
2955                trace.trace(6, "Verified Descriptors: %s" % ok);
2956            else:
2957                trace.trace(6, "Unable to discover User Description Descriptors!");
2958            success = success and ok;
2959
2960        success = initiator.disconnect(0x13) and success;
2961
2962    return success;
2963
2964"""
2965    GATT/SR/GPA/BV-07-C [Server Reads Client Characteristic Configuration Descriptor]
2966"""
2967def gatt_sr_gpa_bv_07_c(transport, upperTester, lowerTester, trace):
2968    success, mtuSize, initiator = preambleConnected(transport, upperTester, 46, trace);
2969    if success:
2970        attData, gattData = ATTData(), GATTData.instance();
2971
2972        for sset in range(4):
2973            """
2974                Switching Service Set
2975
2976            """
2977            trace.trace(6, "Switching to Service Set #%d" % sset);
2978            switch_gatt_service_set(transport, lowerTester, sset, 200);
2979
2980            _descriptors = filterCharacteristics(gattData.descriptors(sset), 0x2902);
2981
2982            """
2983                Discover all Client Characteristic Configuration Descriptors
2984            """
2985            ok, descriptors = specificDescriptors(transport, initiator, [0x0001, 0xffff], 0x2902, trace);
2986            if ok:
2987                for _uuid, _handle in zip(descriptors['uuid'], descriptors['handle']):
2988                    _success, value = readCharacteristic(transport, initiator, _handle, trace);
2989                    _value = gattData.descriptorValue(sset, _handle);
2990                    if _success:
2991                        _success = value == _value;
2992                        trace.trace(6, "Descriptor %s handle 0x%02X value %s - %s" % (attData.uuid(_uuid), _handle, formatArray(value), _success));
2993                    else:
2994                        trace.trace(6, "Descriptor %s handle 0x%02X value %s" % (attData.uuid(_uuid), _handle, attData.error(value)));
2995                    success = success and _success;
2996
2997                ok = descriptors == _descriptors
2998                trace.trace(6, "Verified Descriptors: %s" % ok);
2999            elif sset == 0:
3000                ok = descriptors == _descriptors
3001                trace.trace(6, "Verified Descriptors: %s" % ok);
3002            else:
3003                trace.trace(6, "Unable to discover Client Characteristic Configuration Descriptors!");
3004            success = success and ok;
3005
3006        success = initiator.disconnect(0x13) and success;
3007
3008    return success;
3009
3010"""
3011    GATT/SR/GPA/BV-08-C [Server Reads Server Characteristic Configuration Descriptor]
3012"""
3013def gatt_sr_gpa_bv_08_c(transport, upperTester, lowerTester, trace):
3014    success, mtuSize, initiator = preambleConnected(transport, upperTester, 46, trace);
3015    if success:
3016        attData, gattData = ATTData(), GATTData.instance();
3017
3018        for sset in range(4):
3019            """
3020                Switching Service Set
3021
3022            """
3023            trace.trace(6, "Switching to Service Set #%d" % sset);
3024            switch_gatt_service_set(transport, lowerTester, sset, 200);
3025
3026            _descriptors = filterCharacteristics(gattData.descriptors(sset), 0x2903);
3027
3028            """
3029                Discover all Server Characteristic Configuration Descriptors
3030            """
3031            ok, descriptors = specificDescriptors(transport, initiator, [0x0001, 0xffff], 0x2903, trace);
3032            if ok:
3033                for _uuid, _handle in zip(descriptors['uuid'], descriptors['handle']):
3034                    _success, value = readCharacteristic(transport, initiator, _handle, trace);
3035                    _value = gattData.descriptorValue(sset, _handle);
3036                    if _success:
3037                        _success = value == _value;
3038                        trace.trace(6, "Descriptor %s handle 0x%02X value %s - %s" % (attData.uuid(_uuid), _handle, formatArray(value), _success));
3039                    else:
3040                        trace.trace(6, "Descriptor %s handle 0x%02X value %s" % (attData.uuid(_uuid), _handle, attData.error(value)));
3041                    success = success and _success;
3042
3043                ok = descriptors == _descriptors
3044                trace.trace(6, "Verified Descriptors: %s" % ok);
3045            elif sset == 0:
3046                ok = descriptors == _descriptors
3047                trace.trace(6, "Verified Descriptors: %s" % ok);
3048            else:
3049                trace.trace(6, "Unable to discover Server Characteristic Configuration Descriptors!");
3050            success = success and ok;
3051
3052        success = initiator.disconnect(0x13) and success;
3053
3054    return success;
3055
3056"""
3057    GATT/SR/GPA/BV-12-C [Server handles Characteristic Presentation Format Descriptors]
3058"""
3059def gatt_sr_gpa_bv_12_c(transport, upperTester, lowerTester, trace):
3060    success, mtuSize, initiator = preambleConnected(transport, upperTester, 46, trace);
3061    if success:
3062        attData, gattData = ATTData(), GATTData.instance();
3063
3064        for sset in range(4):
3065            """
3066                Switching Service Set
3067
3068            """
3069            trace.trace(6, "Switching to Service Set #%d" % sset);
3070            switch_gatt_service_set(transport, lowerTester, sset, 200);
3071
3072            _descriptors = filterCharacteristics(gattData.descriptors(sset), 0x2904);
3073
3074            """
3075                Discover all Characteristic Presentation Format Descriptors
3076            """
3077            ok, descriptors = specificDescriptors(transport, initiator, [0x0001, 0xffff], 0x2904, trace);
3078            if ok:
3079                for _uuid, _handle in zip(descriptors['uuid'], descriptors['handle']):
3080                    _success, value = readCharacteristic(transport, initiator, _handle, trace);
3081                    _value = gattData.descriptorValue(sset, _handle);
3082                    if _success:
3083                        _success = value == _value;
3084                        trace.trace(6, "Descriptor %s handle 0x%02X value %s - %s" % (attData.uuid(_uuid), _handle, formatArray(value), _success));
3085                    else:
3086                        trace.trace(6, "Descriptor %s handle 0x%02X value %s" % (attData.uuid(_uuid), _handle, attData.error(value)));
3087                    success = success and _success;
3088
3089                    characteristic = gattData.characteristicWithDescriptor(sset, _handle);
3090                    _success, value = readCharacteristic(transport, initiator, characteristic['value_handle'], trace);
3091                    trace.trace(6, "Characteristic %s handle 0x%02X value %s" % \
3092                                   (attData.uuid(characteristic['uuid']), characteristic['handle'], formatArray(value)));
3093
3094                ok = descriptors == _descriptors
3095                trace.trace(6, "Verified Descriptors: %s" % ok);
3096            elif sset == 0:
3097                ok = descriptors == _descriptors
3098                trace.trace(6, "Verified Descriptors: %s" % ok);
3099            else:
3100                trace.trace(6, "Unable to discover Characteristic Presentation Format Descriptors!");
3101            success = success and ok;
3102
3103        success = initiator.disconnect(0x13) and success;
3104
3105    return success;
3106
3107__tests__ = {
3108    "GAP/GAT/BV-01-C":       [ gap_gat_bv_01_c,       'Mandatory Characteristics' ],
3109#   "GAP/GAT/BV-02-C":       [ gap_gat_bv_02_c,       'Peripheral Privacy Flag Characteristic' ],
3110#   "GAP/GAT/BV-03-C":       [ gap_gat_bv_03_c,       'Reconnection Address Characteristic' ],
3111    "GAP/GAT/BV-04-C":       [ gap_gat_bv_04_c,       'Peripheral Preferred Connection Parameters Characteristic' ],
3112#   "GAP/GAT/BV-05-C":       [ gap_gat_bv_05_c,       'Changing Device Name' ],
3113    "GAP/IDLE/NAMP/BV-01-C": [ gap_idle_namp_bv_01_c, 'Name Discovery Procedure GATT Client' ],
3114#   "GAP/GAT/BX-01-C":       [ gap_gat_bx_01_c,       'Discover All Services' ],
3115
3116    "GATT/SR/GAC/BV-01-C":   [ gatt_sr_gac_bv_01_c,   'Server accepts Server Configuration' ],
3117    "GATT/SR/GAD/BV-01-C":   [ gatt_sr_gad_bv_01_c,   'Server Discovers All Primary Services' ],
3118    "GATT/SR/GAD/BV-02-C":   [ gatt_sr_gad_bv_02_c,   'Server Discovers Primary Services by Service UUID' ],
3119    "GATT/SR/GAD/BV-03-C":   [ gatt_sr_gad_bv_03_c,   'Server Finds Included Services' ],
3120    "GATT/SR/GAD/BV-04-C":   [ gatt_sr_gad_bv_04_c,   'Server Discovers All Characteristics of a Service' ],
3121    "GATT/SR/GAD/BV-05-C":   [ gatt_sr_gad_bv_05_c,   'Server Discovers Characteristics by UUID' ],
3122    "GATT/SR/GAD/BV-06-C":   [ gatt_sr_gad_bv_06_c,   'Server Discovers All Characteristic Descriptors' ],
3123    "GATT/SR/GAR/BV-01-C":   [ gatt_sr_gar_bv_01_c,   'Server Reads Characteristic Value' ],
3124    "GATT/SR/GAR/BI-01-C":   [ gatt_sr_gar_bi_01_c,   'Read Not Permitted error - Reading Characteristic Value' ],
3125    "GATT/SR/GAR/BI-02-C":   [ gatt_sr_gar_bi_02_c,   'Invalid Handle error - Reading Characteristic Value' ],
3126    "GATT/SR/GAR/BI-03-C":   [ gatt_sr_gar_bi_03_c,   'Insufficient Authorization error - Reading Characteristic Value' ],
3127    "GATT/SR/GAR/BI-04-C":   [ gatt_sr_gar_bi_04_c,   'Insufficient Authentication error - Reading Characteristic Value' ],
3128    "GATT/SR/GAR/BV-03-C":   [ gatt_sr_gar_bv_03_c,   'Server Reads using Characteristic UUID' ],
3129    "GATT/SR/GAR/BI-06-C":   [ gatt_sr_gar_bi_06_c,   'Read Not Permitted error - Reading Characteristic by UUID' ],
3130    "GATT/SR/GAR/BI-07-C":   [ gatt_sr_gar_bi_07_c,   'Attribute Not Found error - Reading Characteristic by UUID' ],
3131    "GATT/SR/GAR/BI-09-C":   [ gatt_sr_gar_bi_09_c,   'Insufficient Authorization error - Reading Using Characteristic UUID' ],
3132    "GATT/SR/GAR/BI-10-C":   [ gatt_sr_gar_bi_10_c,   'Insufficient Authentication error - Reading Using Characteristic UUID' ],
3133    "GATT/SR/GAR/BI-11-C":   [ gatt_sr_gar_bi_11_c,   'Insufficient Encryption Key Size error - Reading Using Characteristic UUID' ],
3134    "GATT/SR/GAR/BV-04-C":   [ gatt_sr_gar_bv_04_c,   'Server Reads Long Characteristic Value' ],
3135    "GATT/SR/GAR/BI-12-C":   [ gatt_sr_gar_bi_12_c,   'Read Not Permitted error - Reading Long Characteristic Value' ],
3136    "GATT/SR/GAR/BI-13-C":   [ gatt_sr_gar_bi_13_c,   'Invalid Offset error - Reading Long Characteristic Value' ],
3137    "GATT/SR/GAR/BI-14-C":   [ gatt_sr_gar_bi_14_c,   'Invalid Handle error - Reading Long Characteristic Value' ],
3138    "GATT/SR/GAR/BI-15-C":   [ gatt_sr_gar_bi_15_c,   'Insufficient Authorization error - Reading Long Characteristic Value' ],
3139    "GATT/SR/GAR/BI-16-C":   [ gatt_sr_gar_bi_16_c,   'Insufficient Authentication error - Reading Long Characteristic Value' ],
3140    "GATT/SR/GAR/BI-17-C":   [ gatt_sr_gar_bi_17_c,   'Insufficient Encryption Key Size error - Reading Long Characteristic Value' ],
3141    "GATT/SR/GAR/BV-05-C":   [ gatt_sr_gar_bv_05_c,   'Server Reads Multiple Characteristic Values' ],
3142    "GATT/SR/GAR/BI-18-C":   [ gatt_sr_gar_bi_18_c,   'Read Not Permitted error - Reading Multiple Characteristic Values' ],
3143    "GATT/SR/GAR/BI-19-C":   [ gatt_sr_gar_bi_19_c,   'Invalid Handle error - Reading Multiple Characteristic Values' ],
3144    "GATT/SR/GAR/BI-20-C":   [ gatt_sr_gar_bi_20_c,   'Insufficient Authorization error - Reading Multiple Characteristic Values' ],
3145    "GATT/SR/GAR/BI-21-C":   [ gatt_sr_gar_bi_21_c,   'Insufficient Authentication error - Reading Multiple Characteristic Values' ],
3146    "GATT/SR/GAR/BI-22-C":   [ gatt_sr_gar_bi_22_c,   'Insufficient Encryption Key Size error - Reading Multiple Characteristic Values' ],
3147    "GATT/SR/GAR/BV-06-C":   [ gatt_sr_gar_bv_06_c,   'Server Reads Characteristic Descriptors' ],
3148    "GATT/SR/GAR/BV-07-C":   [ gatt_sr_gar_bv_07_c,   'Server Reads Long Characteristic Descriptor' ],
3149    "GATT/SR/GAW/BV-01-C":   [ gatt_sr_gaw_bv_01_c,   'Server Writes Without Response' ],
3150    "GATT/SR/GAW/BV-03-C":   [ gatt_sr_gaw_bv_03_c,   'Server Writes Characteristic Value' ],
3151    "GATT/SR/GAW/BI-02-C":   [ gatt_sr_gaw_bi_02_c,   'Invalid Handle error - Writing Characteristic Value' ],
3152    "GATT/SR/GAW/BI-03-C":   [ gatt_sr_gaw_bi_03_c,   'Write Not Permitted error - Writing Characteristic Value' ],
3153    "GATT/SR/GAW/BI-04-C":   [ gatt_sr_gaw_bi_04_c,   'Insufficient Authorization error - Writing Characteristic Value' ],
3154    "GATT/SR/GAW/BI-05-C":   [ gatt_sr_gaw_bi_05_c,   'Insufficient Authentication error - Writing Characteristic Value' ],
3155    "GATT/SR/GAW/BI-06-C":   [ gatt_sr_gaw_bi_06_c,   'Insufficient Encryption Key Size error - Writing Characteristic Value' ],
3156    "GATT/SR/GAW/BV-05-C":   [ gatt_sr_gaw_bv_05_c,   'Server Writes Long Characteristic Value' ],
3157    "GATT/SR/GAW/BI-07-C":   [ gatt_sr_gaw_bi_07_c,   'Invalid Handle error - Writing Long Characteristic Value' ],
3158    "GATT/SR/GAW/BI-08-C":   [ gatt_sr_gaw_bi_08_c,   'Write Not Permitted error - Writing Long Characteristic Value' ],
3159    "GATT/SR/GAW/BI-09-C":   [ gatt_sr_gaw_bi_09_c,   'Invalid Offset error - Writing Long Characteristic Value' ],
3160    "GATT/SR/GAW/BI-11-C":   [ gatt_sr_gaw_bi_11_c,   'Insufficient Authorization error - Writing Long Characteristic Value' ],
3161    "GATT/SR/GAW/BI-12-C":   [ gatt_sr_gaw_bi_12_c,   'Insufficient Authentication error - Writing Long Characteristic Value' ],
3162    "GATT/SR/GAW/BI-13-C":   [ gatt_sr_gaw_bi_13_c,   'Insufficient Encryption Key Size error - Writing Long Characteristic Value' ],
3163    "GATT/SR/GAW/BV-08-C":   [ gatt_sr_gaw_bv_08_c,   'Server Writes Characteristic Descriptors' ],
3164    "GATT/SR/GAW/BV-09-C":   [ gatt_sr_gaw_bv_09_c,   'Server Writes Long Characteristic Descriptors' ],
3165    "GATT/SR/GAW/BV-11-C":   [ gatt_sr_gaw_bv_11_c,   'No Pending Prepared Write Requests error - Characteristic Value Reliable Writes' ],
3166    "GATT/SR/GAW/BI-32-C":   [ gatt_sr_gaw_bi_32_c,   'Invalid Attribute Value Length error - Writing Characteristic Value' ],
3167    "GATT/SR/GAW/BI-33-C":   [ gatt_sr_gaw_bi_33_c,   'Invalid Attribute Value Length error - Writing Long Characteristic Value' ],
3168    "GATT/SR/GAN/BV-01-C":   [ gatt_sr_gan_bv_01_c,   'Server generates Characteristic Value Notification' ],
3169    "GATT/SR/GAI/BV-01-C":   [ gatt_sr_gai_bv_01_c,   'Server generates Characteristic Value Indication' ],
3170    "GATT/SR/GAS/BV-01-C":   [ gatt_sr_gas_bv_01_c,   'Server accepts Service Changed Characteristic Indication' ],
3171    "GATT/SR/UNS/BI-01-C":   [ gatt_sr_uns_bi_01_c,   'Server sends Unsupported ATT Requests' ],
3172    "GATT/SR/UNS/BI-02-C":   [ gatt_sr_uns_bi_02_c,   'Server sends Unsupported ATT Commands' ],
3173    "GATT/SR/GPA/BV-01-C":   [ gatt_sr_gpa_bv_01_c,   'Server Reads Primary Service Declaration' ],
3174    "GATT/SR/GPA/BV-02-C":   [ gatt_sr_gpa_bv_02_c,   'Server Reads Secondary Service Declaration' ],
3175    "GATT/SR/GPA/BV-03-C":   [ gatt_sr_gpa_bv_03_c,   'Server Reads Include Declaration' ],
3176    "GATT/SR/GPA/BV-04-C":   [ gatt_sr_gpa_bv_04_c,   'Server Reads Characteristic Declaration' ],
3177    "GATT/SR/GPA/BV-05-C":   [ gatt_sr_gpa_bv_05_c,   'Server Reads Characteristic Extended Properties Declaration' ],
3178    "GATT/SR/GPA/BV-06-C":   [ gatt_sr_gpa_bv_06_c,   'Server Reads Characteristic User Description Descriptor' ],
3179    "GATT/SR/GPA/BV-07-C":   [ gatt_sr_gpa_bv_07_c,   'Server Reads Client Characteristic Configuration Descriptor' ],
3180    "GATT/SR/GPA/BV-08-C":   [ gatt_sr_gpa_bv_08_c,   'Server Reads Server Characteristic Configuration Descriptor' ],
3181    "GATT/SR/GPA/BV-12-C":   [ gatt_sr_gpa_bv_12_c,   'Server handles Characteristic Presentation Format Descriptors' ]
3182};
3183
3184_maxNameLength = max([ len(key) for key in __tests__ ]);
3185
3186_spec = { key: TestSpec(name = key, number_devices = 1, description = "#[" + __tests__[key][1] + "]", test_private = __tests__[key][0]) for key in __tests__ };
3187
3188"""
3189    Return the test spec which contains info about all the tests
3190    this test module provides
3191"""
3192def get_tests_specs():
3193    return _spec;
3194
3195def preamble(transport, trace):
3196    global lowerIRK, upperIRK, lowerRandomAddress, upperRandomAddress;
3197
3198    ok = success = preamble_standby(transport, 0, trace);
3199    trace.trace(4, "preamble Standby " + ("PASS" if success else "FAIL"));
3200    success, upperIRK, upperRandomAddress = preamble_device_address_set(transport, 0, trace);
3201    trace.trace(4, "preamble Device Address Set " + ("PASS" if success else "FAIL"));
3202    ok = ok and success;
3203    return ok;
3204
3205"""
3206    Run a test given its test_spec
3207"""
3208def run_a_test(args, transport, trace, test_spec, device_dumps):
3209    try:
3210        success = preamble(transport, trace);
3211    except Exception as e:
3212        trace.trace(3, "Preamble generated exception: %s" % str(e));
3213        success = False;
3214
3215    trace.trace(2, "%-*s %s test started..." % (_maxNameLength, test_spec.name, test_spec.description[1:]));
3216    test_f = test_spec.test_private;
3217    try:
3218        if test_f.__code__.co_argcount > 4:
3219            success = success and test_f(transport, 0, 1, trace, device_dumps);
3220        elif test_f.__code__.co_argcount > 3:
3221            success = success and test_f(transport, 0, 1, trace);
3222        else:
3223            success = success and test_f(transport, 0, trace);
3224    except Exception as e:
3225        import traceback
3226        traceback.print_exc()
3227        trace.trace(3, "Test generated exception: %s" % str(e));
3228        success = False;
3229
3230    return not success
3231