1# -*- coding: utf-8 -*-
2# Copyright 2019 Oticon A/S
3# SPDX-License-Identifier: Apache-2.0
4
5from numpy import random;
6import os;
7import math;
8from enum import IntEnum;
9from components.utils import *;
10from components.basic_commands import *;
11from components.address import *;
12from components.events import *;
13from components.resolvable import *;
14from components.advertiser import *;
15from components.scanner import *;
16from components.initiator import *;
17from components.preambles import *;
18from components.test_spec import TestSpec;
19
20global lowerIRK, upperIRK, lowerRandomAddress, upperRandomAddress;
21
22class Role(IntEnum):
23    CENTRAL = 0
24    PERIPHERAL  = 1
25
26def __check_command_complete_event(transport, idx, trace):
27    event = get_event(transport, idx, 100);
28    trace.trace(7, str(event));
29    return event.isCommandComplete();
30
31def __check_unknown_command_rsp_event(transport, idx, trace, status):
32    event = get_event(transport, idx, 100);
33    trace.trace(7, str(event));
34    return status == 1 and (event.isCommandComplete() or event.isCommandStatus())
35
36"""
37    HCI/GEV/BV-01-C [Status return for Unsupported Commands]
38"""
39def hci_gev_bv_01_c(transport, idx, trace):
40
41    NumRsp, length, lap = 0, 1, toArray(0x9E8B00, 3);
42
43    status = inquire(transport, idx, lap, length, NumRsp, 100);
44    success = __check_unknown_command_rsp_event(transport, idx, trace, status);
45
46    status = read_buffer_size(transport, idx, 100);
47    success = __check_unknown_command_rsp_event(transport, idx, trace, status) and success;
48
49    le, simul = 0, 0;
50
51    status = write_le_host_support(transport, idx, le, simul, 100);
52    success = __check_unknown_command_rsp_event(transport, idx, trace, status) and success;
53
54    handle, props, PrimChannelMap, OwnAddrType, PeerAddrType = 0, 0, 0, 0, 0;
55    PrimMinInterval = [0 for _ in range(3)];
56    PrimMaxInterval = [0 for _ in range(3)];
57    AVal = [0 for _ in range(6)];
58    FilterPolicy, TxPower, PrimAdvPhy, SecAdvMaxSkip, SecAdvPhy, sid, ScanReqNotifyEnable = 0, 0, 0, 0, 0, 0, 0;
59
60    status = le_set_extended_advertising_parameters(transport, idx, handle, props, PrimMinInterval, PrimMaxInterval, PrimChannelMap, \
61                                                    OwnAddrType, PeerAddrType, AVal, FilterPolicy, TxPower, PrimAdvPhy, SecAdvMaxSkip, \
62                                                    SecAdvPhy, sid, ScanReqNotifyEnable, 100);
63    success = __check_unknown_command_rsp_event(transport, idx, trace, status) and success;
64
65    handle, op, FragPref = 0, 0, 0;
66    data = [];
67
68    status = le_set_extended_advertising_data(transport, idx, handle, op, FragPref, data, 100);
69    success = __check_unknown_command_rsp_event(transport, idx, trace, status) and success;
70
71    handle, op, FragPref = 0, 0, 0;
72    data = [];
73
74    status = le_set_extended_scan_response_data(transport, idx, handle, op, FragPref, data, 100);
75    success = __check_unknown_command_rsp_event(transport, idx, trace, status) and success;
76
77    enable, SetNum = 0, 0;
78    SHandle = [0 for i in range(SetNum)];
79    SDuration = [0 for i in range(SetNum)];
80    SMaxExtAdvEvts = [0 for i in range(SetNum)];
81
82    status = le_set_extended_advertising_enable(transport, idx, enable, SetNum, SHandle, SDuration, SMaxExtAdvEvts, 100);
83    success = __check_unknown_command_rsp_event(transport, idx, trace, status) and success;
84
85    status = le_read_maximum_advertising_data_length(transport, idx, 100);
86    success = __check_unknown_command_rsp_event(transport, idx, trace, status) and success;
87
88    status = le_read_number_of_supported_advertising_sets(transport, idx, 100);
89    success = __check_unknown_command_rsp_event(transport, idx, trace, status) and success;
90
91    handle = 0;
92
93    status = le_remove_advertising_set(transport, idx, handle, 100);
94    success = __check_unknown_command_rsp_event(transport, idx, trace, status) and success;
95
96    status = le_clear_advertising_sets(transport, idx, 100);
97    success = __check_unknown_command_rsp_event(transport, idx, trace, status) and success;
98
99    handle, MinInterval, MaxInterval, props = 0, 0, 0, 0;
100
101    status = le_set_periodic_advertising_parameters(transport, idx, handle, MinInterval, MaxInterval, props, 100);
102    success = __check_unknown_command_rsp_event(transport, idx, trace, status) and success;
103
104    handle, op, dataLength = 0, 0, 251;
105    data = [0 for i in range(dataLength)];
106
107    status = le_set_periodic_advertising_data(transport, idx, handle, op, dataLength, data, 100);
108    success = __check_unknown_command_rsp_event(transport, idx, trace, status) and success;
109
110    handle, enable = 0, 0;
111
112    status = le_set_periodic_advertising_enable(transport, idx, enable, handle, 100);
113    success = __check_unknown_command_rsp_event(transport, idx, trace, status) and success;
114
115    OwnAddrType, FilterPolicy, phys = 0, 0, 0;
116    PType = [0 for i in range(phys)];
117    PInterval = [0 for i in range(phys)];
118    PWindow = [0 for i in range(phys)];
119
120    status = le_set_extended_scan_parameters(transport, idx, OwnAddrType, FilterPolicy, phys, PType, PInterval, PWindow, 100);
121    success = __check_unknown_command_rsp_event(transport, idx, trace, status) and success;
122
123    enable, FilterDup, duration, period = 0, 0, 0, 0;
124
125    status = le_set_extended_scan_enable(transport, idx, enable, FilterDup, duration, period, 100);
126    success = __check_unknown_command_rsp_event(transport, idx, trace, status) and success;
127
128    FilterPolicy, OwnAddrType, PeerAddrType, phys = 0, 0, 0, 0;
129    AVal = [0 for i in range(6)];
130    PInterval = [0 for i in range(phys)];
131    PWindow = [0 for i in range(phys)];
132    PConnIntervalMin = [0 for i in range(phys)];
133    PConnIntervalMax = [0 for i in range(phys)];
134    PConnLatency = [0 for i in range(phys)];
135    PSupervisionTimeout = [0 for i in range(phys)];
136    PMinCeLen = [0 for i in range(phys)];
137    PMaxCeLen = [0 for i in range(phys)];
138
139    status = le_extended_create_connection(transport, idx, FilterPolicy, OwnAddrType, PeerAddrType, AVal, phys, PInterval, PWindow, \
140                                           PConnIntervalMin, PConnIntervalMax, PConnLatency, PSupervisionTimeout, PMinCeLen, PMaxCeLen, 100);
141    success = __check_unknown_command_rsp_event(transport, idx, trace, status) and success;
142
143    FilterPolicy, sid, AddrType, skip, SyncTimeout, unused = 0, 0, 0, 0, 0, 0;
144    AVal = [0 for i in range(6)];
145
146    status = le_periodic_advertising_create_sync(transport, idx, FilterPolicy, sid, AddrType, AVal, skip, SyncTimeout, unused, 100);
147    success = __check_unknown_command_rsp_event(transport, idx, trace, status) and success;
148
149    status = le_periodic_advertising_create_sync_cancel(transport, idx, 100);
150    success = __check_unknown_command_rsp_event(transport, idx, trace, status) and success;
151
152    handle = 0;
153
154    status = le_periodic_advertising_terminate_sync(transport, idx, handle, 100);
155    success = __check_unknown_command_rsp_event(transport, idx, trace, status) and success;
156
157    AddrType, sid = 0, 0;
158    AVal = [0 for i in range(6)];
159
160    status = le_add_device_to_periodic_advertiser_list(transport, idx, AddrType, AVal, sid, 100);
161    success = __check_unknown_command_rsp_event(transport, idx, trace, status) and success;
162
163    AddrType, sid = 0, 0;
164    AVal = [0 for i in range(6)];
165
166    status = le_remove_device_from_periodic_advertiser_list(transport, idx, AddrType, AVal, sid, 100);
167    success = __check_unknown_command_rsp_event(transport, idx, trace, status) and success;
168
169    status = le_clear_periodic_advertiser_list(transport, idx, 100);
170    success = __check_unknown_command_rsp_event(transport, idx, trace, status) and success;
171
172    status = le_read_periodic_advertiser_list_size(transport, idx, 100);
173    success = __check_unknown_command_rsp_event(transport, idx, trace, status) and success;
174
175    status = le_read_rf_path_compensation(transport, idx, 100);
176    success = __check_unknown_command_rsp_event(transport, idx, trace, status) and success;
177
178    TxPathComp, RxPathComp = 0, 0;
179
180    status = le_write_rf_path_compensation(transport, idx, TxPathComp, RxPathComp, 100);
181    success = __check_unknown_command_rsp_event(transport, idx, trace, status) and success;
182
183    return success;
184
185"""
186    HCI/CFC/BV-02-C [Reported Buffer Size]
187"""
188def hci_cfc_bv_02_c(transport, idx, trace):
189
190    status, LeMaxLen, LeMaxNum = le_read_buffer_size(transport, idx, 100);
191    trace.trace(6, "LE Read Buffer Size Command returns status: 0x%02X" % status);
192    success = __check_command_complete_event(transport, idx, trace) and (status == 0);
193
194    if LeMaxLen == 0 and LeMaxNum == 0:
195        status, AclMaxLen, ScoMaxLen, AclMaxNum, ScoMaxNum = read_buffer_size(transport, idx, 100);
196        trace.trace(6, "Read Buffer Size Command returns status: 0x%02X" % status);
197        success = success and __check_command_complete_event(transport, idx, trace) and (status == 0);
198
199    return success;
200
201"""
202    HCI/CIN/BV-01-C [Features returned by Read Local Supported Features Command]
203"""
204def hci_cin_bv_01_c(transport, idx, trace):
205
206    status, features = read_local_supported_features(transport, idx, 100);
207    trace.trace(6, "Read Local Supported Features Command returns status: 0x%02X" % status);
208    success = __check_command_complete_event(transport, idx, trace) and (status == 0);
209    if success:
210        showFeatures(features, trace);
211
212    return success;
213
214"""
215    HCI/CIN/BV-03-C [Supported Commands returned by Read Local Supported Commands Command]
216"""
217def hci_cin_bv_03_c(transport, idx, trace):
218
219    status, commands = read_local_supported_commands(transport, idx, 100);
220    trace.trace(6, "Read Local Supported Commands Command returns status: 0x%02X" % status);
221    success = __check_command_complete_event(transport, idx, trace) and (status == 0);
222    if success:
223        showCommands(commands, trace);
224
225    return success;
226
227"""
228    HCI/CIN/BV-04-C [Versions returned by Read Local Version Information Command]
229"""
230def hci_cin_bv_04_c(transport, idx, trace):
231
232    status, HCIVersion, HCIRevision, LMPVersion, manufacturer, LMPSubversion = read_local_version_information(transport, idx, 100);
233    trace.trace(6, "Read Local Version Information Command returns status: 0x%02X" % status);
234    success = __check_command_complete_event(transport, idx, trace) and (status == 0);
235    if success:
236        trace.trace(6, "HCI Version:    %i" % HCIVersion);
237        trace.trace(6, "HCI Revision:   0x%04X" % HCIRevision);
238        trace.trace(6, "LMP Version:    %i" % LMPVersion);
239        trace.trace(6, "LMP Subversion: 0x%04X" % LMPSubversion);
240        trace.trace(6, "Manufacturer:   0x%04X" % manufacturer);
241
242    return success;
243
244"""
245    HCI/CIN/BV-06-C [Reported Filter Accept List Size]
246"""
247def hci_cin_bv_06_c(transport, idx, trace):
248
249    status = le_clear_filter_accept_list(transport, idx, 100);
250    trace.trace(6, "LE Clear Filter Accept List Command returns status: 0x%02X" % status);
251    success = __check_command_complete_event(transport, idx, trace) and (status == 0);
252
253    status, FalSize = le_read_filter_accept_list_size(transport, idx, 100);
254    trace.trace(6, "LE Read Filter Accept List Size Command returns status: 0x%02X list size: %i" % (status, FalSize));
255    success = success and __check_command_complete_event(transport, idx, trace) and (status == 0);
256
257    for n in range(FalSize+1):
258        AddrType = 0;
259        AVal = [random.randint(0,255) for _ in range(6)];
260        if n < FalSize:
261            lastAVal = AVal
262        status = le_add_device_to_filter_accept_list(transport, idx, AddrType, AVal, 100);
263        trace.trace(6, "LE Add Device to Filter Accept List Command returns status: 0x%02X" % status);
264        success = success and __check_command_complete_event(transport, idx, trace) and ((status == 0) if n < FalSize else (status == 7));
265
266        status = le_remove_device_from_filter_accept_list(transport, idx, AddrType, lastAVal, 100);
267        trace.trace(6, "LE Remove Device from Filter Accept List Command returns status: 0x%02X" % status);
268        success = success and __check_command_complete_event(transport, idx, trace) and (status == 0);
269
270        status = le_add_device_to_filter_accept_list(transport, idx, AddrType, lastAVal, 100);
271        trace.trace(6, "LE Add Device to Filter Accept List Command returns status: 0x%02X" % status);
272        success = success and __check_command_complete_event(transport, idx, trace) and (status == 0);
273
274    return success;
275
276"""
277    HCI/CIN/BV-09-C [Feature Bits returned by Read LE Public Key Validation Feature Bit]
278"""
279def hci_cin_bv_09_c(transport, idx, trace):
280
281    status, features = le_read_local_supported_features(transport, idx, 100);
282    trace.trace(6, "LE Read Local Supported Features Command returns status: 0x%02X" % status);
283    success = __check_command_complete_event(transport, idx, trace) and (status == 0);
284    if success:
285        showLEFeatures(features, trace);
286
287    return success;
288
289"""
290    HCI/CCO/BV-07-C [BR/EDR Commands Not Supported on LE Device]
291"""
292def hci_cco_bv_07_c(transport, idx, trace):
293
294    status = inquire(transport, idx, toArray(0x9E8B00, 3), 1, 1, 100);
295    trace.trace(6, "Inquire Command returns status: 0x%02X" % status);
296    success = status == 1; # Unknown HCI Command (0x01)
297    event = get_event(transport, idx, 100);
298    success = success and (event.isCommandStatus() or event.isCommandComplete());
299    trace.trace(7, str(event));
300
301    return success;
302
303"""
304    HCI/CCO/BV-09-C [Handling LE Set Data Length Command]
305
306    Note: Requires that CONFIG_BT_CTLR_DATA_LENGTH_MAX=60 is set in the prj.conf file for the ptt_app.
307"""
308def hci_cco_bv_09_c(transport, upperTester, lowerTester, trace):
309
310    ownAddress = Address( ExtendedAddressType.PUBLIC );
311    peerAddress = Address( SimpleAddressType.PUBLIC, 0x123456789ABC );
312    advertiser = Advertiser(transport, lowerTester, trace, AdvertiseChannel.ALL_CHANNELS, Advertising.CONNECTABLE_UNDIRECTED, \
313                            ownAddress, peerAddress, AdvertisingFilterPolicy.FILTER_NONE);
314    advertiser.responseData = [ 0x04, 0x09 ] + [ ord(char) for char in "IUT" ];
315    initiatorAddress = Address( ExtendedAddressType.PUBLIC );
316    initiator = Initiator(transport, upperTester, lowerTester, trace, initiatorAddress, Address( ExtendedAddressType.PUBLIC, 0x456789ABCDEF ));
317    success = advertiser.enable();
318
319    connected = initiator.connect();
320    success = success and connected;
321
322    if connected:
323        TxOctets, TxTime = 60, 592;
324        status, handle = le_set_data_length(transport, upperTester, initiator.handles[0], TxOctets, TxTime, 100);
325        trace.trace(6, "LE Set Data Length Command returns status: 0x%02X handle: 0x%04X" % (status, handle));
326        success = success and __check_command_complete_event(transport, upperTester, trace) and (status == 0);
327        """
328            If parameters have changed - both upper- and lower-Tester will receive a LE Data Length Change event
329        """
330        if has_event(transport, upperTester, 200)[0]:
331            event = get_event(transport, upperTester, 100);
332            success = success and (event.subEvent == MetaEvents.BT_HCI_EVT_LE_DATA_LEN_CHANGE);
333            trace.trace(7, str(event));
334
335        if has_event(transport, lowerTester, 200)[0]:
336            event = get_event(transport, lowerTester, 100);
337            success = success and (event.subEvent == MetaEvents.BT_HCI_EVT_LE_DATA_LEN_CHANGE);
338            trace.trace(7, str(event));
339        """
340            Note: Disconnect can generate another LE Data Length Change event...
341        """
342        success = success and initiator.disconnect(0x13);
343
344    else:
345        advertiser.disable();
346
347    return success;
348
349"""
350    HCI/CCO/BV-10-C [Handling LE Read Suggested Default Data Length Command]
351"""
352def hci_cco_bv_10_c(transport, idx, trace):
353
354    status, maxTxOctets, maxTxTime = le_read_suggested_default_data_length(transport, idx, 100);
355    trace.trace(6, "LE Read Suggested Default Data Length Command returns status: 0x%02X" % status);
356    success = __check_command_complete_event(transport, idx, trace) and (status == 0);
357
358    trace.trace(6, "Maximum number of transmitted payload octets: 0x%04X (%d)" % (maxTxOctets, maxTxOctets));
359    trace.trace(6, "Maximum packet transmission time: 0x%04X (%d) microseconds" % (maxTxTime, maxTxTime));
360
361    return success;
362
363"""
364    HCI/CCO/BV-11-C [Handling LE Write Suggested Default Data Length Command]
365"""
366def hci_cco_bv_11_c(transport, idx, trace):
367
368    maxTxOctetsIn, maxTxTimeIn = (0x001B + 0x00FB)//2, (0x0148 + 0x4290)//2;
369    status = le_write_suggested_default_data_length(transport, idx, maxTxOctetsIn, maxTxTimeIn, 100);
370    trace.trace(6, "LE Write Suggested Default Data Length Command returns status: 0x%02X" % status);
371    success = __check_command_complete_event(transport, idx, trace) and (status == 0);
372
373    trace.trace(6, "Maximum number of transmitted payload octets: 0x%04X (%d)" % (maxTxOctetsIn, maxTxOctetsIn));
374    trace.trace(6, "Maximum packet transmission time: 0x%04X (%d) microseconds" % (maxTxTimeIn, maxTxTimeIn));
375
376    status, maxTxOctetsOut, maxTxTimeOut = le_read_suggested_default_data_length(transport, idx, 100);
377    trace.trace(6, "LE Read Suggested Default Data Length Command returns status: 0x%02X" % status);
378    success = success and __check_command_complete_event(transport, idx, trace) and (status == 0);
379
380    trace.trace(6, "Maximum number of transmitted payload octets: 0x%04X (%d)" % (maxTxOctetsOut, maxTxOctetsOut));
381    trace.trace(6, "Maximum packet transmission time: 0x%04X (%d) microseconds" % (maxTxTimeOut, maxTxTimeOut));
382
383    success = success and (maxTxOctetsOut == maxTxOctetsIn) and (maxTxTimeOut == maxTxTimeIn);
384
385    return success;
386
387"""
388    HCI/CCO/BV-12-C [Handling LE Remove Device From Resolving List Command]
389"""
390def hci_cco_bv_12_c(transport, idx, trace):
391
392    peerAddress = Address(SimpleAddressType.PUBLIC, 0x123456789ABC);
393    status = le_add_device_to_resolving_list(transport, idx, peerAddress.type, peerAddress.address, lowerIRK, upperIRK, 100);
394    trace.trace(6, "LE Add Device to Resolving List Command returns status: 0x%02X" % status);
395    success = __check_command_complete_event(transport, idx, trace) and (status == 0);
396
397    status = le_remove_device_from_resolving_list(transport, idx, peerAddress.type, peerAddress.address, 100);
398    trace.trace(6, "LE Remove Device from Resolving List Command returns status: 0x%02X" % status);
399    success = success and __check_command_complete_event(transport, idx, trace) and (status == 0);
400
401    return success;
402
403"""
404    HCI/CCO/BV-13-C [Handling LE Clear Resolving List Command]
405"""
406def hci_cco_bv_13_c(transport, idx, trace):
407
408    peerAddress = Address(SimpleAddressType.PUBLIC, 0x456789ABCDEF);
409    status = le_add_device_to_resolving_list(transport, idx, peerAddress.type, peerAddress.address, lowerIRK, upperIRK, 100);
410    trace.trace(6, "LE Add Device to Resolving List Command returns status: 0x%02X" % status);
411    success = __check_command_complete_event(transport, idx, trace) and (status == 0);
412
413    status = le_clear_resolving_list(transport, idx, 100);
414    trace.trace(6, "LE Clear Resolving List Command returns status: 0x%02X" % status);
415    success = success and __check_command_complete_event(transport, idx, trace) and (status == 0);
416
417    return success;
418
419"""
420    HCI/CCO/BV-14-C [Handling LE Read Resolving List Size Command]
421"""
422def hci_cco_bv_14_c(transport, idx, trace):
423
424    status, listSize = le_read_resolving_list_size(transport, idx, 100);
425    trace.trace(6, "LE Read Resolving List Size Command returns status: 0x%02X" % status);
426    success = __check_command_complete_event(transport, idx, trace) and (status == 0) and (listSize > 0);
427    trace.trace(6, "Resolving List Size returned: %d" % listSize);
428
429    return success;
430
431"""
432    HCI/CCO/BV-15-C [Handling LE Set Default PHY Command]
433"""
434def hci_cco_bv_15_c(transport, idx, trace):
435
436    status = le_set_default_phy(transport, idx, 3, 0, 0, 100);
437    trace.trace(6, "LE Set Default PHY Command returns status: 0x%02X" % status);
438    success = __check_command_complete_event(transport, idx, trace) and (status == 0);
439
440    return success;
441
442"""
443    HCI/CCO/BV-16-C [Handling LE Read Periodic Advertiser List Size Command]
444"""
445def hci_cco_bv_16_c(transport, idx, trace):
446
447    status, listSize = le_read_periodic_advertiser_list_size(transport, idx, 100);
448    trace.trace(6, "LE Read Periodic Advertiser List Size Command returns status: 0x%02X" % status);
449    success = __check_command_complete_event(transport, idx, trace) and (status == 0) and (listSize > 0);
450    trace.trace(6, "Periodic Advertiser List Size returned: %d" % listSize);
451
452    return success;
453
454"""
455    HCI/CCO/BV-17-C [Handling Add, Remove and Clear Periodic Advertiser List Commands]
456"""
457def hci_cco_bv_17_c(transport, idx, trace):
458
459    status = le_clear_periodic_advertiser_list(transport, idx, 100);
460    trace.trace(6, "LE Clear Periodic Advertiser List Command returns status: 0x%02X" % status);
461    success = __check_command_complete_event(transport, idx, trace) and (status == 0);
462
463    peerAddress = Address(SimpleAddressType.PUBLIC, 0x123456789ABC);
464    status = le_add_device_to_periodic_advertiser_list(transport, idx, peerAddress.type, peerAddress.address, 1, 100);
465    trace.trace(6, "LE Add Device to Periodic Advertiser List Command returns status: 0x%02X" % status);
466    success = success and __check_command_complete_event(transport, idx, trace) and (status == 0);
467
468    status = le_remove_device_from_periodic_advertiser_list(transport, idx, peerAddress.type, peerAddress.address, 1, 100);
469    trace.trace(6, "LE Remove Device from Periodic Advertiser List Command returns status: 0x%02X" % status);
470    success = success and __check_command_complete_event(transport, idx, trace) and (status == 0);
471
472    status = le_remove_device_from_periodic_advertiser_list(transport, idx, peerAddress.type, peerAddress.address, 1, 100);
473    trace.trace(6, "LE Remove Device from Periodic Advertiser List Command returns status: 0x%02X" % status);
474    success = success and __check_command_complete_event(transport, idx, trace) and (status == 0x42);
475
476    status = le_add_device_to_periodic_advertiser_list(transport, idx, peerAddress.type, peerAddress.address, 1, 100);
477    trace.trace(6, "LE Add Device to Periodic Advertiser List Command returns status: 0x%02X" % status);
478    success = success and __check_command_complete_event(transport, idx, trace) and (status == 0);
479
480    status = le_clear_periodic_advertiser_list(transport, idx, 100);
481    trace.trace(6, "LE Clear Periodic Advertiser List Command returns status: 0x%02X" % status);
482    success = success and __check_command_complete_event(transport, idx, trace) and (status == 0);
483
484    return success;
485
486"""
487    HCI/CCO/BV-18-C [Handling LE Read Transmit Power Command]
488"""
489def hci_cco_bv_18_c(transport, idx, trace):
490
491    status, minTxPower, maxTxPower = le_read_transmit_power(transport, idx, 100);
492    trace.trace(6, "LE Read Transmit Power Command returns status: 0x%02X" % status);
493    success = __check_command_complete_event(transport, idx, trace) and (status == 0);
494    success = success and (-127 <= minTxPower) and (minTxPower <= 126) and (-127 <= maxTxPower) and (maxTxPower <= 126) and (minTxPower <= maxTxPower);
495    trace.trace(6, "LE Read Transmit Power Command returned range: [%d, %d] dBm." % (minTxPower, maxTxPower));
496
497    return success;
498
499"""
500    HCI/DDI/BV-03-C [Disable Advertising with Set Advertising Enable Command]
501"""
502def hci_ddi_bv_03_c(transport, upperTester, lowerTester, trace):
503
504    ownAddress = Address( SimpleAddressType.PUBLIC );
505    peerAddress = Address( SimpleAddressType.PUBLIC, 0x456789ABCDEF );
506    advertiser = Advertiser(transport, upperTester, trace, AdvertiseChannel.ALL_CHANNELS, Advertising.CONNECTABLE_UNDIRECTED, \
507                            ownAddress, peerAddress, AdvertisingFilterPolicy.FILTER_NONE);
508    advertiser.responseData = [ 0x04, 0x09 ] + [ ord(char) for char in "IUT" ];
509    ownAddress = Address( SimpleAddressType.PUBLIC );
510    scanner = Scanner(transport, lowerTester, trace, ScanType.PASSIVE, AdvertisingReport.ADV_IND, ownAddress, ScanningFilterPolicy.FILTER_NONE, 5);
511
512    success = advertiser.enable();
513
514    success = success and scanner.enable();
515    scanner.monitor();
516    success = success and scanner.disable();
517    success = success and scanner.qualifyReports( 5 );
518
519    success = success and advertiser.disable();
520    success = success and scanner.enable();
521    scanner.monitor();
522    success = success and scanner.disable();
523    success = success and not scanner.qualifyReports( 1 );
524
525    return success;
526
527"""
528    HCI/DDI/BV-04-C [Disable Scanning with Set Scan Enable Command]
529"""
530def hci_ddi_bv_04_c(transport, upperTester, lowerTester, trace):
531
532    ownAddress = Address( SimpleAddressType.PUBLIC );
533    peerAddress = Address( SimpleAddressType.PUBLIC, 0x123456789ABC );
534    advertiser = Advertiser(transport, lowerTester, trace, AdvertiseChannel.ALL_CHANNELS, Advertising.CONNECTABLE_UNDIRECTED, \
535                            ownAddress, peerAddress, AdvertisingFilterPolicy.FILTER_NONE);
536    advertiser.responseData = [ 0x04, 0x09 ] + [ ord(char) for char in "IUT" ];
537    ownAddress = Address( SimpleAddressType.PUBLIC );
538    scanner = Scanner(transport, upperTester, trace, ScanType.PASSIVE, AdvertisingReport.ADV_IND, ownAddress, ScanningFilterPolicy.FILTER_NONE, 5);
539
540    success = advertiser.enable();
541
542    success = success and scanner.enable();
543    scanner.monitor();
544    success = success and scanner.disable();
545    success = success and scanner.qualifyReports( 5 );
546
547    scanner.monitor();
548    success = success and not scanner.qualifyReports( 1 );
549
550    success = success and advertiser.disable();
551
552    return success;
553
554"""
555    HCI/DDI/BI-02-C [Rejecting invalid Advertising Parameters]
556"""
557def hci_ddi_bi_02_c(transport, upperTester, trace):
558
559    ownAddress = Address( SimpleAddressType.PUBLIC );
560    peerAddress = Address( SimpleAddressType.PUBLIC, 0x456789ABCDEF );
561    advertiser = Advertiser(transport, upperTester, trace, AdvertiseChannel.ALL_CHANNELS, Advertising.NON_CONNECTABLE_UNDIRECTED, \
562                            ownAddress, peerAddress, AdvertisingFilterPolicy.FILTER_NONE);
563    advertiser.responseData = [ 0x04, 0x09 ] + [ ord(char) for char in "IUT" ];
564
565    advertiser.minInterval, advertiser.maxInterval = 32-2, 32-1;
566
567    successA = not advertiser.enable();
568    success = successA and (advertiser.status == 0x12);
569
570    if not successA:
571        advertiser.disable();
572
573    return success;
574
575"""
576    HCI/DDI/BI-63-C [Reject Set Extended Advertising Data Command, Data Too Long, LE 1M PHY]
577"""
578def hci_ddi_bi_63_c(transport, upperTester, lowerTester, trace):
579
580    Handle          = 0;
581    Properties      = 0;
582    PrimMinInterval = toArray(0x0140, 3); # Minimum Advertise Interval = 320 x 0.625 ms = 200.00 ms
583    PrimMaxInterval = toArray(0x0140, 3); # Maximum Advertise Interval = 320 x 0.625 ms = 200.00 ms
584    PrimChannelMap  = 0x07;  # Advertise on all three channels (#37, #38 and #39)
585    OwnAddrType     = SimpleAddressType.PUBLIC;
586    PeerAddrType    = 0;
587    PeerAddress     = toArray(0, 6);
588    FilterPolicy    = AdvertisingFilterPolicy.FILTER_NONE;
589    TxPower         = 0;
590    PrimAdvPhy      = PhysicalChannel.LE_1M; # Primary advertisement PHY is LE 1M
591    SecAdvMaxSkip   = 0;     # AUX_ADV_IND shall be sent prior to the next advertising event
592    SecAdvPhy       = PhysicalChannel.LE_1M;
593    Sid             = 0;
594    ScanReqNotifyEnable = 0; # Scan request notifications disabled
595
596    success = preamble_ext_advertising_parameters_set(transport, upperTester, Handle, Properties, PrimMinInterval, PrimMaxInterval, \
597                                                      PrimChannelMap, OwnAddrType, PeerAddrType, PeerAddress, FilterPolicy, TxPower, \
598                                                      PrimAdvPhy, SecAdvMaxSkip, SecAdvPhy, Sid, ScanReqNotifyEnable, trace);
599
600    if not success:
601        return False;
602
603    # Get maximum advertising data size
604    status, maxADSize = le_read_maximum_advertising_data_length(transport, upperTester, 100);
605    if status != 0:
606        return False
607
608    FragPref = 0; # The Controller may fragment all Host advertising data
609
610    # Set fragments of advertising data until we hit maxADSize - 1
611    fragmentCount = 7;
612    fragmentSize = math.ceil((maxADSize-1)/(fragmentCount));
613    fragmentData = random.randint(0, 256, fragmentSize);
614
615    count = 0;
616    while (count < fragmentCount):
617
618        op = FragmentOperation.FIRST_FRAGMENT
619        if (count > 0):
620            op = FragmentOperation.INTERMEDIATE_FRAGMENT;
621            if count == fragmentCount - 1:
622                # Adjust size of last fragment to hit maxADSize - 1 exactly
623                fragmentData = fragmentData[:(maxADSize - 1 - fragmentSize*6)]
624
625        status = le_set_extended_advertising_data(transport, upperTester, Handle, op, FragPref, fragmentData, 100);
626        if status != 0:
627            return False;
628
629        count += 1;
630
631    # Now setting another fragment of two bytes should fail
632    status = le_set_extended_advertising_data(transport, upperTester, Handle, FragmentOperation.INTERMEDIATE_FRAGMENT, FragPref, random.randint(0, 256, 2), 100);
633    return status == 0x07; # Memory Capacity Exceeded expected
634
635"""
636    HCI/DDI/BI-65-C [Reject Set Extended Scan Response Data Command, Data Too Long, LE 1M PHY]
637"""
638def hci_ddi_bi_65_c(transport, upperTester, lowerTester, trace):
639
640    Handle          = 0;
641    Properties      = 0x02; # Scannable
642    PrimMinInterval = toArray(0x0140, 3); # Minimum Advertise Interval = 320 x 0.625 ms = 200.00 ms
643    PrimMaxInterval = toArray(0x0140, 3); # Maximum Advertise Interval = 320 x 0.625 ms = 200.00 ms
644    PrimChannelMap  = 0x07;  # Advertise on all three channels (#37, #38 and #39)
645    OwnAddrType     = SimpleAddressType.PUBLIC;
646    PeerAddrType    = 0;
647    PeerAddress     = toArray(0, 6);
648    FilterPolicy    = AdvertisingFilterPolicy.FILTER_NONE;
649    TxPower         = 0;
650    PrimAdvPhy      = PhysicalChannel.LE_1M; # Primary advertisement PHY is LE 1M
651    SecAdvMaxSkip   = 0;     # AUX_ADV_IND shall be sent prior to the next advertising event
652    SecAdvPhy       = PhysicalChannel.LE_1M;
653    Sid             = 0;
654    ScanReqNotifyEnable = 0; # Scan request notifications disabled
655
656    success = preamble_ext_advertising_parameters_set(transport, upperTester, Handle, Properties, PrimMinInterval, PrimMaxInterval, \
657                                                      PrimChannelMap, OwnAddrType, PeerAddrType, PeerAddress, FilterPolicy, TxPower, \
658                                                      PrimAdvPhy, SecAdvMaxSkip, SecAdvPhy, Sid, ScanReqNotifyEnable, trace);
659
660    if not success:
661        return False;
662
663    # Get maximum advertising data size
664    status, maxADSize = le_read_maximum_advertising_data_length(transport, upperTester, 100);
665    if status != 0:
666        return False;
667
668    FragPref = 0; # The Controller may fragment all Host advertising data
669
670    # Set fragments of advertising data until we hit maxADSize - 1
671    fragmentCount = 7;
672    fragmentSize = math.ceil((maxADSize-1)/(fragmentCount));
673    fragmentData = random.randint(0, 256, fragmentSize);
674
675    count = 0;
676    while (count < fragmentCount):
677
678        op = FragmentOperation.FIRST_FRAGMENT
679        if (count > 0):
680            op = FragmentOperation.INTERMEDIATE_FRAGMENT;
681            if count == fragmentCount - 1:
682                # Adjust size of last fragment to hit maxADSize - 1 exactly
683                fragmentData = fragmentData[:(maxADSize - 1 - fragmentSize*6)]
684
685        status = le_set_extended_scan_response_data(transport, upperTester, Handle, op, FragPref, fragmentData, 100);
686        if status != 0:
687            return False;
688
689        count += 1;
690
691    # Now setting another fragment of two bytes should fail
692    status = le_set_extended_scan_response_data(transport, upperTester, Handle, FragmentOperation.INTERMEDIATE_FRAGMENT, FragPref, random.randint(0, 256, 2), 100);
693    return status == 0x07; # Memory Capacity Exceeded expected
694
695"""
696    HCI/HFC/BV-04-C [Events enabled by LE Set Event Mask Command]
697"""
698def hci_hfc_bv_04_c(transport, upperTester, lowerTester, trace):
699
700    """ Bit:   5  4  4  3  2  1  0  0
701               6  8  0  2  4  6  8  0
702            0x20 00 00 00 00 00 80 10 ~ Bits 4, 15, 61 (Disconnection Complete Event, Hardware Error Event, LE Meta Event)
703    """
704    events = [0x10, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20];
705
706    status = set_event_mask(transport, upperTester, events, 100);
707    trace.trace(6, "Set Event Mask Command returns status: 0x%02X" % status);
708    success = __check_command_complete_event(transport, upperTester, trace) and (status == 0);
709
710    """ Bit:  5  4  4  3  2  1  0  0
711              6  8  0  2  4  6  8  0
712           0x00 00 00 00 00 07 FF FD ~ All except 'LE Channel Selection Algorithm Event and LE Advertising Report Event'
713    """
714    events = [0xFD, 0xFF, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00];
715
716    status = le_set_event_mask(transport, upperTester, events, 100);
717    trace.trace(6, "LE Set Event Mask Command returns status: 0x%02X" % status);
718    success = success and __check_command_complete_event(transport, upperTester, trace) and (status == 0);
719
720    """
721    status = le_set_event_mask(transport, lowerTester, events, 100);
722    trace.trace(6, "LE Set Event Mask Command returns status: 0x%02X" % status);
723    success = success and __check_command_complete_event(transport, lowerTester, trace) and (status == 0);
724    """
725
726    ownAddress = Address( SimpleAddressType.PUBLIC );
727    peerAddress = Address( SimpleAddressType.PUBLIC, 0x123456789ABC );
728    advertiser = Advertiser(transport, lowerTester, trace, AdvertiseChannel.ALL_CHANNELS, Advertising.CONNECTABLE_UNDIRECTED, \
729                            ownAddress, peerAddress, AdvertisingFilterPolicy.FILTER_NONE);
730    advertiser.responseData = [ 0x04, 0x09 ] + [ ord(char) for char in "IUT" ];
731    ownAddress = Address( SimpleAddressType.PUBLIC );
732    scanner = Scanner(transport, upperTester, trace, ScanType.ACTIVE, AdvertisingReport.ADV_IND, ownAddress, ScanningFilterPolicy.FILTER_NONE, 5, 5);
733    initiatorAddress = Address( ExtendedAddressType.PUBLIC );
734    initiator = Initiator(transport, upperTester, lowerTester, trace, initiatorAddress, Address( ExtendedAddressType.PUBLIC, 0x456789ABCDEF ));
735
736    success = advertiser.enable();
737
738    success = success and scanner.enable();
739    scanner.monitor();
740    success = success and scanner.disable();
741    success = success and not scanner.qualifyResponses( 5 );
742    success = success and not scanner.qualifyReports( 5 );
743
744    transport.wait(100);
745
746    connected = initiator.connect();
747    success = success and connected;
748
749    transport.wait(500);
750
751    if connected:
752        success = success and initiator.disconnect(0x13);
753
754    return success;
755
756"""
757    HCI/CM/BV-01-C [Handling LE Read Peer Resolvable Address Command]
758"""
759def hci_cm_bv_01_c(transport, upperTester, lowerTester, trace):
760
761    """
762        Add Public address of lowerTester and upperTester to the Resolving List
763    """
764    RPAs = [ ResolvableAddresses( transport, upperTester, trace, upperIRK ), ResolvableAddresses( transport, lowerTester, trace, lowerIRK ) ];
765    ownAddress = Address( SimpleAddressType.PUBLIC, 0x123456789ABC );
766    peerAddress = Address( SimpleAddressType.PUBLIC, 0x456789ABCDEF );
767    success = RPAs[upperTester].clear() and RPAs[lowerTester].clear();
768    success = success and RPAs[upperTester].add( peerAddress, lowerIRK );
769    success = success and RPAs[lowerTester].add( ownAddress, upperIRK );
770
771    """
772        Set resolvable private address timeout in seconds ( sixty seconds )
773    """
774    success = success and RPAs[upperTester].timeout(60) and RPAs[lowerTester].timeout(60);
775    success = success and RPAs[upperTester].enable() and RPAs[lowerTester].enable();
776
777    for iutRole in [ Role.CENTRAL, Role.PERIPHERAL ]:
778        ownAddress = Address( ExtendedAddressType.RESOLVABLE_OR_PUBLIC, 0x456789ABCDEF if iutRole is Role.CENTRAL else 0x123456789ABC);
779        peerAddress = Address( SimpleAddressType.PUBLIC, 0x123456789ABC if iutRole is Role.CENTRAL else 0x456789ABCDEF);
780        if iutRole == Role.CENTRAL:
781            advertiser = Advertiser(transport, lowerTester, trace, AdvertiseChannel.ALL_CHANNELS, Advertising.CONNECTABLE_LDC_DIRECTED, ownAddress, peerAddress);
782        else:
783            advertiser = Advertiser(transport, upperTester, trace, AdvertiseChannel.ALL_CHANNELS, Advertising.CONNECTABLE_LDC_DIRECTED, ownAddress, peerAddress);
784        advertiser.responseData = [ 0x04, 0x09 ] + [ ord(char) for char in "IUT" ];
785
786        initiatorAddress = Address( ExtendedAddressType.RESOLVABLE_OR_PUBLIC );
787        if iutRole == Role.CENTRAL:
788            initiator = Initiator(transport, upperTester, lowerTester, trace, initiatorAddress, Address( IdentityAddressType.PUBLIC_IDENTITY, toNumber(ownAddress.address) ));
789        else:
790            initiator = Initiator(transport, lowerTester, upperTester, trace, initiatorAddress, Address( IdentityAddressType.PUBLIC_IDENTITY, toNumber(ownAddress.address) ));
791        success = success and advertiser.enable();
792
793        connected = initiator.connect();
794        success = success and connected;
795
796        peerAddress = Address( SimpleAddressType.PUBLIC, 0x456789ABCDEF );
797        status, RPA = le_read_peer_resolvable_address(transport, upperTester, peerAddress.type, peerAddress.address, 100);
798        trace.trace(6, "LE Read Peer Resolvable Address Command returns status: 0x%02X RPA: %s" % (status, formatAddress(RPA)));
799        success = success and __check_command_complete_event(transport, upperTester, trace) and (status == 0);
800
801        if iutRole == Role.CENTRAL:
802            success = success and (initiator.peerRPA() == RPA);
803            if initiator.peerRPA() != RPA:
804                print((initiator.peerRPA()));
805                print(RPA);
806                trace.trace(5, "Expected: %s Received: %s" % (Address(None, initiator.peerRPA()), Address(None, RPA)));
807        else:
808            success = success and (initiator.localRPA() == RPA);
809            if initiator.localRPA() != RPA:
810                trace.trace(5, "Expected: %s Received: %s" % (Address(None, initiator.localRPA()), Address(None, RPA)));
811
812        transport.wait(200);
813
814        if connected:
815            connected = not initiator.disconnect(0x13);
816            success = success and not connected;
817
818    return success;
819
820"""
821    HCI/CM/BV-02-C [Handling LE Read Local Resolvable Address Command]
822"""
823def hci_cm_bv_02_c(transport, upperTester, lowerTester, trace):
824
825    """
826        Add Public address of lowerTester and upperTester to the Resolving List
827    """
828    RPAs = [ ResolvableAddresses( transport, upperTester, trace, upperIRK ), ResolvableAddresses( transport, lowerTester, trace, lowerIRK ) ];
829    ownAddress = Address( SimpleAddressType.PUBLIC, 0x123456789ABC );
830    peerAddress = Address( SimpleAddressType.PUBLIC, 0x456789ABCDEF );
831    success = RPAs[upperTester].clear() and RPAs[lowerTester].clear();
832    success = success and RPAs[upperTester].add( peerAddress, lowerIRK );
833    success = success and RPAs[lowerTester].add( ownAddress, upperIRK );
834
835    """
836        Set resolvable private address timeout in seconds ( sixty seconds )
837    """
838    success = success and RPAs[upperTester].timeout(60) and RPAs[lowerTester].timeout(60);
839    success = success and RPAs[upperTester].enable() and RPAs[lowerTester].enable();
840
841    for iutRole in [ Role.CENTRAL, Role.PERIPHERAL ]:
842        ownAddress = Address( ExtendedAddressType.RESOLVABLE_OR_PUBLIC, 0x456789ABCDEF if iutRole is Role.CENTRAL else 0x123456789ABC);
843        peerAddress = Address( SimpleAddressType.PUBLIC, 0x123456789ABC if iutRole is Role.CENTRAL else 0x456789ABCDEF);
844        if iutRole == Role.CENTRAL:
845            advertiser = Advertiser(transport, lowerTester, trace, AdvertiseChannel.ALL_CHANNELS, Advertising.CONNECTABLE_LDC_DIRECTED, ownAddress, peerAddress);
846        else:
847            advertiser = Advertiser(transport, upperTester, trace, AdvertiseChannel.ALL_CHANNELS, Advertising.CONNECTABLE_LDC_DIRECTED, ownAddress, peerAddress);
848        advertiser.responseData = [ 0x04, 0x09 ] + [ ord(char) for char in "IUT" ];
849
850        initiatorAddress = Address( ExtendedAddressType.RESOLVABLE_OR_PUBLIC );
851        if iutRole == Role.CENTRAL:
852            initiator = Initiator(transport, upperTester, lowerTester, trace, initiatorAddress, Address( IdentityAddressType.PUBLIC_IDENTITY, toNumber(ownAddress.address) ));
853        else:
854            initiator = Initiator(transport, lowerTester, upperTester, trace, initiatorAddress, Address( IdentityAddressType.PUBLIC_IDENTITY, toNumber(ownAddress.address) ));
855        success = success and advertiser.enable();
856
857        connected = initiator.connect();
858        success = success and connected;
859
860        peerAddress = Address( SimpleAddressType.PUBLIC, 0x456789ABCDEF );
861        status, RPA = le_read_local_resolvable_address(transport, upperTester, peerAddress.type, peerAddress.address, 100);
862        trace.trace(6, "LE Read Local Resolvable Address Command returns status: 0x%02X RPA: %s" % (status, formatAddress(RPA)));
863        success = success and __check_command_complete_event(transport, upperTester, trace) and (status == 0);
864
865        if iutRole == Role.CENTRAL:
866            success = success and (initiator.localRPA() == RPA);
867        else:
868            success = success and (initiator.peerRPA() == RPA);
869
870        transport.wait(200);
871
872        if connected:
873            connected = not initiator.disconnect(0x13);
874            success = success and not connected;
875
876    return success;
877
878"""
879    HCI/CM/BV-03-C [Handling LE Read PHY Command]
880"""
881def hci_cm_bv_03_c(transport, upperTester, lowerTester, trace):
882
883    ownAddress = Address( ExtendedAddressType.PUBLIC );
884    peerAddress = Address( SimpleAddressType.PUBLIC, 0x123456789ABC );
885    advertiser = Advertiser(transport, lowerTester, trace, AdvertiseChannel.ALL_CHANNELS, Advertising.CONNECTABLE_UNDIRECTED, \
886                            ownAddress, peerAddress, AdvertisingFilterPolicy.FILTER_NONE);
887    advertiser.responseData = [ 0x04, 0x09 ] + [ ord(char) for char in "IUT" ];
888    initiatorAddress = Address( ExtendedAddressType.PUBLIC );
889    initiator = Initiator(transport, upperTester, lowerTester, trace, initiatorAddress, Address( ExtendedAddressType.PUBLIC, 0x456789ABCDEF ));
890    success = advertiser.enable();
891
892    connected = initiator.connect();
893    success = success and connected;
894
895    if success:
896        status, handle, TxPhy, RxPhy = le_read_phy(transport, upperTester, initiator.handles[0], 100);
897        trace.trace(6, "LE Read PHY Command returns status: 0x%02X handle: 0x%04X TxPHY: %d RxPHY: %d" % (status, handle, TxPhy, RxPhy));
898        success = success and __check_command_complete_event(transport, upperTester, trace) and (status == 0);
899
900    if connected:
901        connected = not initiator.disconnect(0x13);
902        success = success and not connected;
903
904    return success;
905
906"""
907    HCI/DSU/BV-02-C [Reset Command received in Advertising State]
908"""
909def hci_dsu_bv_02_c(transport, upperTester, lowerTester, trace):
910
911    ownAddress = Address( SimpleAddressType.PUBLIC );
912    peerAddress = Address( SimpleAddressType.PUBLIC, 0x456789ABCDEF );
913    advertiser = Advertiser(transport, upperTester, trace, AdvertiseChannel.ALL_CHANNELS, Advertising.CONNECTABLE_UNDIRECTED, \
914                            ownAddress, peerAddress, AdvertisingFilterPolicy.FILTER_NONE);
915    advertiser.responseData = [ 0x04, 0x09 ] + [ ord(char) for char in "IUT" ];
916    ownAddress = Address( SimpleAddressType.PUBLIC );
917    scanner = Scanner(transport, lowerTester, trace, ScanType.PASSIVE, AdvertisingReport.ADV_IND, ownAddress, ScanningFilterPolicy.FILTER_NONE, 5);
918
919    success = advertiser.enable();
920
921    success = success and scanner.enable();
922    scanner.monitor();
923    success = success and scanner.disable();
924    success = success and scanner.qualifyReports( 5 );
925
926    status = reset(transport, upperTester, 100);
927    trace.trace(6, "Reset Command returns status: 0x%02X" % status);
928    success = success and __check_command_complete_event(transport, upperTester, trace) and (status == 0);
929
930    """
931        Verify that the IUT has stopped Advertising
932    """
933    success = success and scanner.enable();
934    scanner.monitor();
935    success = success and scanner.disable();
936    success = success and not scanner.qualifyReports( 5 );
937
938    return success;
939
940"""
941    HCI/DSU/BV-03-C [Reset Command received in Peripheral Role]
942"""
943def hci_dsu_bv_03_c(transport, upperTester, lowerTester, trace):
944
945    ownAddress = Address( ExtendedAddressType.PUBLIC );
946    peerAddress = Address( SimpleAddressType.PUBLIC, 0x456789ABCDEF );
947    advertiser = Advertiser(transport, upperTester, trace, AdvertiseChannel.ALL_CHANNELS, Advertising.CONNECTABLE_UNDIRECTED, \
948                            ownAddress, peerAddress, AdvertisingFilterPolicy.FILTER_NONE);
949    advertiser.responseData = [ 0x04, 0x09 ] + [ ord(char) for char in "IUT" ];
950    initiatorAddress = Address( ExtendedAddressType.PUBLIC );
951    initiator = Initiator(transport, lowerTester, upperTester, trace, initiatorAddress, Address( ExtendedAddressType.PUBLIC, 0x123456789ABC ));
952    success = advertiser.enable();
953
954    success = success and initiator.connect();
955
956    transport.wait(200);
957
958    status = reset(transport, upperTester, 100);
959    trace.trace(6, "Reset Command returns status: 0x%02X" % status);
960    success = success and __check_command_complete_event(transport, upperTester, trace) and (status == 0);
961
962    """
963       There might be pending disconnect events lying around...
964    """
965    while has_event(transport, lowerTester, 200)[0]:
966        event = get_event(transport, lowerTester, 100);
967        trace.trace(7, str(event));
968        if event.event == Events.BT_HCI_EVT_DISCONN_COMPLETE:
969            status, handle, reason = event.decode();
970            success = success and (reason == 0x08); # Connection Timeout
971
972    while has_event(transport, upperTester, 200)[0]:
973        event = get_event(transport, upperTester, 100);
974        trace.trace(7, str(event));
975        if event.event == Events.BT_HCI_EVT_DISCONN_COMPLETE:
976            status, handle, reason = event.decode();
977            success = success and (reason == 0x08); # Connection Timeout
978
979    return success;
980
981"""
982    HCI/DSU/BV-04-C [Reset Command received in Scanning State]
983"""
984def hci_dsu_bv_04_c(transport, upperTester, lowerTester, trace):
985
986    ownAddress = Address( SimpleAddressType.PUBLIC );
987    peerAddress = Address( SimpleAddressType.PUBLIC, 0x123456789ABC );
988    advertiser = Advertiser(transport, lowerTester, trace, AdvertiseChannel.ALL_CHANNELS, Advertising.CONNECTABLE_UNDIRECTED, \
989                            ownAddress, peerAddress, AdvertisingFilterPolicy.FILTER_NONE);
990    advertiser.responseData = [ 0x04, 0x09 ] + [ ord(char) for char in "IUT" ];
991    ownAddress = Address( SimpleAddressType.PUBLIC );
992    scanner = Scanner(transport, upperTester, trace, ScanType.PASSIVE, AdvertisingReport.ADV_IND, ownAddress, ScanningFilterPolicy.FILTER_NONE, 5);
993
994    success = advertiser.enable();
995
996    success = success and scanner.enable();
997    scanner.monitor();
998    success = success and scanner.disable();
999    success = success and scanner.qualifyReports( 5 );
1000
1001    status = reset(transport, upperTester, 100);
1002    trace.trace(6, "Reset Command returns status: 0x%02X" % status);
1003    success = success and __check_command_complete_event(transport, upperTester, trace) and (status == 0);
1004
1005    """
1006        Verify that the IUT has stopped Advertising
1007    """
1008    success = success and scanner.enable();
1009    scanner.monitor();
1010    success = success and scanner.disable();
1011    success = success and not scanner.qualifyReports( 5 );
1012
1013    return success;
1014
1015"""
1016    HCI/DSU/BV-05-C [Reset Command received in Initiating State]
1017"""
1018def hci_dsu_bv_05_c(transport, upperTester, lowerTester, trace):
1019
1020    ownAddress = Address( ExtendedAddressType.PUBLIC );
1021    peerAddress = Address( SimpleAddressType.PUBLIC, 0x123456789ABC );
1022    advertiser = Advertiser(transport, lowerTester, trace, AdvertiseChannel.ALL_CHANNELS, Advertising.CONNECTABLE_UNDIRECTED, \
1023                            ownAddress, peerAddress, AdvertisingFilterPolicy.FILTER_NONE);
1024    advertiser.responseData = [ 0x04, 0x09 ] + [ ord(char) for char in "IUT" ];
1025    initiatorAddress = Address( ExtendedAddressType.PUBLIC );
1026    initiator = Initiator(transport, upperTester, lowerTester, trace, initiatorAddress, Address( ExtendedAddressType.PUBLIC, 0x456789ABCDEF ));
1027
1028    success = initiator.preConnect();
1029
1030    status = reset(transport, upperTester, 100);
1031    trace.trace(6, "Reset Command returns status: 0x%02X" % status);
1032    success = success and __check_command_complete_event(transport, upperTester, trace) and (status == 0);
1033
1034    success = success and advertiser.enable();
1035    success = success and not initiator.postConnect();
1036    success = success and advertiser.disable();
1037
1038    return success;
1039
1040"""
1041    HCI/DSU/BV-06-C [Reset Command received in Central Role]
1042"""
1043def hci_dsu_bv_06_c(transport, upperTester, lowerTester, trace):
1044
1045    ownAddress = Address( ExtendedAddressType.PUBLIC );
1046    peerAddress = Address( SimpleAddressType.PUBLIC, 0x123456789ABC );
1047    advertiser = Advertiser(transport, lowerTester, trace, AdvertiseChannel.ALL_CHANNELS, Advertising.CONNECTABLE_UNDIRECTED, \
1048                            ownAddress, peerAddress, AdvertisingFilterPolicy.FILTER_NONE);
1049    advertiser.responseData = [ 0x04, 0x09 ] + [ ord(char) for char in "IUT" ];
1050    initiatorAddress = Address( ExtendedAddressType.PUBLIC );
1051    initiator = Initiator(transport, upperTester, lowerTester, trace, initiatorAddress, Address( ExtendedAddressType.PUBLIC, 0x456789ABCDEF ));
1052    success = advertiser.enable();
1053
1054    success = success and initiator.connect();
1055
1056    transport.wait(200);
1057
1058    status = reset(transport, upperTester, 100);
1059    trace.trace(6, "Reset Command returns status: 0x%02X" % status);
1060    success = success and __check_command_complete_event(transport, upperTester, trace) and (status == 0);
1061
1062    return success;
1063
1064__tests__ = {
1065    "HCI/CCO/BV-07-C": [ hci_cco_bv_07_c, 'BR/EDR Commands Not Supported on LE Device' ],
1066    "HCI/CCO/BV-09-C": [ hci_cco_bv_09_c, 'Handling LE Set Data Length Command' ],
1067    "HCI/CCO/BV-10-C": [ hci_cco_bv_10_c, 'Handling LE Read Suggested Default Data Length Command' ],
1068    "HCI/CCO/BV-11-C": [ hci_cco_bv_11_c, 'Handling LE Write Suggested Default Data Length Command' ],
1069    "HCI/CCO/BV-12-C": [ hci_cco_bv_12_c, 'Handling LE Remove Device From Resolving List Command' ],
1070    "HCI/CCO/BV-13-C": [ hci_cco_bv_13_c, 'Handling LE Clear Resolving List Command' ],
1071    "HCI/CCO/BV-14-C": [ hci_cco_bv_14_c, 'Handling LE Read Resolving List Size Command' ],
1072    "HCI/CCO/BV-15-C": [ hci_cco_bv_15_c, 'Handling LE Set Default PHY Command' ],
1073#   "HCI/CCO/BV-16-C": [ hci_cco_bv_17_c, 'Handling LE Read Periodic Advertiser List Size Command' ],
1074#   "HCI/CCO/BV-17-C": [ hci_cco_bv_17_c, 'Handling Add, Remove and Clear Periodic Advertiser List Commands' ],
1075    "HCI/CCO/BV-18-C": [ hci_cco_bv_18_c, 'Handling LE Read Transmit Power Command' ],
1076    "HCI/CFC/BV-02-C": [ hci_cfc_bv_02_c, 'Reported Buffer Size' ],
1077    "HCI/CIN/BV-01-C": [ hci_cin_bv_01_c, 'Features returned by Read Local Supported Features Command' ],
1078    "HCI/CIN/BV-03-C": [ hci_cin_bv_03_c, 'Supported Commands returned by Read Local Supported Commands Command' ],
1079    "HCI/CIN/BV-04-C": [ hci_cin_bv_04_c, 'Versions returned by Read Local Version Information Command' ],
1080    "HCI/CIN/BV-06-C": [ hci_cin_bv_06_c, 'Reported Filter Accept List Size' ],
1081    "HCI/CIN/BV-09-C": [ hci_cin_bv_09_c, 'Feature Bits returned by Read LE Public Key Validation Feature Bit' ],
1082    "HCI/CM/BV-01-C":  [ hci_cm_bv_01_c,  'Handling LE Read Peer Resolvable Address Command' ],
1083    "HCI/CM/BV-02-C":  [ hci_cm_bv_02_c,  'Handling LE Read Local Resolvable Address Command' ],
1084    "HCI/CM/BV-03-C":  [ hci_cm_bv_03_c,  'Handling LE Read PHY Command' ],
1085    "HCI/DDI/BI-02-C": [ hci_ddi_bi_02_c, 'Rejecting invalid Advertising Parameters' ],
1086    "HCI/DDI/BI-63-C": [ hci_ddi_bi_63_c, 'Reject Set Extended Advertising Data Command, Data Too Long, LE 1M PHY' ],
1087    "HCI/DDI/BI-65-C": [ hci_ddi_bi_65_c, 'Reject Set Extended Scan Response Data Command, Data Too Long, LE 1M PHY' ],
1088    "HCI/DDI/BV-03-C": [ hci_ddi_bv_03_c, 'Disable Advertising with Set Advertising Enable Command' ],
1089    "HCI/DDI/BV-04-C": [ hci_ddi_bv_04_c, 'Disable Scanning with Set Scan Enable Command' ],
1090    "HCI/DSU/BV-02-C": [ hci_dsu_bv_02_c, 'Reset Command received in Advertising State' ],
1091    "HCI/DSU/BV-03-C": [ hci_dsu_bv_03_c, 'Reset Command received in Peripheral Role' ],
1092    "HCI/DSU/BV-04-C": [ hci_dsu_bv_04_c, 'Reset Command received in Scanning State' ],
1093    "HCI/DSU/BV-05-C": [ hci_dsu_bv_05_c, 'Reset Command received in Initiating State' ],
1094    "HCI/DSU/BV-06-C": [ hci_dsu_bv_06_c, 'Reset Command received in Central Role' ],
1095    "HCI/GEV/BV-01-C": [ hci_gev_bv_01_c, 'Status return for Unsupported Commands' ],
1096    "HCI/HFC/BV-04-C": [ hci_hfc_bv_04_c, 'Events enabled by LE Set Event Mask Command' ]
1097};
1098
1099_maxNameLength = max([ len(key) for key in __tests__ ]);
1100
1101_spec = { key: TestSpec(name = key, number_devices = 2, description = "#[" + __tests__[key][1] + "]", test_private = __tests__[key][0]) for key in __tests__ };
1102
1103"""
1104    Return the test spec which contains info about all the tests
1105    this test module provides
1106"""
1107def get_tests_specs():
1108    return _spec;
1109
1110def preamble(transport, trace):
1111    global lowerIRK, upperIRK, lowerRandomAddress, upperRandomAddress;
1112
1113    ok = success = preamble_standby(transport, 0, trace);
1114    trace.trace(4, "preamble Standby " + ("PASS" if success else "FAIL"));
1115    success = preamble_standby(transport, 1, trace);
1116    ok = ok and success;
1117    trace.trace(4, "preamble Standby " + ("PASS" if success else "FAIL"));
1118    success, upperIRK, upperRandomAddress = preamble_device_address_set(transport, 0, trace);
1119    trace.trace(4, "preamble Device Address Set " + ("PASS" if success else "FAIL"));
1120    ok = ok and success;
1121    success, lowerIRK, lowerRandomAddress = preamble_device_address_set(transport, 1, trace);
1122    trace.trace(4, "preamble Device Address Set " + ("PASS" if success else "FAIL"));
1123    return ok and success;
1124
1125"""
1126    Run a test given its test_spec
1127"""
1128def run_a_test(args, transport, trace, test_spec, device_dumps):
1129    try:
1130        success = preamble(transport, trace);
1131    except Exception as e:
1132        trace.trace(3, "Preamble generated exception: %s" % str(e));
1133        success = False;
1134
1135    trace.trace(2, "%-*s %s test started..." % (_maxNameLength, test_spec.name, test_spec.description[1:]));
1136    test_f = test_spec.test_private;
1137    try:
1138        if test_f.__code__.co_argcount > 4:
1139            success = success and test_f(transport, 0, 1, trace, device_dumps);
1140        elif test_f.__code__.co_argcount > 3:
1141            success = success and test_f(transport, 0, 1, trace);
1142        else:
1143            success = success and test_f(transport, 0, trace);
1144    except Exception as e:
1145        import traceback
1146        traceback.print_exc()
1147        trace.trace(3, "Test generated exception: %s" % str(e));
1148        success = False;
1149
1150    return not success
1151