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.
Files changed (120) hide show
  1. brg_certificate/ag/energous_v0_defines.py +105 -114
  2. brg_certificate/ag/energous_v1_defines.py +105 -114
  3. brg_certificate/ag/energous_v2_defines.py +105 -114
  4. brg_certificate/ag/energous_v3_defines.py +105 -114
  5. brg_certificate/ag/energous_v4_defines.py +105 -114
  6. brg_certificate/ag/fanstel_lan_v0_defines.py +105 -114
  7. brg_certificate/ag/fanstel_lte_v0_defines.py +105 -114
  8. brg_certificate/ag/fanstel_wifi_v0_defines.py +105 -114
  9. brg_certificate/ag/minew_lte_v0_defines.py +105 -114
  10. brg_certificate/ag/wlt_types.html +983 -150
  11. brg_certificate/ag/wlt_types_ag.py +1326 -248
  12. brg_certificate/ag/wlt_types_ag_jsons/brg2brg_ota.json +69 -0
  13. brg_certificate/ag/wlt_types_ag_jsons/brg2gw_hb.json +101 -0
  14. brg_certificate/ag/wlt_types_ag_jsons/brg2gw_hb_sleep.json +45 -0
  15. brg_certificate/ag/wlt_types_ag_jsons/calibration.json +75 -0
  16. brg_certificate/ag/wlt_types_ag_jsons/custom.json +99 -0
  17. brg_certificate/ag/wlt_types_ag_jsons/datapath.json +133 -8
  18. brg_certificate/ag/wlt_types_ag_jsons/energy2400.json +99 -0
  19. brg_certificate/ag/wlt_types_ag_jsons/energySub1g.json +96 -0
  20. brg_certificate/ag/wlt_types_ag_jsons/externalSensor.json +113 -0
  21. brg_certificate/ag/wlt_types_ag_jsons/interface.json +157 -0
  22. brg_certificate/ag/wlt_types_ag_jsons/powerManagement.json +205 -0
  23. brg_certificate/cert_common.py +61 -11
  24. brg_certificate/cert_config.py +12 -7
  25. brg_certificate/cert_utils.py +3 -1
  26. brg_certificate/certificate_bcc_test_list.txt +0 -2
  27. brg_certificate/certificate_test_list.txt +4 -4
  28. brg_certificate/tests/calibration/interval_test/interval_test.json +1 -1
  29. brg_certificate/tests/calibration/interval_test/interval_test.py +5 -5
  30. brg_certificate/tests/calibration/output_power_test/output_power_test.json +1 -1
  31. brg_certificate/tests/calibration/output_power_test/output_power_test.py +5 -5
  32. brg_certificate/tests/calibration/pattern_test/pattern_test.json +1 -1
  33. brg_certificate/tests/calibration/pattern_test/pattern_test.py +16 -10
  34. brg_certificate/tests/datapath/aging_test/aging_test.py +10 -9
  35. brg_certificate/tests/datapath/num_of_tags_test/num_of_tags_test.py +8 -13
  36. brg_certificate/tests/datapath/output_power_test/output_power_test.json +1 -1
  37. brg_certificate/tests/datapath/output_power_test/output_power_test.py +5 -5
  38. brg_certificate/tests/datapath/pacer_interval_ble5_test/pacer_interval_ble5_test.json +1 -1
  39. brg_certificate/tests/datapath/pacer_interval_ble5_test/pacer_interval_ble5_test.py +11 -7
  40. brg_certificate/tests/datapath/pacer_interval_tags_count_test/pacer_interval_tags_count_test.py +11 -4
  41. brg_certificate/tests/datapath/pacer_interval_test/pacer_interval_test.py +10 -10
  42. brg_certificate/tests/datapath/pattern_test/pattern_test.json +1 -1
  43. brg_certificate/tests/datapath/pattern_test/pattern_test.py +5 -6
  44. brg_certificate/tests/datapath/pkt_filter_ble5_test/pkt_filter_ble5_test.json +1 -1
  45. brg_certificate/tests/datapath/pkt_filter_ble5_test/pkt_filter_ble5_test.py +10 -9
  46. brg_certificate/tests/datapath/pkt_filter_gen3_test/pkt_filter_gen3_test.json +1 -1
  47. brg_certificate/tests/datapath/pkt_filter_gen3_test/pkt_filter_gen3_test.py +11 -10
  48. brg_certificate/tests/datapath/pkt_filter_test/pkt_filter_test.json +1 -1
  49. brg_certificate/tests/datapath/pkt_filter_test/pkt_filter_test.py +11 -10
  50. brg_certificate/tests/datapath/rssi_threshold_test/rssi_threshold_test.json +1 -1
  51. brg_certificate/tests/datapath/rssi_threshold_test/rssi_threshold_test.py +11 -10
  52. brg_certificate/tests/datapath/rx_channel_test/rx_channel_test.json +1 -1
  53. brg_certificate/tests/datapath/rx_channel_test/rx_channel_test.py +5 -6
  54. brg_certificate/tests/datapath/rx_rate_gen2_test/rx_rate_gen2_test.py +39 -37
  55. brg_certificate/tests/datapath/rx_rate_gen3_test/rx_rate_gen3_test.py +46 -46
  56. brg_certificate/tests/datapath/stress_gen3_test/stress_gen3_test.json +2 -3
  57. brg_certificate/tests/datapath/stress_gen3_test/stress_gen3_test.py +21 -17
  58. brg_certificate/tests/datapath/stress_test/stress_test.json +2 -3
  59. brg_certificate/tests/datapath/stress_test/stress_test.py +20 -17
  60. brg_certificate/tests/datapath/tx_repetition_algo_test/tx_repetition_algo_test.py +1 -1
  61. brg_certificate/tests/datapath/tx_repetition_test/tx_repetition_test.json +1 -1
  62. brg_certificate/tests/datapath/tx_repetition_test/tx_repetition_test.py +12 -10
  63. brg_certificate/tests/edge_mgmt/actions_test/actions_test.json +1 -1
  64. brg_certificate/tests/edge_mgmt/actions_test/actions_test.py +13 -13
  65. brg_certificate/tests/edge_mgmt/brg2brg_ota_ble5_test/brg2brg_ota_ble5_test.py +1 -1
  66. brg_certificate/tests/edge_mgmt/leds_test/leds_test.py +2 -2
  67. brg_certificate/tests/energy2400/duty_cycle_test/duty_cycle_test.json +1 -1
  68. brg_certificate/tests/energy2400/duty_cycle_test/duty_cycle_test.py +5 -5
  69. brg_certificate/tests/energy2400/output_power_test/output_power_test.json +1 -1
  70. brg_certificate/tests/energy2400/output_power_test/output_power_test.py +5 -5
  71. brg_certificate/tests/energy2400/pattern_test/pattern_test.json +1 -1
  72. brg_certificate/tests/energy2400/pattern_test/pattern_test.py +5 -5
  73. brg_certificate/tests/energy2400/signal_indicator_ble5_10_250k_test/signal_indicator_ble5_10_250k_test.json +2 -2
  74. brg_certificate/tests/energy2400/signal_indicator_ble5_10_250k_test/signal_indicator_ble5_10_250k_test.py +256 -278
  75. brg_certificate/tests/energy2400/signal_indicator_ble5_10_500k_test/signal_indicator_ble5_10_500k_test.json +2 -2
  76. brg_certificate/tests/energy2400/signal_indicator_ble5_10_500k_test/signal_indicator_ble5_10_500k_test.py +256 -278
  77. brg_certificate/tests/energy2400/signal_indicator_sub1g_2_4_test/signal_indicator_sub1g_2_4_test.py +3 -3
  78. brg_certificate/tests/energy2400/signal_indicator_test/signal_indicator_test.py +30 -91
  79. brg_certificate/tests/energy_sub1g/duty_cycle_test/duty_cycle_test.json +1 -1
  80. brg_certificate/tests/energy_sub1g/duty_cycle_test/duty_cycle_test.py +5 -5
  81. brg_certificate/tests/energy_sub1g/pattern_test/pattern_test.json +1 -1
  82. brg_certificate/tests/energy_sub1g/pattern_test/pattern_test.py +5 -5
  83. brg_certificate/tests/energy_sub1g/signal_indicator_functionality_test/signal_indicator_functionality_test.py +2 -2
  84. brg_certificate/tests/energy_sub1g/signal_indicator_test/signal_indicator_test.json +1 -1
  85. brg_certificate/tests/energy_sub1g/signal_indicator_test/signal_indicator_test.py +5 -5
  86. brg_certificate/tests/pwr_mgmt/pwr_mgmt_test/pwr_mgmt_test.py +2 -2
  87. brg_certificate/tests/sensors/ext_sensor_test/ext_sensor_test.json +1 -1
  88. brg_certificate/tests/sensors/ext_sensor_test/ext_sensor_test.py +6 -7
  89. brg_certificate/wltPb_pb2.py +4 -4
  90. brg_certificate/wltPb_pb2.pyi +2 -1
  91. gw_certificate/api_if/gw_capabilities.py +37 -1
  92. gw_certificate/common/serialization_formatter.py +93 -0
  93. gw_certificate/common/wltPb_pb2.py +50 -38
  94. gw_certificate/common/wltPb_pb2.pyi +42 -35
  95. gw_certificate/gw_certificate.py +4 -2
  96. gw_certificate/gw_certificate_cli.py +5 -4
  97. gw_certificate/interface/4.4.91_app.zip +0 -0
  98. gw_certificate/interface/{4.4.52_sd_bl_app.zip → 4.4.91_sd_bl_app.zip} +0 -0
  99. gw_certificate/interface/ble_simulator.py +5 -3
  100. gw_certificate/interface/flash_fw.py +90 -0
  101. gw_certificate/interface/mqtt.py +39 -23
  102. gw_certificate/interface/pkt_generator.py +0 -44
  103. gw_certificate/interface/uart_if.py +25 -12
  104. gw_certificate/tests/actions.py +33 -5
  105. gw_certificate/tests/connection.py +3 -1
  106. gw_certificate/tests/downlink.py +2 -2
  107. gw_certificate/tests/generic.py +5 -4
  108. gw_certificate/tests/registration.py +4 -4
  109. gw_certificate/tests/static/generated_packet_table.py +47 -25
  110. gw_certificate/tests/static/packet_table.csv +10067 -10051
  111. gw_certificate/tests/static/uplink_defines.py +2 -1
  112. gw_certificate/tests/throughput.py +3 -2
  113. gw_certificate/tests/uplink.py +171 -32
  114. {wiliot_certificate-1.5.2a1.dist-info → wiliot_certificate-4.4.0.dist-info}/METADATA +71 -30
  115. {wiliot_certificate-1.5.2a1.dist-info → wiliot_certificate-4.4.0.dist-info}/RECORD +119 -117
  116. {wiliot_certificate-1.5.2a1.dist-info → wiliot_certificate-4.4.0.dist-info}/WHEEL +1 -1
  117. gw_certificate/interface/4.4.52_app.zip +0 -0
  118. {wiliot_certificate-1.5.2a1.dist-info → wiliot_certificate-4.4.0.dist-info}/entry_points.txt +0 -0
  119. {wiliot_certificate-1.5.2a1.dist-info → wiliot_certificate-4.4.0.dist-info}/licenses/LICENSE +0 -0
  120. {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 = 1500
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
 
@@ -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
- duplicates = packets_sent_df[REC_TIMESTAMP].value_counts()
112
- duplicated_ts = duplicates[duplicates > 1].index
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
- for ts in duplicated_ts:
115
- self.ts_errors.append(f"Multiple packets were uploaded with identical timestamp (ts = {int(ts)})")
116
- self.has_identical_ts = True
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
- required_bridge_id = validation_data.iloc[0]['alias_bridge_id']
597
- if required_bridge_id != pkt_alias_bridge_id.upper():
598
- report.append(f"Alias bridge ID of the packet does not match. The required alias bridge ID is {required_bridge_id} but the packet alias bridge ID is {pkt_alias_bridge_id}")
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, AliasBridgeIDStage, GeolocationStage]
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 = stages + [ApiValidationStage]
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: 1.5.2a1
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 python library with tools used to test & certify boards and their compatibility with Wiliot's echosystem.
58
+ wiliot-certificate is a Python library that provides tools for testing and certifying boards for compatibility with Wiliots 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 GWs capabilities.
71
- The GW Certificate includes different test that run sequentially to test each capability reported by the GW.
72
- To run the GW Certificate the GW needs to use a public MQTT Broker (Eclipse):
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
- #### GW Certificate Release Notes:
91
+ #### Gateway Certificate Release Notes:
83
92
  Release:
84
93
  - Standalone wiliot-certificate package
85
94
  - Python 3.13 support
86
- - Gw API version 205 support
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
- usage: wlt-gw-certificate [-h] -owner OWNER -gw GW [-suffix SUFFIX] [-tests {connection,uplink,downlink,stress}]
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
- required arguments:
115
+ Required arguments:
99
116
  -gw GW Gateway ID
100
117
 
101
- optional arguments:
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 Time the uplink stages should wait before processing packets
108
- -suffix Allow for different suffixes after the GW ID in MQTT topics
109
- -env Wiliot envrionment for Registration and bridgeOTA tests
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 BRGs capabilities.
115
- The BRG Certificate includes different tests that run sequentially to test each capability reported by the BRG.
116
- The BRG Certificate tool uses a public MQTT Broker (Eclipse):
117
-
118
- Host: mqtt.eclipseprojects.io
119
- TLS TCP Port: 8883
120
- TLS Websocket Port: 443
121
- TCP Port: 1883
122
- Websocket Port: 80
123
-
124
- More information can be found at https://mqtt.eclipseprojects.io/.
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: brg_certificate_cli.py [-h] [--brg BRG] [--brg_cloud_connectivity BRG_CLOUD_CONNECTIVITY] [--brg1 BRG1] --gw GW [--data {tags,sim}] [--port PORT] [--clean] [--tl TL] [--run RUN]
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