wiliot-certificate 1.5.2a1__py3-none-any.whl → 4.4.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- brg_certificate/ag/energous_v0_defines.py +105 -114
- brg_certificate/ag/energous_v1_defines.py +105 -114
- brg_certificate/ag/energous_v2_defines.py +105 -114
- brg_certificate/ag/energous_v3_defines.py +105 -114
- brg_certificate/ag/energous_v4_defines.py +105 -114
- brg_certificate/ag/fanstel_lan_v0_defines.py +105 -114
- brg_certificate/ag/fanstel_lte_v0_defines.py +105 -114
- brg_certificate/ag/fanstel_wifi_v0_defines.py +105 -114
- brg_certificate/ag/minew_lte_v0_defines.py +105 -114
- brg_certificate/ag/wlt_types.html +983 -150
- brg_certificate/ag/wlt_types_ag.py +1326 -248
- brg_certificate/ag/wlt_types_ag_jsons/brg2brg_ota.json +69 -0
- brg_certificate/ag/wlt_types_ag_jsons/brg2gw_hb.json +101 -0
- brg_certificate/ag/wlt_types_ag_jsons/brg2gw_hb_sleep.json +45 -0
- brg_certificate/ag/wlt_types_ag_jsons/calibration.json +75 -0
- brg_certificate/ag/wlt_types_ag_jsons/custom.json +99 -0
- brg_certificate/ag/wlt_types_ag_jsons/datapath.json +133 -8
- brg_certificate/ag/wlt_types_ag_jsons/energy2400.json +99 -0
- brg_certificate/ag/wlt_types_ag_jsons/energySub1g.json +96 -0
- brg_certificate/ag/wlt_types_ag_jsons/externalSensor.json +113 -0
- brg_certificate/ag/wlt_types_ag_jsons/interface.json +157 -0
- brg_certificate/ag/wlt_types_ag_jsons/powerManagement.json +205 -0
- brg_certificate/cert_common.py +61 -11
- brg_certificate/cert_config.py +12 -7
- brg_certificate/cert_utils.py +3 -1
- brg_certificate/certificate_bcc_test_list.txt +0 -2
- brg_certificate/certificate_test_list.txt +4 -4
- brg_certificate/tests/calibration/interval_test/interval_test.json +1 -1
- brg_certificate/tests/calibration/interval_test/interval_test.py +5 -5
- brg_certificate/tests/calibration/output_power_test/output_power_test.json +1 -1
- brg_certificate/tests/calibration/output_power_test/output_power_test.py +5 -5
- brg_certificate/tests/calibration/pattern_test/pattern_test.json +1 -1
- brg_certificate/tests/calibration/pattern_test/pattern_test.py +16 -10
- brg_certificate/tests/datapath/aging_test/aging_test.py +10 -9
- brg_certificate/tests/datapath/num_of_tags_test/num_of_tags_test.py +8 -13
- brg_certificate/tests/datapath/output_power_test/output_power_test.json +1 -1
- brg_certificate/tests/datapath/output_power_test/output_power_test.py +5 -5
- brg_certificate/tests/datapath/pacer_interval_ble5_test/pacer_interval_ble5_test.json +1 -1
- brg_certificate/tests/datapath/pacer_interval_ble5_test/pacer_interval_ble5_test.py +11 -7
- brg_certificate/tests/datapath/pacer_interval_tags_count_test/pacer_interval_tags_count_test.py +11 -4
- brg_certificate/tests/datapath/pacer_interval_test/pacer_interval_test.py +10 -10
- brg_certificate/tests/datapath/pattern_test/pattern_test.json +1 -1
- brg_certificate/tests/datapath/pattern_test/pattern_test.py +5 -6
- brg_certificate/tests/datapath/pkt_filter_ble5_test/pkt_filter_ble5_test.json +1 -1
- brg_certificate/tests/datapath/pkt_filter_ble5_test/pkt_filter_ble5_test.py +10 -9
- brg_certificate/tests/datapath/pkt_filter_gen3_test/pkt_filter_gen3_test.json +1 -1
- brg_certificate/tests/datapath/pkt_filter_gen3_test/pkt_filter_gen3_test.py +11 -10
- brg_certificate/tests/datapath/pkt_filter_test/pkt_filter_test.json +1 -1
- brg_certificate/tests/datapath/pkt_filter_test/pkt_filter_test.py +11 -10
- brg_certificate/tests/datapath/rssi_threshold_test/rssi_threshold_test.json +1 -1
- brg_certificate/tests/datapath/rssi_threshold_test/rssi_threshold_test.py +11 -10
- brg_certificate/tests/datapath/rx_channel_test/rx_channel_test.json +1 -1
- brg_certificate/tests/datapath/rx_channel_test/rx_channel_test.py +5 -6
- brg_certificate/tests/datapath/rx_rate_gen2_test/rx_rate_gen2_test.py +39 -37
- brg_certificate/tests/datapath/rx_rate_gen3_test/rx_rate_gen3_test.py +46 -46
- brg_certificate/tests/datapath/stress_gen3_test/stress_gen3_test.json +2 -3
- brg_certificate/tests/datapath/stress_gen3_test/stress_gen3_test.py +21 -17
- brg_certificate/tests/datapath/stress_test/stress_test.json +2 -3
- brg_certificate/tests/datapath/stress_test/stress_test.py +20 -17
- brg_certificate/tests/datapath/tx_repetition_algo_test/tx_repetition_algo_test.py +1 -1
- brg_certificate/tests/datapath/tx_repetition_test/tx_repetition_test.json +1 -1
- brg_certificate/tests/datapath/tx_repetition_test/tx_repetition_test.py +12 -10
- brg_certificate/tests/edge_mgmt/actions_test/actions_test.json +1 -1
- brg_certificate/tests/edge_mgmt/actions_test/actions_test.py +13 -13
- brg_certificate/tests/edge_mgmt/brg2brg_ota_ble5_test/brg2brg_ota_ble5_test.py +1 -1
- brg_certificate/tests/edge_mgmt/leds_test/leds_test.py +2 -2
- brg_certificate/tests/energy2400/duty_cycle_test/duty_cycle_test.json +1 -1
- brg_certificate/tests/energy2400/duty_cycle_test/duty_cycle_test.py +5 -5
- brg_certificate/tests/energy2400/output_power_test/output_power_test.json +1 -1
- brg_certificate/tests/energy2400/output_power_test/output_power_test.py +5 -5
- brg_certificate/tests/energy2400/pattern_test/pattern_test.json +1 -1
- brg_certificate/tests/energy2400/pattern_test/pattern_test.py +5 -5
- brg_certificate/tests/energy2400/signal_indicator_ble5_10_250k_test/signal_indicator_ble5_10_250k_test.json +2 -2
- brg_certificate/tests/energy2400/signal_indicator_ble5_10_250k_test/signal_indicator_ble5_10_250k_test.py +256 -278
- brg_certificate/tests/energy2400/signal_indicator_ble5_10_500k_test/signal_indicator_ble5_10_500k_test.json +2 -2
- brg_certificate/tests/energy2400/signal_indicator_ble5_10_500k_test/signal_indicator_ble5_10_500k_test.py +256 -278
- brg_certificate/tests/energy2400/signal_indicator_sub1g_2_4_test/signal_indicator_sub1g_2_4_test.py +3 -3
- brg_certificate/tests/energy2400/signal_indicator_test/signal_indicator_test.py +30 -91
- brg_certificate/tests/energy_sub1g/duty_cycle_test/duty_cycle_test.json +1 -1
- brg_certificate/tests/energy_sub1g/duty_cycle_test/duty_cycle_test.py +5 -5
- brg_certificate/tests/energy_sub1g/pattern_test/pattern_test.json +1 -1
- brg_certificate/tests/energy_sub1g/pattern_test/pattern_test.py +5 -5
- brg_certificate/tests/energy_sub1g/signal_indicator_functionality_test/signal_indicator_functionality_test.py +2 -2
- brg_certificate/tests/energy_sub1g/signal_indicator_test/signal_indicator_test.json +1 -1
- brg_certificate/tests/energy_sub1g/signal_indicator_test/signal_indicator_test.py +5 -5
- brg_certificate/tests/pwr_mgmt/pwr_mgmt_test/pwr_mgmt_test.py +2 -2
- brg_certificate/tests/sensors/ext_sensor_test/ext_sensor_test.json +1 -1
- brg_certificate/tests/sensors/ext_sensor_test/ext_sensor_test.py +6 -7
- brg_certificate/wltPb_pb2.py +4 -4
- brg_certificate/wltPb_pb2.pyi +2 -1
- gw_certificate/api_if/gw_capabilities.py +37 -1
- gw_certificate/common/serialization_formatter.py +93 -0
- gw_certificate/common/wltPb_pb2.py +50 -38
- gw_certificate/common/wltPb_pb2.pyi +42 -35
- gw_certificate/gw_certificate.py +4 -2
- gw_certificate/gw_certificate_cli.py +5 -4
- gw_certificate/interface/4.4.91_app.zip +0 -0
- gw_certificate/interface/{4.4.52_sd_bl_app.zip → 4.4.91_sd_bl_app.zip} +0 -0
- gw_certificate/interface/ble_simulator.py +5 -3
- gw_certificate/interface/flash_fw.py +90 -0
- gw_certificate/interface/mqtt.py +39 -23
- gw_certificate/interface/pkt_generator.py +0 -44
- gw_certificate/interface/uart_if.py +25 -12
- gw_certificate/tests/actions.py +33 -5
- gw_certificate/tests/connection.py +3 -1
- gw_certificate/tests/downlink.py +2 -2
- gw_certificate/tests/generic.py +5 -4
- gw_certificate/tests/registration.py +4 -4
- gw_certificate/tests/static/generated_packet_table.py +47 -25
- gw_certificate/tests/static/packet_table.csv +10067 -10051
- gw_certificate/tests/static/uplink_defines.py +2 -1
- gw_certificate/tests/throughput.py +3 -2
- gw_certificate/tests/uplink.py +171 -32
- {wiliot_certificate-1.5.2a1.dist-info → wiliot_certificate-4.4.0.dist-info}/METADATA +71 -30
- {wiliot_certificate-1.5.2a1.dist-info → wiliot_certificate-4.4.0.dist-info}/RECORD +119 -117
- {wiliot_certificate-1.5.2a1.dist-info → wiliot_certificate-4.4.0.dist-info}/WHEEL +1 -1
- gw_certificate/interface/4.4.52_app.zip +0 -0
- {wiliot_certificate-1.5.2a1.dist-info → wiliot_certificate-4.4.0.dist-info}/entry_points.txt +0 -0
- {wiliot_certificate-1.5.2a1.dist-info → wiliot_certificate-4.4.0.dist-info}/licenses/LICENSE +0 -0
- {wiliot_certificate-1.5.2a1.dist-info → wiliot_certificate-4.4.0.dist-info}/top_level.txt +0 -0
|
@@ -2,12 +2,13 @@ from gw_certificate.interface.if_defines import *
|
|
|
2
2
|
from gw_certificate.ag.ut_defines import *
|
|
3
3
|
|
|
4
4
|
RECEIVED = 'received'
|
|
5
|
+
SHOULD_RECEIVE = 'shouldReceive'
|
|
5
6
|
SHARED_COLUMNS = [PAYLOAD]
|
|
6
7
|
INT64_COLUMNS = [RSSI]
|
|
7
8
|
OBJECT_COLUMNS = [PAYLOAD]
|
|
8
9
|
REPORT_COLUMNS = ['pkt_id', 'duplication', 'time_delay']
|
|
9
10
|
|
|
10
11
|
ADV_TIMESTAMP = 'adv_timestamp'
|
|
11
|
-
TS_DEVIATION =
|
|
12
|
+
TS_DEVIATION = 4500
|
|
12
13
|
TS_TOLERANCE = 2500
|
|
13
14
|
REC_TIMESTAMP = 'rec_timestamp'
|
|
@@ -134,6 +134,7 @@ class StressTestStage(GenericStressStage):
|
|
|
134
134
|
run_data = self.run_stress_data.data
|
|
135
135
|
end_time = datetime.datetime.now() + datetime.timedelta(seconds=TIME_PER_DELAY_FIRST if delay == STRESS_DEFAULT_DELAYS[0] else TIME_PER_DELAY)
|
|
136
136
|
last_sent_time = time.perf_counter_ns()
|
|
137
|
+
debug_print('Advertising packets...')
|
|
137
138
|
for index, row in run_data.iterrows():
|
|
138
139
|
if datetime.datetime.now() > end_time:
|
|
139
140
|
debug_print(f"Timeout for PPS rate {int(ONE_SECOND_MS / delay)} reached")
|
|
@@ -142,7 +143,7 @@ class StressTestStage(GenericStressStage):
|
|
|
142
143
|
self.local_pkts.append(row[PAYLOAD])
|
|
143
144
|
while True:
|
|
144
145
|
if time.perf_counter_ns() - last_sent_time >= delay * 10**6:
|
|
145
|
-
self.ble_sim.send_packet(data, duplicates=self.duplicates, delay=0)
|
|
146
|
+
self.ble_sim.send_packet(data, duplicates=self.duplicates, delay=0, print_for_debug=False)
|
|
146
147
|
last_sent_time = time.perf_counter_ns()
|
|
147
148
|
break
|
|
148
149
|
self.ts_records_arr[delay_idx].set_adv_timestamp_current(data)
|
|
@@ -199,7 +200,7 @@ class StressTestStage(GenericStressStage):
|
|
|
199
200
|
for idx, delay in enumerate(self.delays):
|
|
200
201
|
if self.ts_records_arr[idx].is_ts_error():
|
|
201
202
|
self.add_to_stage_report(f"Timestamps errors during PPS {self.report_data[str(delay)]['pkts_per_sec_desired']}:")
|
|
202
|
-
self.ts_records_arr[idx].add_ts_errs_to_report(self)
|
|
203
|
+
self.ts_records_arr[idx].add_ts_errs_to_report(self, newline=False)
|
|
203
204
|
self.add_report_line_separator()
|
|
204
205
|
self.add_to_stage_report(f'Stage data saved - {self.csv_path}')
|
|
205
206
|
|
gw_certificate/tests/uplink.py
CHANGED
|
@@ -14,16 +14,18 @@ from gw_certificate.interface.if_defines import DEFAULT_DELAY, LOCATION
|
|
|
14
14
|
from gw_certificate.tests.static.uplink_defines import *
|
|
15
15
|
from gw_certificate.interface.mqtt import MqttClient, Serialization
|
|
16
16
|
from gw_certificate.interface.pkt_generator import BrgPktGenerator, apply_adva_bitmask
|
|
17
|
-
from gw_certificate.tests.static.generated_packet_table import UnifiedRunData, SensorRunData, MgmtRunData, PacketTableHelper
|
|
18
|
-
from gw_certificate.tests.generic import PassCriteria, PERFECT_SCORE, MINIMUM_SCORE, GenericTest, GenericStage, ERR_SUMMARY_DEFAULT
|
|
17
|
+
from gw_certificate.tests.static.generated_packet_table import UnifiedRunData, SensorRunData, MgmtRunData, PacketTableHelper, ACLRunData
|
|
18
|
+
from gw_certificate.tests.generic import PassCriteria, PERFECT_SCORE, MINIMUM_SCORE, GenericTest, GenericStage, ERR_SUMMARY_DEFAULT, INFORMATIVE
|
|
19
19
|
from gw_certificate.api_if.api_validation import MESSAGE_TYPES, validate_message
|
|
20
20
|
from gw_certificate.tests.static.generated_packet_table import CSV_NAME
|
|
21
|
+
from gw_certificate.common.serialization_formatter import ACL_MODE, ACL_BRIDGE_IDS, SerializationFormatter, Configurable, ACL_ALLOW, ACL_DENY
|
|
21
22
|
|
|
22
23
|
|
|
23
24
|
# HELPER DEFINES
|
|
24
25
|
TABLE_SUFFIX = "Table"
|
|
25
26
|
ERR_SUM_MISSING_PKTS = "Insufficient amount of packets were scanned & uploaded by the gateway. "
|
|
26
27
|
ERR_SUM_ONLY_1E = "Packets with length != '1E' were not uploaded. "
|
|
28
|
+
ACL_MODE_COUNT = 2
|
|
27
29
|
|
|
28
30
|
# HELPER FUNCTIONS
|
|
29
31
|
def process_payload(packet:dict):
|
|
@@ -106,21 +108,24 @@ class TimestampsHelper(PacketTableHelper):
|
|
|
106
108
|
|
|
107
109
|
packets_sent_df[REC_TIMESTAMP] = packets_sent_df.apply(validate_row, axis=1)
|
|
108
110
|
|
|
109
|
-
# Validate no 2 packets hold the same timestamp
|
|
110
|
-
if REC_TIMESTAMP in packets_sent_df.columns:
|
|
111
|
-
|
|
112
|
-
|
|
111
|
+
# # Validate no 2 packets hold the same timestamp - disabled, not a requirement for certification
|
|
112
|
+
# if REC_TIMESTAMP in packets_sent_df.columns:
|
|
113
|
+
# duplicates = packets_sent_df[REC_TIMESTAMP].value_counts()
|
|
114
|
+
# duplicated_ts = duplicates[duplicates > 1].index
|
|
113
115
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
116
|
+
# for ts in duplicated_ts:
|
|
117
|
+
# self.ts_errors.append(f"Multiple packets were uploaded with identical timestamp (ts = {int(ts)})")
|
|
118
|
+
# self.has_identical_ts = True
|
|
119
|
+
|
|
120
|
+
def add_ts_errs_to_report(self, stage:GenericStage, newline=True):
|
|
117
121
|
|
|
118
|
-
def add_ts_errs_to_report(self, stage:GenericStage):
|
|
119
122
|
for idx, ts_err in enumerate(self.ts_errors):
|
|
120
123
|
stage.add_to_stage_report(ts_err)
|
|
121
124
|
if idx == 1 and (len(self.ts_errors) - 1) > idx:
|
|
122
125
|
stage.add_to_stage_report(f'Additional errors ({len(self.ts_errors) - 1 - idx}) are suppressed to avoid clutter')
|
|
123
126
|
break
|
|
127
|
+
if len(self.ts_errors) > 0 and newline:
|
|
128
|
+
stage.add_to_stage_report('')
|
|
124
129
|
|
|
125
130
|
def is_ts_error(self) -> bool:
|
|
126
131
|
return len(self.ts_errors) > 0
|
|
@@ -203,6 +208,7 @@ class GenericUplinkStage(GenericStage):
|
|
|
203
208
|
if len(not_received) > 0:
|
|
204
209
|
self.add_to_stage_report('Packets not received:')
|
|
205
210
|
self.add_to_stage_report(tabulate.tabulate(not_received, headers='keys', showindex=False))
|
|
211
|
+
self.add_to_stage_report('')
|
|
206
212
|
|
|
207
213
|
self.ts_records.add_ts_errs_to_report(self)
|
|
208
214
|
|
|
@@ -221,6 +227,9 @@ class GenericUplinkStage(GenericStage):
|
|
|
221
227
|
|
|
222
228
|
return self.report
|
|
223
229
|
|
|
230
|
+
def swap_endianness(self, hex_str: str) -> str:
|
|
231
|
+
return ''.join(format(b, '02X') for b in bytes.fromhex(hex_str)[::-1])
|
|
232
|
+
|
|
224
233
|
|
|
225
234
|
class ManagementPacketStage(GenericUplinkStage):
|
|
226
235
|
def __init__(self, **kwargs):
|
|
@@ -372,6 +381,7 @@ class SensorPacketStage(GenericUplinkStage):
|
|
|
372
381
|
if len(not_received) > 0:
|
|
373
382
|
self.add_to_stage_report('Packets not received:')
|
|
374
383
|
self.add_to_stage_report(tabulate.tabulate(not_received_rep_cols, headers='keys', showindex=False))
|
|
384
|
+
self.add_to_stage_report('')
|
|
375
385
|
|
|
376
386
|
def all_varying_len_sensors_missed(not_received_df):
|
|
377
387
|
not_uploaded_count = 0
|
|
@@ -548,22 +558,8 @@ class AliasBridgeIDStage(GenericUplinkStage):
|
|
|
548
558
|
all_payloads = uplink_tests_df[PAYLOAD]
|
|
549
559
|
self.all_test_payloads = all_payloads.tolist()
|
|
550
560
|
|
|
551
|
-
def _parser(row, desired:Literal['adva', 'without_adva']):
|
|
552
|
-
if desired == 'adva':
|
|
553
|
-
output_string = row.at[ADVA_PAYLOAD][:12]
|
|
554
|
-
elif desired == 'without_adva':
|
|
555
|
-
output_string = row.at[ADVA_PAYLOAD][12:]
|
|
556
|
-
else:
|
|
557
|
-
raise ValueError
|
|
558
|
-
return output_string
|
|
559
|
-
|
|
560
561
|
# Create data set for alias bridge verification
|
|
561
|
-
alias_bridge_id_df = uplink_tests_df.copy()
|
|
562
|
-
# Take the adva from the payload
|
|
563
|
-
alias_bridge_id_df['alias_bridge_id'] = alias_bridge_id_df['adva']
|
|
564
|
-
# Convert bridge_id to little endian
|
|
565
|
-
alias_bridge_id_df['alias_bridge_id'] = alias_bridge_id_df['alias_bridge_id'].apply(lambda x: ''.join(format(byte, '02X') for byte in bytes.fromhex(x)[::-1]))
|
|
566
|
-
self.alias_bridge_id_df = alias_bridge_id_df
|
|
562
|
+
self.alias_bridge_id_df = uplink_tests_df.copy()
|
|
567
563
|
|
|
568
564
|
def generate_stage_report(self, **kwargs):
|
|
569
565
|
report = []
|
|
@@ -580,7 +576,7 @@ class AliasBridgeIDStage(GenericUplinkStage):
|
|
|
580
576
|
if any(payload in test_payload for test_payload in self.all_test_payloads):
|
|
581
577
|
filtered_pkts.append(pkt)
|
|
582
578
|
message['packets'] = filtered_pkts
|
|
583
|
-
|
|
579
|
+
|
|
584
580
|
def is_alias_bridge_id_valid(message):
|
|
585
581
|
nonlocal aliasBridgeId_valid
|
|
586
582
|
packets = message['packets']
|
|
@@ -593,9 +589,10 @@ class AliasBridgeIDStage(GenericUplinkStage):
|
|
|
593
589
|
if len(validation_data) != 1:
|
|
594
590
|
debug_print(f"validation_data unexpected len:{len(validation_data)}, for payload:{pkt_payload}")
|
|
595
591
|
return
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
592
|
+
expected_bridge_id = validation_data.iloc[0]['adva']
|
|
593
|
+
expected_bridge_ids = [expected_bridge_id, self.swap_endianness(expected_bridge_id)]
|
|
594
|
+
if pkt_alias_bridge_id.upper() not in expected_bridge_ids:
|
|
595
|
+
report.append(f"Alias bridge ID of the packet does not match. Expected alias bridge IDs:{expected_bridge_ids} but the packet alias bridge ID is {pkt_alias_bridge_id}")
|
|
599
596
|
self.stage_pass = MINIMUM_SCORE
|
|
600
597
|
self.error_summary = "aliasBridgeId doesn't match the expected one of a packet. "
|
|
601
598
|
aliasBridgeId_valid = False
|
|
@@ -633,6 +630,7 @@ class GeolocationStage(GenericUplinkStage):
|
|
|
633
630
|
self.__dict__.update(kwargs)
|
|
634
631
|
super().__init__(**self.__dict__, stage_name=type(self).__name__)
|
|
635
632
|
self.graph_html_path = os.path.join(self.test_dir, f'{self.stage_name}.html')
|
|
633
|
+
self.result_indication = INFORMATIVE
|
|
636
634
|
|
|
637
635
|
|
|
638
636
|
def prepare_stage(self):
|
|
@@ -678,11 +676,150 @@ class GeolocationStage(GenericUplinkStage):
|
|
|
678
676
|
stage_report=self.report.split('\n'), graph = graph_div)
|
|
679
677
|
return self.report
|
|
680
678
|
|
|
679
|
+
class ACLStage(GenericUplinkStage):
|
|
680
|
+
def __init__(self, **kwargs):
|
|
681
|
+
self.stage_tooltip = "Configures the gateway's Access Control List and simulate bridges. Expects 100% discard rate"
|
|
682
|
+
self.__dict__.update(kwargs)
|
|
683
|
+
super().__init__(**self.__dict__, stage_name=type(self).__name__)
|
|
684
|
+
self.pass_min = 60
|
|
685
|
+
self.inconclusive_min = 50
|
|
686
|
+
self.run_data = ACLRunData().data
|
|
687
|
+
|
|
688
|
+
@property
|
|
689
|
+
def acl_modes(self):
|
|
690
|
+
return [ACL_ALLOW, ACL_DENY]
|
|
691
|
+
|
|
692
|
+
def run(self):
|
|
693
|
+
super().run()
|
|
694
|
+
|
|
695
|
+
def advertise_packets(pkts_group, adv_count, acl_brg_ids, mode):
|
|
696
|
+
acl_dict = {ACL_MODE: mode, ACL_BRIDGE_IDS: acl_brg_ids}
|
|
697
|
+
|
|
698
|
+
# Calculate row indices we want to advertise
|
|
699
|
+
df_packets_count = len(self.run_data) // adv_count
|
|
700
|
+
start_idx = df_packets_count * pkts_group
|
|
701
|
+
end_idx = df_packets_count * (pkts_group + 1)
|
|
702
|
+
|
|
703
|
+
for index, row in self.run_data.iloc[start_idx:end_idx].iterrows():
|
|
704
|
+
if mode == ACL_ALLOW:
|
|
705
|
+
should_be_received = row['bridge_id'] in acl_brg_ids
|
|
706
|
+
else:
|
|
707
|
+
should_be_received = row['bridge_id'] not in acl_brg_ids
|
|
708
|
+
data = row[ADVA_PAYLOAD]
|
|
709
|
+
self.local_pkts.append((row[PAYLOAD], row['duplication'], row['time_delay'], row['adva'], acl_dict, should_be_received))
|
|
710
|
+
self.ble_sim.send_packet(raw_packet=data, duplicates=row['duplication'], delay=row['time_delay'])
|
|
711
|
+
self.ts_records.set_adv_timestamp_current(data)
|
|
712
|
+
|
|
713
|
+
def configure_acl(mode, bridgeIds):
|
|
714
|
+
acl_dict = {ACL_MODE: mode, ACL_BRIDGE_IDS: bridgeIds}
|
|
715
|
+
ser_format = SerializationFormatter(self.mqttc.get_serialization())
|
|
716
|
+
payload = ser_format.cfg_param_set(self.cfg_data.status_msg_get(), Configurable.ACL.value, acl_dict)
|
|
717
|
+
self.mqttc.flush_messages_topic('status')
|
|
718
|
+
self.mqttc.send_payload(payload)
|
|
719
|
+
time.sleep(5 if self.aggregation_time == 0 else self.aggregation_time)
|
|
720
|
+
debug_print('Status message received from gw:')
|
|
721
|
+
gw_status = self.mqttc.get_status_message()
|
|
722
|
+
if gw_status != None and isinstance(gw_status, dict) and ser_format.is_pb():
|
|
723
|
+
gw_status = ser_format.pb_status_acl_bytes_to_hex_string(gw_status)
|
|
724
|
+
debug_print(gw_status)
|
|
725
|
+
|
|
726
|
+
# Configuring each bridge in ACL, once for each mode
|
|
727
|
+
brg_ids = self.run_data['bridge_id'].unique().tolist()
|
|
728
|
+
cfg_and_adv_loops = len(brg_ids) * len(self.acl_modes)
|
|
729
|
+
i = 0
|
|
730
|
+
for brg_id in brg_ids:
|
|
731
|
+
acl_brg_ids = [brg_id]
|
|
732
|
+
for mode in self.acl_modes:
|
|
733
|
+
configure_acl(mode, acl_brg_ids)
|
|
734
|
+
time.sleep(5 if self.aggregation_time == 0 else self.aggregation_time)
|
|
735
|
+
advertise_packets(i, cfg_and_adv_loops, acl_brg_ids, mode)
|
|
736
|
+
time.sleep(5 if self.aggregation_time == 0 else self.aggregation_time)
|
|
737
|
+
i += 1
|
|
738
|
+
|
|
739
|
+
configure_acl(ACL_DENY, [])
|
|
740
|
+
time.sleep(5)
|
|
741
|
+
|
|
742
|
+
def compare_local_mqtt(self):
|
|
743
|
+
self.fetch_mqtt_from_stage()
|
|
744
|
+
local_pkts_df = pd.DataFrame(self.local_pkts, columns=[PAYLOAD, 'duplication', 'time_delay', 'aliasBridgeId', 'ACL', SHOULD_RECEIVE])
|
|
745
|
+
mqtt_pkts_df = pd.DataFrame(self.mqtt_pkts)
|
|
746
|
+
comparison = local_pkts_df
|
|
747
|
+
|
|
748
|
+
if PAYLOAD not in mqtt_pkts_df.columns:
|
|
749
|
+
mqtt_pkts_df[PAYLOAD] = ''
|
|
750
|
+
received_pkts_df = pd.merge(local_pkts_df[PAYLOAD], mqtt_pkts_df[PAYLOAD], how='inner')
|
|
751
|
+
|
|
752
|
+
received_pkts = set(received_pkts_df[PAYLOAD])
|
|
753
|
+
|
|
754
|
+
self.pkts_received_count = pd.Series.count(received_pkts_df)
|
|
755
|
+
unique_received_count = len(received_pkts)
|
|
756
|
+
self.pkts_filtered_out_count = self.pkts_received_count - unique_received_count
|
|
757
|
+
|
|
758
|
+
comparison[RECEIVED] = comparison[PAYLOAD].isin(received_pkts)
|
|
759
|
+
self.comparison = comparison
|
|
760
|
+
|
|
761
|
+
def generate_stage_report(self):
|
|
762
|
+
self.compare_local_mqtt()
|
|
763
|
+
self.ts_records.validate_timestamps(self.mqtt_pkts)
|
|
764
|
+
self.add_report_header()
|
|
765
|
+
|
|
766
|
+
num_pkts_sent = len(self.comparison)
|
|
767
|
+
num_pkts_received = self.comparison[RECEIVED].eq(True).sum()
|
|
768
|
+
num_pkts_should_received = self.comparison[SHOULD_RECEIVE].eq(True).sum()
|
|
769
|
+
num_pkts_should_discard = self.comparison[SHOULD_RECEIVE].eq(False).sum()
|
|
770
|
+
num_pkts_discarded_correctly = (self.comparison[SHOULD_RECEIVE].eq(False) & self.comparison[RECEIVED].eq(False)).sum()
|
|
771
|
+
num_pkts_received_correctly = (self.comparison[SHOULD_RECEIVE].eq(True) & self.comparison[RECEIVED].eq(True)).sum()
|
|
772
|
+
num_pkts_failed_to_discard = (self.comparison[SHOULD_RECEIVE].eq(False) & self.comparison[RECEIVED].eq(True)).sum()
|
|
773
|
+
num_pkts_failed_to_receive = (self.comparison[SHOULD_RECEIVE].eq(True) & self.comparison[RECEIVED].eq(False)).sum()
|
|
774
|
+
self.add_to_stage_report(f"Total packets advertised: {num_pkts_sent}")
|
|
775
|
+
self.add_to_stage_report(f"Packets received / should've received: {num_pkts_received_correctly} / {num_pkts_should_received}")
|
|
776
|
+
self.add_to_stage_report(f"Packets discarded / should've discarded: {num_pkts_discarded_correctly} / {num_pkts_should_discard}")
|
|
777
|
+
self.add_to_stage_report(f"Failed to discard: {num_pkts_failed_to_discard}\n")
|
|
778
|
+
|
|
779
|
+
if num_pkts_failed_to_discard > 0:
|
|
780
|
+
self.stage_pass = MINIMUM_SCORE
|
|
781
|
+
self.error_summary = "Received packet/s that should've been discarded"
|
|
782
|
+
for index, row in self.comparison.iterrows():
|
|
783
|
+
if row[RECEIVED] == True and row[SHOULD_RECEIVE] == False:
|
|
784
|
+
self.add_to_stage_report(f"Payload from bridge {row['aliasBridgeId']} should have been filtered out: {row[PAYLOAD]}")
|
|
785
|
+
self.add_to_stage_report('')
|
|
786
|
+
# Report packets failed to receive only if we have issue discarding.
|
|
787
|
+
# Since it increase the likelyhood of bad logic, and not just missed packets
|
|
788
|
+
if num_pkts_failed_to_receive > 0:
|
|
789
|
+
for index, row in self.comparison.iterrows():
|
|
790
|
+
if row[RECEIVED] == False and row[SHOULD_RECEIVE] == True:
|
|
791
|
+
self.add_to_stage_report(f"Payload from bridge {row['aliasBridgeId']} wasn't received: {row[PAYLOAD]}")
|
|
792
|
+
self.add_to_stage_report('')
|
|
793
|
+
elif num_pkts_received == 0:
|
|
794
|
+
self.stage_pass = MINIMUM_SCORE
|
|
795
|
+
self.error_summary = "No packets received"
|
|
796
|
+
debug_print(f"No packets were received")
|
|
797
|
+
else:
|
|
798
|
+
self.stage_pass = num_pkts_received / num_pkts_should_received * PERFECT_SCORE
|
|
799
|
+
if self.stage_pass < self.pass_min:
|
|
800
|
+
self.add_to_stage_report(ERR_SUM_MISSING_PKTS)
|
|
801
|
+
self.error_summary = ERR_SUM_MISSING_PKTS
|
|
802
|
+
|
|
803
|
+
if num_pkts_received > 0:
|
|
804
|
+
self.add_report_topic_validation('data')
|
|
805
|
+
|
|
806
|
+
self.ts_records.add_ts_errs_to_report(self)
|
|
807
|
+
|
|
808
|
+
self.comparison.to_csv(self.csv_path)
|
|
809
|
+
self.add_report_line_separator()
|
|
810
|
+
self.add_to_stage_report(f'Stage data saved - {self.csv_path}')
|
|
811
|
+
debug_print(self.report)
|
|
812
|
+
|
|
813
|
+
# Generate HTML
|
|
814
|
+
self.report_html = self.template_engine.render_template('stage.html', stage=self,
|
|
815
|
+
stage_report=self.report.split('\n'))
|
|
816
|
+
|
|
817
|
+
return self.report
|
|
681
818
|
|
|
682
819
|
# TEST CLASS
|
|
683
|
-
TX_STAGES = [ManagementPacketStage, DataPacketStage, SensorPacketStage]
|
|
820
|
+
TX_STAGES = [ManagementPacketStage, DataPacketStage, SensorPacketStage, ACLStage]
|
|
684
821
|
UNCOUPLED_STAGES = [ManagementPacketStage, DataPacketStage, SensorPacketStage,
|
|
685
|
-
SequentialSequenceIdStage,
|
|
822
|
+
SequentialSequenceIdStage, GeolocationStage]
|
|
686
823
|
|
|
687
824
|
class UplinkTest(GenericTest):
|
|
688
825
|
def __init__(self, **kwargs):
|
|
@@ -695,7 +832,9 @@ class UplinkTest(GenericTest):
|
|
|
695
832
|
super().prepare_test()
|
|
696
833
|
stages = UNCOUPLED_STAGES
|
|
697
834
|
if self.mqttc.get_serialization() == Serialization.JSON:
|
|
698
|
-
stages
|
|
835
|
+
stages.append(ApiValidationStage)
|
|
836
|
+
if self.cfg_data.is_acl_supported():
|
|
837
|
+
stages.append(ACLStage)
|
|
699
838
|
# if self.gw_capabilities.geoLocationSupport:
|
|
700
839
|
# stages.append(GeolocationStage)
|
|
701
840
|
self.stages = [stage(**self.__dict__) for stage in stages]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: wiliot_certificate
|
|
3
|
-
Version:
|
|
3
|
+
Version: 4.4.0
|
|
4
4
|
Summary: A library for certifying Wiliot-compliant boards
|
|
5
5
|
Author-email: Wiliot <support@wiliot.com>
|
|
6
6
|
License: MIT License
|
|
@@ -52,24 +52,33 @@ Requires-Dist: reportlab>=4.3.1
|
|
|
52
52
|
Requires-Dist: google-api-python-client>=2.162.0
|
|
53
53
|
Dynamic: license-file
|
|
54
54
|
|
|
55
|
-
# wiliot-certificate
|
|
55
|
+
# wiliot-certificate Version 4.4.0
|
|
56
56
|
|
|
57
57
|
<!-- Description -->
|
|
58
|
-
wiliot-certificate is a
|
|
58
|
+
wiliot-certificate is a Python library that provides tools for testing and certifying boards for compatibility with Wiliot’s ecosystem.
|
|
59
59
|
This python package includes the following CLI utilities:
|
|
60
60
|
- Gateway Certificate (`wlt-cert-gw`)
|
|
61
61
|
- Bridge Certificate (`wlt-cert-brg`)
|
|
62
62
|
|
|
63
|
+
# Version:
|
|
64
|
+
wiliot-certificate versions 4.4.0 are compatible with firmware version 4.4.6 (ESP: 4.4.44, BLE: 4.4.93)
|
|
65
|
+
|
|
63
66
|
## Installing wiliot-certificate
|
|
67
|
+
Uninstall wiliot-deployment-tools if installed (relevant for old wlt-gw-certificate users):
|
|
68
|
+
````commandline
|
|
69
|
+
pip uninstall wiliot-deployment-tools
|
|
70
|
+
````
|
|
71
|
+
|
|
72
|
+
Install wiliot-certificate:
|
|
64
73
|
````commandline
|
|
65
74
|
pip install wiliot-certificate
|
|
66
75
|
````
|
|
67
76
|
|
|
68
77
|
## Using wiliot-certificate
|
|
69
78
|
### Gateway Certificate
|
|
70
|
-
Test Wiliot
|
|
71
|
-
The
|
|
72
|
-
To run the
|
|
79
|
+
Test Wiliot Gateway capabilities.
|
|
80
|
+
The Gateway Certificate includes different test that run sequentially to test each capability reported by the Gateway.
|
|
81
|
+
To run the Gateway Certificate the Gateway needs to use a public MQTT Broker (Eclipse):
|
|
73
82
|
|
|
74
83
|
Host: mqtt.eclipseprojects.io
|
|
75
84
|
TLS TCP Port: 8883
|
|
@@ -79,59 +88,91 @@ Websocket Port: 80
|
|
|
79
88
|
|
|
80
89
|
More information can be found at https://mqtt.eclipseprojects.io/.
|
|
81
90
|
|
|
82
|
-
####
|
|
91
|
+
#### Gateway Certificate Release Notes:
|
|
83
92
|
Release:
|
|
84
93
|
- Standalone wiliot-certificate package
|
|
85
94
|
- Python 3.13 support
|
|
86
|
-
-
|
|
95
|
+
- Gateway API version 205 support
|
|
87
96
|
- Registration test added
|
|
88
97
|
- Bridge OTA stage added under actions
|
|
89
98
|
- Aggregation flag supported by StressTest
|
|
90
99
|
- -update flag compatibility fix. Upgrades bootloader if needed
|
|
91
100
|
- -actions flag to select specific actions to test
|
|
101
|
+
- ACL (Access control list) test for gateways reporting API version 205 in the connection test
|
|
102
|
+
|
|
103
|
+
#### The following capabilities are not tested in this version
|
|
104
|
+
- Access control list stress stress
|
|
105
|
+
- Validation schema verification
|
|
106
|
+
- Board type registered within the Board Type Management system
|
|
107
|
+
- Bridge OTA progress reporting
|
|
108
|
+
|
|
92
109
|
|
|
93
110
|
```
|
|
94
|
-
|
|
111
|
+
Usage: wlt-cert-gw [-h] -owner OWNER -gw GW [-suffix SUFFIX] [-tests {connection,uplink,downlink,stress}]
|
|
95
112
|
|
|
96
113
|
Gateway Certificate - CLI Tool to test Wiliot GWs
|
|
97
114
|
|
|
98
|
-
|
|
115
|
+
Required arguments:
|
|
99
116
|
-gw GW Gateway ID
|
|
100
117
|
|
|
101
|
-
|
|
118
|
+
Optional arguments:
|
|
102
119
|
-owner OWNER Owner ID (Required for non-registration tests)
|
|
103
120
|
-tests Pick specific tests to run
|
|
104
121
|
-actions Pick specific actions to test during the ActionsTest
|
|
105
122
|
-update Update the firmware of the test board
|
|
106
123
|
-pps Pick specific PPS rate for the stress test
|
|
107
|
-
-agg
|
|
108
|
-
-suffix Allow for different suffixes after the
|
|
109
|
-
-env Wiliot
|
|
124
|
+
-agg Duration uplink stages wait before processing packets
|
|
125
|
+
-suffix Allow for different suffixes after the Gateway ID in MQTT topics
|
|
126
|
+
-env Wiliot environment for registration and bridgeOTA tests
|
|
110
127
|
-h, --help show this help message and exit
|
|
111
128
|
```
|
|
112
129
|
|
|
113
130
|
### Bridge Certificate
|
|
114
|
-
Test Wiliot
|
|
115
|
-
The
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
131
|
+
Test Wiliot Bridge capabilities.
|
|
132
|
+
The Bridge Certificate includes different tests that run sequentially to test each capability reported by the bridge.
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
# update Gateway sim version :
|
|
136
|
+
- Update your gateway and bridge using Wiliot's platform. (https://platform.wiliot.com/)
|
|
137
|
+
- Transfer the gateway to dev mode - run the following command: py ut\dev_mode.py --gw [GW] --enable
|
|
138
|
+
- Connect the gateway to your laptop via USB connection:
|
|
139
|
+
- Run the following: wlt-cert-brg --gw SIM --brg <XXXXXXXXXXXX> --port <COM_PORT>
|
|
140
|
+
- For other options of running, see the 'run example' section.
|
|
141
|
+
|
|
142
|
+
#### Bridge Certificate Release Notes:
|
|
143
|
+
Release
|
|
144
|
+
- First release of Bridge Certificate – includes validation tests for bridge functionality.
|
|
145
|
+
- Additional details are available in the JSON files.
|
|
146
|
+
|
|
147
|
+
# The following capabilities are not tested in this version
|
|
148
|
+
|
|
149
|
+
Power management
|
|
150
|
+
- Functionality of energize and transmit in sleep mode
|
|
151
|
+
Edge management
|
|
152
|
+
- Timing of heartbeat and interface packets
|
|
153
|
+
Module Energy 2400
|
|
154
|
+
- Functionality of energy pattern, output power and duty cycle
|
|
155
|
+
Module Energy SUB1G
|
|
156
|
+
- Functionality of energy pattern and duty cycle
|
|
157
|
+
Module Datapath
|
|
158
|
+
- RSSI edge cases: -127 and 0
|
|
159
|
+
- Functionality of transmission pattern, output power
|
|
160
|
+
- Pacer interval with channel 10 and 500k modulation
|
|
161
|
+
- Pacer interval using GEN3 Pixels
|
|
162
|
+
- Packet filter: the following configuration - DEBUG, TEMP & DEBUG, TEMPS & DEBUG & ADVANCE
|
|
163
|
+
- Rx rate feature with extended advertising
|
|
164
|
+
- Functionality of adaptive pacer algorithm
|
|
165
|
+
- Supported Pixels for extended advertising and GEN3
|
|
166
|
+
Calibration
|
|
167
|
+
- Functionality of output power and interval calibration
|
|
168
|
+
- Functionality of calibration transmission patterns for the configuration STANDARD & EU & DISABLE
|
|
125
169
|
|
|
126
|
-
#### BRG Certificate Release Notes:
|
|
127
|
-
1.3.0:
|
|
128
|
-
- FIRST VERSION
|
|
129
170
|
|
|
130
171
|
```
|
|
131
|
-
usage:
|
|
172
|
+
usage: wlt-cert-brg [-h] [--brg BRG] [--brg_cloud_connectivity BRG_CLOUD_CONNECTIVITY] [--brg1 BRG1] --gw GW [--data {tags,sim}] [--port PORT] [--clean] [--tl TL] [--run RUN]
|
|
132
173
|
[--drun DRUN] [--exit_on_test_failure] [--exit_on_param_failure] [--analyze_interference]
|
|
133
174
|
|
|
134
|
-
Bridge Certificate CLI
|
|
175
|
+
# Bridge Certificate CLI
|
|
135
176
|
|
|
136
177
|
options:
|
|
137
178
|
-h, --help show this help message and exit
|