wiliot-certificate 1.3.0a1__py3-none-any.whl → 1.4.0a2__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 (184) hide show
  1. brg_certificate/__init__.py +0 -0
  2. brg_certificate/ag/energous_v0_defines.py +925 -0
  3. brg_certificate/ag/energous_v1_defines.py +931 -0
  4. brg_certificate/ag/energous_v2_defines.py +925 -0
  5. brg_certificate/ag/energous_v3_defines.py +925 -0
  6. brg_certificate/ag/energous_v4_defines.py +925 -0
  7. brg_certificate/ag/fanstel_lan_v0_defines.py +925 -0
  8. brg_certificate/ag/fanstel_lte_v0_defines.py +925 -0
  9. brg_certificate/ag/fanstel_wifi_v0_defines.py +925 -0
  10. brg_certificate/ag/minew_lte_v0_defines.py +925 -0
  11. brg_certificate/ag/wlt_cmd_if.html +102 -0
  12. brg_certificate/ag/wlt_types.html +6114 -0
  13. brg_certificate/ag/wlt_types_ag.py +7840 -0
  14. brg_certificate/ag/wlt_types_ag_jsons/brg2brg_ota.json +142 -0
  15. brg_certificate/ag/wlt_types_ag_jsons/brg2gw_hb.json +785 -0
  16. brg_certificate/ag/wlt_types_ag_jsons/brg2gw_hb_sleep.json +139 -0
  17. brg_certificate/ag/wlt_types_ag_jsons/calibration.json +394 -0
  18. brg_certificate/ag/wlt_types_ag_jsons/custom.json +515 -0
  19. brg_certificate/ag/wlt_types_ag_jsons/datapath.json +672 -0
  20. brg_certificate/ag/wlt_types_ag_jsons/energy2400.json +550 -0
  21. brg_certificate/ag/wlt_types_ag_jsons/energySub1g.json +595 -0
  22. brg_certificate/ag/wlt_types_ag_jsons/externalSensor.json +598 -0
  23. brg_certificate/ag/wlt_types_ag_jsons/interface.json +938 -0
  24. brg_certificate/ag/wlt_types_ag_jsons/powerManagement.json +1234 -0
  25. brg_certificate/ag/wlt_types_ag_jsons/side_info_sensor.json +105 -0
  26. brg_certificate/ag/wlt_types_ag_jsons/signal_indicator_data.json +77 -0
  27. brg_certificate/ag/wlt_types_ag_jsons/unified_echo_ext_pkt.json +61 -0
  28. brg_certificate/ag/wlt_types_ag_jsons/unified_echo_pkt.json +110 -0
  29. brg_certificate/brg_certificate.py +191 -0
  30. brg_certificate/brg_certificate_cli.py +47 -0
  31. brg_certificate/cert_common.py +828 -0
  32. brg_certificate/cert_config.py +395 -0
  33. brg_certificate/cert_data_sim.py +188 -0
  34. brg_certificate/cert_defines.py +337 -0
  35. brg_certificate/cert_gw_sim.py +285 -0
  36. brg_certificate/cert_mqtt.py +373 -0
  37. brg_certificate/cert_prints.py +181 -0
  38. brg_certificate/cert_protobuf.py +88 -0
  39. brg_certificate/cert_results.py +300 -0
  40. brg_certificate/cert_utils.py +358 -0
  41. brg_certificate/certificate_sanity_test_list.txt +36 -0
  42. brg_certificate/certificate_test_list.txt +43 -0
  43. brg_certificate/config/eclipse.json +10 -0
  44. brg_certificate/config/hivemq.json +10 -0
  45. brg_certificate/config/mosquitto.json +10 -0
  46. brg_certificate/config/mosquitto.md +95 -0
  47. brg_certificate/config/wiliot-dev.json +10 -0
  48. brg_certificate/restore_brg.py +59 -0
  49. brg_certificate/tests/calibration/interval_test/interval_test.json +13 -0
  50. brg_certificate/tests/calibration/interval_test/interval_test.py +28 -0
  51. brg_certificate/tests/calibration/output_power_test/output_power_test.json +13 -0
  52. brg_certificate/tests/calibration/output_power_test/output_power_test.py +28 -0
  53. brg_certificate/tests/calibration/pattern_test/pattern_test.json +13 -0
  54. brg_certificate/tests/calibration/pattern_test/pattern_test.py +70 -0
  55. brg_certificate/tests/datapath/adaptive_pacer_algo_test/adaptive_pacer_algo_test.json +13 -0
  56. brg_certificate/tests/datapath/adaptive_pacer_algo_test/adaptive_pacer_algo_test.py +76 -0
  57. brg_certificate/tests/datapath/num_of_tags_test/num_of_tags_test.json +13 -0
  58. brg_certificate/tests/datapath/num_of_tags_test/num_of_tags_test.py +83 -0
  59. brg_certificate/tests/datapath/output_power_test/output_power_test.json +13 -0
  60. brg_certificate/tests/datapath/output_power_test/output_power_test.py +27 -0
  61. brg_certificate/tests/datapath/pacer_interval_ble5_test/pacer_interval_ble5_test.json +13 -0
  62. brg_certificate/tests/datapath/pacer_interval_ble5_test/pacer_interval_ble5_test.py +43 -0
  63. brg_certificate/tests/datapath/pacer_interval_tags_count_test/pacer_interval_tags_count_test.json +13 -0
  64. brg_certificate/tests/datapath/pacer_interval_tags_count_test/pacer_interval_tags_count_test.py +63 -0
  65. brg_certificate/tests/datapath/pacer_interval_test/pacer_interval_test.json +13 -0
  66. brg_certificate/tests/datapath/pacer_interval_test/pacer_interval_test.py +50 -0
  67. brg_certificate/tests/datapath/pattern_test/pattern_test.json +13 -0
  68. brg_certificate/tests/datapath/pattern_test/pattern_test.py +28 -0
  69. brg_certificate/tests/datapath/pkt_filter_ble5_test/pkt_filter_ble5_test.json +13 -0
  70. brg_certificate/tests/datapath/pkt_filter_ble5_test/pkt_filter_ble5_test.py +51 -0
  71. brg_certificate/tests/datapath/pkt_filter_gen3_test/pkt_filter_gen3_test.json +13 -0
  72. brg_certificate/tests/datapath/pkt_filter_gen3_test/pkt_filter_gen3_test.py +54 -0
  73. brg_certificate/tests/datapath/pkt_filter_test/pkt_filter_test.json +13 -0
  74. brg_certificate/tests/datapath/pkt_filter_test/pkt_filter_test.py +55 -0
  75. brg_certificate/tests/datapath/rssi_threshold_test/rssi_threshold_test.json +13 -0
  76. brg_certificate/tests/datapath/rssi_threshold_test/rssi_threshold_test.py +73 -0
  77. brg_certificate/tests/datapath/rx_channel_test/rx_channel_test.json +13 -0
  78. brg_certificate/tests/datapath/rx_channel_test/rx_channel_test.py +41 -0
  79. brg_certificate/tests/datapath/rx_rate_gen2_test/rx_rate_gen2_test.json +21 -0
  80. brg_certificate/tests/datapath/rx_rate_gen2_test/rx_rate_gen2_test.py +184 -0
  81. brg_certificate/tests/datapath/rx_rate_gen3_test/rx_rate_gen3_test.json +21 -0
  82. brg_certificate/tests/datapath/rx_rate_gen3_test/rx_rate_gen3_test.py +210 -0
  83. brg_certificate/tests/datapath/stress_gen3_test/stress_gen3_test.json +30 -0
  84. brg_certificate/tests/datapath/stress_gen3_test/stress_gen3_test.py +203 -0
  85. brg_certificate/tests/datapath/stress_test/stress_test.json +30 -0
  86. brg_certificate/tests/datapath/stress_test/stress_test.py +210 -0
  87. brg_certificate/tests/datapath/tx_repetition_algo_test/tx_repetition_algo_test.json +13 -0
  88. brg_certificate/tests/datapath/tx_repetition_algo_test/tx_repetition_algo_test.py +113 -0
  89. brg_certificate/tests/datapath/tx_repetition_test/tx_repetition_test.json +13 -0
  90. brg_certificate/tests/datapath/tx_repetition_test/tx_repetition_test.py +79 -0
  91. brg_certificate/tests/edge_mgmt/actions_test/actions_test.json +13 -0
  92. brg_certificate/tests/edge_mgmt/actions_test/actions_test.py +432 -0
  93. brg_certificate/tests/edge_mgmt/brg2brg_ota_ble5_test/brg2brg_ota_ble5_test.json +13 -0
  94. brg_certificate/tests/edge_mgmt/brg2brg_ota_ble5_test/brg2brg_ota_ble5_test.py +94 -0
  95. brg_certificate/tests/edge_mgmt/brg2brg_ota_test/brg2brg_ota_test.json +13 -0
  96. brg_certificate/tests/edge_mgmt/brg2brg_ota_test/brg2brg_ota_test.py +87 -0
  97. brg_certificate/tests/edge_mgmt/leds_test/leds_test.json +13 -0
  98. brg_certificate/tests/edge_mgmt/leds_test/leds_test.py +210 -0
  99. brg_certificate/tests/edge_mgmt/ota_test/ota_test.json +13 -0
  100. brg_certificate/tests/edge_mgmt/ota_test/ota_test.py +83 -0
  101. brg_certificate/tests/edge_mgmt/stat_test/stat_test.json +13 -0
  102. brg_certificate/tests/edge_mgmt/stat_test/stat_test.py +48 -0
  103. brg_certificate/tests/energy2400/duty_cycle_test/duty_cycle_test.json +13 -0
  104. brg_certificate/tests/energy2400/duty_cycle_test/duty_cycle_test.py +26 -0
  105. brg_certificate/tests/energy2400/output_power_test/output_power_test.json +13 -0
  106. brg_certificate/tests/energy2400/output_power_test/output_power_test.py +27 -0
  107. brg_certificate/tests/energy2400/pattern_test/pattern_test.json +13 -0
  108. brg_certificate/tests/energy2400/pattern_test/pattern_test.py +28 -0
  109. brg_certificate/tests/energy2400/signal_indicator_ble5_test/signal_indicator_ble5_test.json +13 -0
  110. brg_certificate/tests/energy2400/signal_indicator_ble5_test/signal_indicator_ble5_test.py +398 -0
  111. brg_certificate/tests/energy2400/signal_indicator_sub1g_2_4_test/signal_indicator_sub1g_2_4_test.json +13 -0
  112. brg_certificate/tests/energy2400/signal_indicator_sub1g_2_4_test/signal_indicator_sub1g_2_4_test.py +153 -0
  113. brg_certificate/tests/energy2400/signal_indicator_test/signal_indicator_test.json +13 -0
  114. brg_certificate/tests/energy2400/signal_indicator_test/signal_indicator_test.py +264 -0
  115. brg_certificate/tests/energy_sub1g/duty_cycle_test/duty_cycle_test.json +13 -0
  116. brg_certificate/tests/energy_sub1g/duty_cycle_test/duty_cycle_test.py +27 -0
  117. brg_certificate/tests/energy_sub1g/pattern_test/pattern_test.json +13 -0
  118. brg_certificate/tests/energy_sub1g/pattern_test/pattern_test.py +26 -0
  119. brg_certificate/tests/energy_sub1g/signal_indicator_functionality_test/signal_indicator_functionality_test.json +13 -0
  120. brg_certificate/tests/energy_sub1g/signal_indicator_functionality_test/signal_indicator_functionality_test.py +397 -0
  121. brg_certificate/tests/energy_sub1g/signal_indicator_test/signal_indicator_test.json +13 -0
  122. brg_certificate/tests/energy_sub1g/signal_indicator_test/signal_indicator_test.py +27 -0
  123. brg_certificate/wltPb_pb2.py +72 -0
  124. brg_certificate/wltPb_pb2.pyi +227 -0
  125. brg_certificate/wlt_types.py +114 -0
  126. gw_certificate/api/extended_api.py +7 -1531
  127. gw_certificate/api_if/200/data.json +106 -0
  128. gw_certificate/api_if/200/logs.json +12 -0
  129. gw_certificate/api_if/200/status.json +47 -0
  130. gw_certificate/api_if/201/data.json +98 -0
  131. gw_certificate/api_if/201/logs.json +12 -0
  132. gw_certificate/api_if/201/status.json +53 -0
  133. gw_certificate/api_if/202/data.json +83 -0
  134. gw_certificate/api_if/202/logs.json +12 -0
  135. gw_certificate/api_if/202/status.json +60 -0
  136. gw_certificate/api_if/203/data.json +85 -0
  137. gw_certificate/api_if/203/logs.json +12 -0
  138. gw_certificate/api_if/203/status.json +63 -0
  139. gw_certificate/api_if/204/data.json +85 -0
  140. gw_certificate/api_if/204/logs.json +12 -0
  141. gw_certificate/api_if/204/status.json +63 -0
  142. gw_certificate/api_if/205/data.json +85 -0
  143. gw_certificate/api_if/205/logs.json +12 -0
  144. gw_certificate/api_if/205/status.json +63 -0
  145. gw_certificate/api_if/api_validation.py +0 -2
  146. gw_certificate/common/analysis_data_bricks.py +18 -1413
  147. gw_certificate/common/debug.py +0 -21
  148. gw_certificate/common/utils.py +1 -212
  149. gw_certificate/common/utils_defines.py +0 -87
  150. gw_certificate/gw_certificate.py +9 -7
  151. gw_certificate/gw_certificate_cli.py +39 -23
  152. gw_certificate/interface/4.4.52_app.zip +0 -0
  153. gw_certificate/interface/4.4.52_sd_bl_app.zip +0 -0
  154. gw_certificate/interface/ble_simulator.py +0 -32
  155. gw_certificate/interface/if_defines.py +1 -0
  156. gw_certificate/interface/mqtt.py +96 -19
  157. gw_certificate/interface/nrfutil-linux +0 -0
  158. gw_certificate/interface/nrfutil-mac +0 -0
  159. gw_certificate/interface/nrfutil.exe +0 -0
  160. gw_certificate/interface/pkt_generator.py +0 -82
  161. gw_certificate/interface/uart_if.py +73 -43
  162. gw_certificate/templates/results.html +1 -1
  163. gw_certificate/tests/__init__.py +1 -2
  164. gw_certificate/tests/actions.py +134 -9
  165. gw_certificate/tests/connection.py +10 -5
  166. gw_certificate/tests/downlink.py +2 -4
  167. gw_certificate/tests/generic.py +62 -12
  168. gw_certificate/tests/registration.py +78 -27
  169. gw_certificate/tests/static/generated_packet_table.py +12 -48
  170. gw_certificate/tests/static/packet_table.csv +10048 -10048
  171. gw_certificate/tests/static/references.py +2 -1
  172. gw_certificate/tests/static/uplink_defines.py +0 -7
  173. gw_certificate/tests/throughput.py +7 -12
  174. gw_certificate/tests/uplink.py +83 -43
  175. {wiliot_certificate-1.3.0a1.dist-info → wiliot_certificate-1.4.0a2.dist-info}/METADATA +59 -8
  176. wiliot_certificate-1.4.0a2.dist-info/RECORD +198 -0
  177. {wiliot_certificate-1.3.0a1.dist-info → wiliot_certificate-1.4.0a2.dist-info}/WHEEL +1 -1
  178. wiliot_certificate-1.4.0a2.dist-info/entry_points.txt +3 -0
  179. wiliot_certificate-1.4.0a2.dist-info/top_level.txt +2 -0
  180. gw_certificate/interface/packet_error.py +0 -22
  181. wiliot_certificate-1.3.0a1.dist-info/RECORD +0 -51
  182. wiliot_certificate-1.3.0a1.dist-info/entry_points.txt +0 -2
  183. wiliot_certificate-1.3.0a1.dist-info/top_level.txt +0 -1
  184. {wiliot_certificate-1.3.0a1.dist-info → wiliot_certificate-1.4.0a2.dist-info}/LICENSE +0 -0
@@ -0,0 +1,828 @@
1
+ from brg_certificate.cert_prints import *
2
+ from brg_certificate.cert_defines import *
3
+ from brg_certificate.wlt_types import *
4
+ import brg_certificate.cert_config as cert_config
5
+ import brg_certificate.cert_mqtt as cert_mqtt
6
+ import datetime
7
+ # from ut_te import ut_rtsa
8
+ import pandas as pd
9
+ import os
10
+ import plotly.express as px
11
+ import math, random
12
+
13
+ DEFAULT_HDR = ag.Hdr(group_id=ag.GROUP_ID_GW2BRG)
14
+
15
+ # Returns a 12 chars long hex string
16
+ int2mac_get = lambda int_val: "{:012X}".format(int_val)
17
+
18
+ def name_to_val(name):
19
+ return globals()[name]
20
+
21
+ def test_prolog(test):
22
+ """
23
+ kicks off the test:
24
+ - sets test start time
25
+ - checks to see if brg is DB for DB-only tests
26
+ - setups spectrum analyzer configuration if needed
27
+
28
+ :param WltTest test: test to be started
29
+ :return test: returns the test
30
+ """
31
+ test.start_time = datetime.datetime.now()
32
+
33
+ test_run_print(test)
34
+
35
+ test.mqttc.flush_pkts()
36
+
37
+ #TODO - remove/check status later on in the test
38
+ test.set_phase_rc(PROLOG, rc=test.rc)
39
+ test.add_phase_reason(PROLOG, reason=test.reason)
40
+ #
41
+
42
+ return test
43
+
44
+ def test_epilog(test, revert_brgs=False, revert_gws=False, modules=[], brg1_modules=[], ble5=False):
45
+ """
46
+ closes off the test:
47
+ - sets test end time and duration
48
+ - reverts gw/brgs/both to defaults
49
+ - prints test results
50
+
51
+ :param WltTest test: test to be finished
52
+ :param bool revert_brgs: reverts brgs to defaults (default ep and config), defaults to False
53
+ :param bool revert_gws: reverts gws to defaults (default config), defaults to False
54
+ :return test: returns the test
55
+ """
56
+ # TODO - REMOVE when rc is re-designed
57
+ if test.get_phase_by_name(TEST_BODY):
58
+ test.set_phase_rc(TEST_BODY, test.rc)
59
+ test.add_phase_reason(TEST_BODY, test.reason)
60
+
61
+ test.reset_result()
62
+ test.set_phase_rc(EPILOG, TEST_PASSED)
63
+
64
+ if revert_brgs:
65
+ res2 = DONE
66
+ test, res = cert_config.config_brg_defaults(test, modules=modules, ble5=ble5)
67
+ # TODO - REMOVE when rc is re-designed
68
+ test.set_phase_rc(EPILOG, test.rc)
69
+ test.reset_result()
70
+ #
71
+ if test.brg1 and test.multi_brg:
72
+ brg1_modules = modules if not brg1_modules else brg1_modules
73
+ test, res2 = cert_config.config_brg1_defaults(test, modules=brg1_modules)
74
+ # TODO - REMOVE when rc is re-designed
75
+ test.set_phase_rc(EPILOG, test.rc)
76
+ test.reset_result()
77
+ #
78
+ if res == NO_RESPONSE or res2 == NO_RESPONSE:
79
+ txt = "Failed: Revert BRGs to defaults"
80
+ utPrint(txt, "RED")
81
+ test.add_phase_reason(EPILOG, txt)
82
+
83
+ if revert_gws:
84
+ test, res = cert_config.config_gw_defaults(test)
85
+ # TODO - REMOVE when rc is re-designed
86
+ test.set_phase_rc(EPILOG, test.rc)
87
+ test.reset_result()
88
+ #
89
+ if res == NO_RESPONSE:
90
+ txt = "Failed: Revert GW to defaults"
91
+ utPrint(txt, "RED")
92
+ test.add_phase_reason(EPILOG, txt)
93
+
94
+ test.mqttc.flush_pkts()
95
+ test.end_time = datetime.datetime.now()
96
+ test.duration = str(test.end_time - test.start_time).split(".")[0]
97
+
98
+ # patch for nightly pipeline - as long as brg ver is updated, continue
99
+ if ("ota_test" in test.module_name and not "brg2brg" in test.module_name and
100
+ (BRG_VER_SUCCESS in test.get_phase_reason(TEST_BODY) or WANTED_VER_SAME in test.get_phase_reason(TEST_BODY))
101
+ and test.get_phase_rc(TEST_BODY) == TEST_FAILED):
102
+ print("Setting rc to TEST_PASSED for pipeline after BRG OTA succeeded")
103
+ test.set_phase_rc(TEST_BODY, TEST_PASSED)
104
+ test.set_phase_rc(EPILOG, TEST_PASSED)
105
+
106
+ test_epilog_print(test)
107
+ return test
108
+
109
+ def get_gw_versions(test):
110
+ """
111
+ returns gw ble and wifi versions
112
+
113
+ :param WltTest test: test (with gw) to be checked
114
+ :return dict[str, str]: dictionary with BLE_VERSION and WIFI_VERSION
115
+ """
116
+ test.mqttc.flush_pkts()
117
+ cert_config.gw_info_action(test)
118
+ found = False
119
+ gw_ble_version, gw_wifi_version = "", ""
120
+ start_time = datetime.datetime.now()
121
+ while not found:
122
+ for p in test.mqttc._userdata[PKTS].status:
123
+ if GW_INFO in p.body:
124
+ print("Config pkts:")
125
+ print_pkt(p.body)
126
+ if test.protobuf:
127
+ gw_ble_version = p.body[GW_INFO][ENTRIES][BLE_VERSION][STR_VAL]
128
+ gw_wifi_version = p.body[GW_INFO][ENTRIES][WIFI_VERSION][STR_VAL]
129
+ else:
130
+ gw_ble_version = p.body[GW_INFO][BLE_VERSION]
131
+ gw_wifi_version = p.body[GW_INFO][WIFI_VERSION]
132
+ print(f"current versions: wifi {gw_wifi_version} ble {gw_ble_version}")
133
+ found = True
134
+ print_update_wait()
135
+ if (datetime.datetime.now() - start_time).seconds > DEFAULT_GW_FIELD_UPDATE_TIMEOUT:
136
+ test.rc = TEST_FAILED
137
+ test.add_reason(f"{GW_INFO} not found after {DEFAULT_BRG_FIELD_UPDATE_TIMEOUT} seconds!")
138
+ break
139
+ return {BLE_VERSION:gw_ble_version, WIFI_VERSION:gw_wifi_version}
140
+
141
+ def get_gw_geolocation(test):
142
+ """
143
+ returns gw latitude and longitude from a gw_info action
144
+
145
+ :param WltTest test: test (with gw) to be checked
146
+ :return dict[str, float]: dictionary with GW_LATITUDE and GW_LONGITUDE
147
+ """
148
+ test.mqttc.flush_pkts()
149
+ cert_config.gw_info_action(test)
150
+ found = False
151
+ gw_lat, gw_lng = 0.0, 0.0
152
+ start_time = datetime.datetime.now()
153
+ while not found:
154
+ for p in test.mqttc._userdata[PKTS].status:
155
+ if GW_INFO in p.body:
156
+ print_pkt(p.body)
157
+ gw_lat = p.body[GW_INFO][GW_LATITUDE]
158
+ gw_lng = p.body[GW_INFO][GW_LONGITUDE]
159
+ print(f"gw_lat:{gw_lat} \ngw_lng:{gw_lng}")
160
+ found = True
161
+ print_update_wait()
162
+ if (datetime.datetime.now() - start_time).seconds > DEFAULT_GW_FIELD_UPDATE_TIMEOUT:
163
+ test.rc = TEST_FAILED
164
+ test.add_reason(f"{GW_INFO} not found after {DEFAULT_BRG_FIELD_UPDATE_TIMEOUT} seconds!")
165
+ break
166
+ return test, {GW_LATITUDE:gw_lat, GW_LONGITUDE:gw_lng}
167
+
168
+ def get_gw_info(test):
169
+ """
170
+ gets gw info json dict from a gw_info action
171
+
172
+ :param WltTest test: test with gw that it's info will be retreived
173
+ :return str/dict[str, str]: json info dict from an info pkt OR a NO_RESPONSE str
174
+ """
175
+ test.mqttc.flush_pkts()
176
+ # Always send gw info in both JSON and protobuf
177
+ cert_config.gw_info_action(test)
178
+ test.protobuf = not test.protobuf
179
+ cert_config.gw_info_action(test)
180
+ test.protobuf = not test.protobuf
181
+
182
+ start_time = datetime.datetime.now()
183
+ while (datetime.datetime.now() - start_time).seconds < DEFAULT_GW_FIELD_UPDATE_TIMEOUT:
184
+ for p in test.mqttc._userdata[PKTS].status:
185
+ if GW_INFO in p.body:
186
+ print_pkt(p.body)
187
+ return p.body
188
+ print_update_wait()
189
+ return NO_RESPONSE
190
+
191
+ def get_logs(test):
192
+ """
193
+ gets logs info json dict from a gw_logs action
194
+
195
+ :param WltTest test: test with gw that it's info will be retreived
196
+ :return str/dict[str, str]: json info dict from an info pkt OR a NO_RESPONSE str
197
+ """
198
+ test.mqttc.flush_pkts()
199
+ cert_config.gw_logs_action(test)
200
+ start_time = datetime.datetime.now()
201
+ while (datetime.datetime.now() - start_time).seconds < DEFAULT_GW_FIELD_UPDATE_TIMEOUT:
202
+ for p in test.mqttc._userdata[PKTS].status:
203
+ if GET_LOGS:
204
+ print_pkt(p.body)
205
+ return p.body
206
+ print_update_wait()
207
+ return NO_RESPONSE
208
+
209
+ def get_brg_cfg_pkts(test, last=False, cfg_info=False):
210
+ """
211
+ gets brg cfg data pkts (payload)
212
+
213
+ :param WltTest test: test to be scanned (it's first brg is the default brg to be scanned for)
214
+ :param bool last: set to True to get only the last pkt caught, defaults to False
215
+ :param bool cfg_info: set to True to get cfg info sent by the brg (msg_type=1 instead of 5 which is the default for this function), defaults to False
216
+ :param int brg_mac: specific brg_mac in case we want to get cfg pkts for a specific brg different than the default, defaults to 0
217
+ :param bool module: Indicates we look for a module pkt as ack for config change
218
+ :return str/list[str]: cfg pkts payloads list/last cfg pkt payload received
219
+ """
220
+ pkts = []
221
+ msg_type = ag.BRG_MGMT_MSG_TYPE_CFG_SET
222
+ if cfg_info:
223
+ msg_type = ag.BRG_MGMT_MSG_TYPE_CFG_INFO
224
+
225
+ for p in cert_mqtt.get_brg2gw_mgmt_pkts(test.mqttc, test):
226
+ brg2gw_cfg = p[MGMT_PKT].pkt
227
+ if type(brg2gw_cfg).__name__ in [module.__name__ for module in test.active_brg.modules]:
228
+ if brg2gw_cfg.msg_type == msg_type:
229
+ pkts += [p[PAYLOAD]]
230
+ if pkts and last:
231
+ return pkts[-1]
232
+ return pkts
233
+
234
+ def get_brg_hb_pkts(test, last=False, brg_id_str=""):
235
+ """
236
+ gets brg hb data pkts (payload)
237
+
238
+ :param WltTest test: test to be scanned (it's first brg is the default brg to be scanned for)
239
+ :param bool last:set to True to get only the last pkt caught, defaults to False
240
+ :param str brg_id: specific brg_id in case we want to get hb pkts for a specific brg different than the default, defaults to ""
241
+ :return str/list[str]: hb pkts payloads list/last hb pkt payload received
242
+ """
243
+ pkts = []
244
+ if brg_id_str == "" and test.active_brg:
245
+ brg_id_str = test.active_brg.id_str
246
+ for p in cert_mqtt.get_brg2gw_mgmt_pkts(test.mqttc, test, brg_id_str):
247
+ brg2gw_hb = p[MGMT_PKT].pkt
248
+ if brg_id_str and type(brg2gw_hb) == eval_pkt(f'Brg2GwHbV{test.active_brg.api_version}'):
249
+ pkts += [p[PAYLOAD]]
250
+ elif not brg_id_str and type(brg2gw_hb) == eval_pkt(f'Brg2GwHbV{test.active_brg.api_version}'):
251
+ pkts += [p[PAYLOAD]]
252
+ if pkts and last:
253
+ return pkts[len(pkts)-1]
254
+ return pkts
255
+
256
+ time_in_sec = lambda t : t.seconds + t.microseconds / 1000000
257
+
258
+ # Pandas DataFrame documentation: https://pandas.pydata.org/docs/reference/frame.html
259
+
260
+ def get_all_brg_pkts(test):
261
+ utPrint(f"Collecting all BRG pkts", "BLUE")
262
+ return cert_mqtt.get_unified_data_pkts(test)
263
+
264
+ def get_pkts_data_frame(test, gw_data=False, brg_data=False, per_pkt_type=False):
265
+ pkts = []
266
+ tags_last_pkt_cntr = {}
267
+ tags_received_per_src = {}
268
+ tbc = None
269
+ gw_pkts = 0
270
+ brg_pkts = 0
271
+ all_data = {TIMESTAMP:[],TAG_ID:[],SRC_ID:[],NFPKT:[],TBC:[],PACKET_CNTR:[],PKT_CNTR_DIFF:[],CER:[],RSSI:[],BRG_LATENCY:[],PAYLOAD:[],SEQUENCE_ID:[],GW_ID:[], PACKET_TYPE:[]}
272
+ if gw_data:
273
+ pkts += cert_mqtt.get_internal_brg_unified_data_pkts(test)
274
+ if brg_data:
275
+ if test.brg1 and test.multi_brg:
276
+ pkts += get_all_brg_pkts(test)
277
+ test.active_brg = test.brg1
278
+ pkts += get_all_brg_pkts(test)
279
+ test.active_brg = test.brg0
280
+ else:
281
+ pkts += get_all_brg_pkts(test)
282
+ for p in pkts:
283
+ # Protection from pkts of type "test_mode" from old tags
284
+ if type(p[DECODED_DATA][PACKET_TYPE]) == str or p[DECODED_DATA][PACKET_TYPE] == None:
285
+ print(f"Skipped packet {p}")
286
+ continue
287
+ if per_pkt_type:
288
+ tag_id = p[DECODED_DATA][TAG_ID] + "_" + str(p[DECODED_DATA][PACKET_TYPE])
289
+ else:
290
+ tag_id = p[DECODED_DATA][TAG_ID]
291
+
292
+ if UNIFIED_PKT in p:
293
+ src_id = p[ALIAS_BRIDGE_ID]
294
+ nfpkt = p[UNIFIED_PKT].pkt.nfpkt
295
+ rssi = p[UNIFIED_PKT].pkt.rssi
296
+ brg_latency = p[UNIFIED_PKT].pkt.brg_latency
297
+ if isinstance(p[UNIFIED_PKT].pkt, ag.UnifiedEchoPktV1) or isinstance(p[UNIFIED_PKT].pkt, ag.UnifiedEchoExtPkt):
298
+ tbc = p[UNIFIED_PKT].pkt.tbc
299
+
300
+ all_data[TIMESTAMP] += [p[TIMESTAMP]]
301
+ all_data[TAG_ID] += [tag_id]
302
+ all_data[GW_ID] += [p[GW_ID]]
303
+ all_data[SRC_ID] += [src_id]
304
+ all_data[NFPKT] += [nfpkt]
305
+ all_data[TBC] += [tbc]
306
+ all_data[PACKET_CNTR] += [p[DECODED_DATA][PACKET_CNTR]]
307
+ all_data[RSSI] += [rssi]
308
+ all_data[BRG_LATENCY] += [brg_latency]
309
+ all_data[PAYLOAD] += [p[PAYLOAD]]
310
+ all_data[SEQUENCE_ID] += [p[SEQUENCE_ID]]
311
+ all_data[PACKET_TYPE] += [p[DECODED_DATA][PACKET_TYPE]]
312
+
313
+ # handling pkt_cntr_diff
314
+ pkt_cntr_diff = (p[DECODED_DATA][PACKET_CNTR] - tags_last_pkt_cntr[tag_id])%255 if tag_id and tag_id in tags_received_per_src and src_id and src_id in tags_received_per_src[tag_id] else None
315
+ all_data[PKT_CNTR_DIFF] += [pkt_cntr_diff]
316
+ cer = 1-(nfpkt/pkt_cntr_diff) if pkt_cntr_diff else None
317
+ all_data[CER] += [cer]
318
+
319
+ # saving last pkt_cntr per tag
320
+ tags_last_pkt_cntr[tag_id] = p[DECODED_DATA][PACKET_CNTR]
321
+
322
+ # saving all srcs a tag was received from
323
+ if tag_id and src_id:
324
+ if tag_id not in tags_received_per_src:
325
+ tags_received_per_src[tag_id] = [src_id]
326
+ elif not src_id in tags_received_per_src[tag_id]:
327
+ tags_received_per_src[tag_id] += [src_id]
328
+
329
+ if gw_data:
330
+ if src_id == test.internal_id_alias():
331
+ gw_pkts += 1
332
+ if brg_data:
333
+ if src_id != test.internal_id_alias():
334
+ brg_pkts += 1
335
+
336
+ if gw_data:
337
+ print(f"Found {gw_pkts} gw_tags_pkts")
338
+ if brg_data:
339
+ print(f"Found {brg_pkts} brg_tags_pkts")
340
+
341
+ df = pd.DataFrame.from_dict(all_data)
342
+ df = df.sort_values(by=TIMESTAMP)
343
+ return df
344
+
345
+ def data_scan(test, gw_data=False, brg_data=False, scan_time=0, per_pkt_type=False, pkt_filter_cfg=0, flush_pkts=True, first_pkt_is_start_time=False):
346
+ # MQTT scan
347
+ if flush_pkts:
348
+ test.mqttc.flush_pkts()
349
+ start_time = datetime.datetime.now()
350
+ if scan_time:
351
+ mqtt_scan_start(test, scan_time)
352
+ chars = ["|", "/", "-", "\\"]
353
+ start_time = datetime.datetime.now()
354
+ i = 0
355
+ while not test.rc:
356
+ cur_duration = (datetime.datetime.now() - start_time).seconds
357
+ if cur_duration >= scan_time:
358
+ break
359
+ if pipeline_running():
360
+ sys.stdout.write(".")
361
+ else:
362
+ sys.stdout.write("\r"+chars[i%4]*20+" "+str(cur_duration)+" "+chars[i%4]*20+" {} pkts captured".format(len(test.mqttc._userdata[PKTS].data)))
363
+ sys.stdout.flush()
364
+ time.sleep(0.25)
365
+ i += 1
366
+ print("\n")
367
+
368
+ if per_pkt_type:
369
+ cert_mqtt.dump_pkts(test, log=str(pkt_filter_cfg))
370
+ if pkt_filter_cfg == ag.PKT_FILTER_RANDOM_FIRST_ARRIVING_PKT:
371
+ # When PKT_FILTER_RANDOM_FIRST_ARRIVING_PKT we don't want to split the tags to be per pkt_type
372
+ per_pkt_type = False
373
+ df = get_pkts_data_frame(test, gw_data=gw_data, brg_data=brg_data, per_pkt_type=per_pkt_type)
374
+ if not df.empty:
375
+ df['gw_id'] = test.internal_id_alias()
376
+ if first_pkt_is_start_time:
377
+ start_time = min(df[TIMESTAMP])
378
+ df[TIMESTAMP_DELTA] = (df[TIMESTAMP]- start_time) / 1000
379
+ else:
380
+ df[TIMESTAMP_DELTA] = (df[TIMESTAMP] / 1000) - start_time.timestamp()
381
+ return df
382
+
383
+ def pacing_analysis(test, pacer_interval, df, pkt_filter_cfg=ag.PKT_FILTER_RANDOM_FIRST_ARRIVING_PKT, num_of_pixels=0, is_ble5_test=False):
384
+ ROUND = 3
385
+
386
+ # Validate pkts amount
387
+ if df[TAG_ID].nunique() == 0:
388
+ if pkt_filter_cfg == ag.PKT_FILTER_DISABLE_FORWARDING:
389
+ print("Packets echo disabled and no packets were found accordingly")
390
+ else:
391
+ test.rc = TEST_FAILED
392
+ test.add_reason("No packets found!\nMake sure you have an energizing BRG around you.")
393
+ print(test.reason)
394
+ return test
395
+ elif pkt_filter_cfg == ag.PKT_FILTER_DISABLE_FORWARDING:
396
+ test.rc = TEST_FAILED
397
+ test.add_reason("Packets were found while packets echo is turned off!")
398
+ print(test.reason)
399
+ return test
400
+
401
+ # Verify received pkt types are correct when cfg is not PKT_FILTER_RANDOM_FIRST_ARRIVING_PKT
402
+ if pkt_filter_cfg != ag.PKT_FILTER_RANDOM_FIRST_ARRIVING_PKT:
403
+ for pkt_type in list(df[PACKET_TYPE].unique()):
404
+ if ((pkt_filter_cfg & (1 << pkt_type)) == 0
405
+ and not (is_ble5_test and test.internal_brg and pkt_type == ag.PKT_TYPE_BLE5_EXTENDED_TEMP_ADVANCED)):
406
+ test.rc = TEST_FAILED
407
+ test.add_reason(f"Tag is of packet type {pkt_type} which is turned off in packet_types_mask configuration!")
408
+ return test
409
+
410
+ # Verify the tags count according to simulation data and pkt_filter_cfg
411
+ tags_count = len(list(df[TAG_ID].unique()))
412
+ if test.data == DATA_SIMULATION and num_of_pixels:
413
+ if pkt_filter_cfg == ag.PKT_FILTER_TEMP_AND_ADVANCED_PKTS or pkt_filter_cfg == ag.PKT_FILTER_TEMP_AND_DEBUG_PKTS:
414
+ expected_tags_count = num_of_pixels * 2
415
+ elif pkt_filter_cfg == ag.PKT_FILTER_TEMP_ADVANCED_AND_DEBUG_PKTS:
416
+ expected_tags_count = num_of_pixels * 3
417
+ else:
418
+ expected_tags_count = num_of_pixels
419
+ if tags_count != expected_tags_count:
420
+ test.rc = TEST_FAILED
421
+ test.add_reason(f"Expected {expected_tags_count} pixels but found {tags_count}!")
422
+ print(test.reason)
423
+ return test
424
+
425
+ # Verify the tags pacer interval
426
+ failed_tags = 0
427
+ for tag in list(df[TAG_ID].unique()):
428
+ pkts = df.query('tag_id == @tag')
429
+ avg_pacer = round(pkts.timestamp.diff().mean(skipna=True)/1000, ROUND)
430
+ print(f"Tag: {tag} avg_pacer={avg_pacer} num_of_pkts={len(pkts)}")
431
+ if ((avg_pacer / pacer_interval) < PACER_INTERVAL_THRESHOLD_HIGH and (pacer_interval - avg_pacer) > 1):
432
+ failed_tags += 1
433
+ test.rc = TEST_FAILED
434
+ print(f"Tag {tag} with diff_time {list(pkts.timestamp.diff().div(1000))}, avg_pacer={avg_pacer} exceeds {PACER_INTERVAL_THRESHOLD_HIGH} minimum threshold!")
435
+ if test.data == DATA_SIMULATION and (avg_pacer / pacer_interval) > PACER_INTERVAL_CEIL_THRESHOLD:
436
+ failed_tags += 1
437
+ print(f"Tag {tag} with diff_time {list(pkts.timestamp.diff().div(1000))}, avg_pacer={avg_pacer} exceeds {PACER_INTERVAL_CEIL_THRESHOLD} maximum threshold!")
438
+ if failed_tags > 1: # Fail the test on ceil threshold only when more than one tag failed
439
+ test.rc = TEST_FAILED
440
+
441
+ # PASS test if only 1 tag out of many failed - this could be an issue with the tag
442
+ if tags_count >= PACER_INTERVAL_MIN_TAGS_COUNT and failed_tags <= PACER_INTERVAL_MAX_FAILED_TAGS:
443
+ test.rc = TEST_PASSED
444
+ # Addition to understand how many tags failed in total
445
+ if test.rc == TEST_FAILED:
446
+ test.add_reason(f"{failed_tags}/{tags_count} tags with wrong time diff")
447
+ print(test.reason)
448
+ return test
449
+ return test
450
+
451
+ def reboot_config_analysis(test, expected_hash, timeout=ACTION_LONG_TIMEOUT, ble_version=None, bl_version=None):
452
+ utPrint("Analyzing Reboot", "BLUE")
453
+ # start with a 5 sec wait time before searching interface to allow the BRG to reboot
454
+ time.sleep(5)
455
+
456
+ start_time = datetime.datetime.now()
457
+ seq_ids = []
458
+ found = {ag.MODULE_IF : False, ag.MODULE_DATAPATH: False}
459
+ received_hash = 0
460
+ # Flush data pkts only to keep the GW logs which are in status topic
461
+ test.mqttc.flush_data_pkts()
462
+
463
+ while not all(found.values()):
464
+ # scan for ModuleIf and ModuleDatapath pkts of all api versions to support api version change on update
465
+ # ModuleDatapath arrival shows that the BLE really rebooted
466
+ if_pkts_list = [eval_pkt(f'ModuleIfV{i}') for i in range(ag.API_VERSION_V9, ag.API_VERSION_LATEST+1)]
467
+ datapath_pkts_list = [eval_pkt(f'ModuleDatapathV{i}') for i in range(ag.API_VERSION_V9, ag.API_VERSION_LATEST+1)]
468
+ pkts = cert_mqtt.get_brg2gw_mgmt_pkts(test.mqttc, test, mgmt_types=if_pkts_list+datapath_pkts_list)
469
+ for p in pkts:
470
+ if (not seq_ids or p[SEQUENCE_ID] not in seq_ids):
471
+ seq_ids.append(p[SEQUENCE_ID])
472
+ module_pkt = p[MGMT_PKT].pkt
473
+ if not found[module_pkt.module_type]:
474
+ print("\nGot {} packet after {} sec!".format(type(module_pkt).__name__, (datetime.datetime.now() - start_time).seconds))
475
+ print(module_pkt)
476
+ if module_pkt.module_type == ag.MODULE_IF:
477
+ test.active_brg.api_version = module_pkt.api_version
478
+ print(f"received ModuleIfV{test.active_brg.api_version} pkt:")
479
+ # get received cfg_hash & expected cfg_hash
480
+ received_hash = module_pkt.cfg_hash
481
+ print(f"\nexpected cfg_hash: {hex(expected_hash)}")
482
+ print(f"received cfg_hash: {hex(received_hash)}")
483
+ # brg version update (OTA) analysis
484
+ if ble_version:
485
+ brg_version = f"{module_pkt.major_ver}.{module_pkt.minor_ver}.{module_pkt.patch_ver}"
486
+ print(f"\nBRG version: {brg_version}, expected version: {ble_version}")
487
+ # compare wanted version to received version
488
+ if brg_version == ble_version:
489
+ test.add_reason(BRG_VER_SUCCESS)
490
+ # ALSO compare received cfg_hash to expected cfg_hash
491
+ # expected_hash will be 1 if api_version was updated
492
+ if received_hash == expected_hash or expected_hash == 1:
493
+ found[module_pkt.module_type] = True
494
+ elif bl_version:
495
+ brg_bl_version = module_pkt.bl_version
496
+ print(f"\nBRG bootloader version: {brg_bl_version}, expected bootloader version: {bl_version}")
497
+ # compare wanted version to received version
498
+ if brg_bl_version == bl_version:
499
+ test.add_reason(BRG_BL_VER_SUCCESS)
500
+ found[module_pkt.module_type] = True
501
+ # analysis of any other reboot actions with no version update (relevant only for api version 8 or higher)
502
+ # compare received cfg_hash to expected cfg_hash
503
+ elif received_hash == expected_hash:
504
+ found[module_pkt.module_type] = True
505
+ else:
506
+ found[module_pkt.module_type] = True
507
+ print_update_wait()
508
+
509
+ if (datetime.datetime.now() - start_time).seconds > timeout:
510
+ test.rc = TEST_FAILED
511
+ unfound = [f'{ag.MODULES_DICT[m]}{test.active_brg.api_version}' for m in found if not found[m]]
512
+ test.add_reason(f"{unfound} not received in {timeout} sec")
513
+ break
514
+ return test
515
+
516
+ def scan_for_mgmt_pkts(test, mgmt_type):
517
+
518
+ start_time = datetime.datetime.now()
519
+ # Search for module packets
520
+ found = False
521
+ ret_pkts = []
522
+ while DEFAULT_BRG_FIELD_UPDATE_TIMEOUT > (datetime.datetime.now() - start_time).seconds:
523
+ print_update_wait()
524
+ pkts_collected = cert_mqtt.get_brg2gw_mgmt_pkts(test.mqttc, test, mgmt_types=mgmt_type)
525
+ if pkts_collected:
526
+ utPrint("Found brg2gw_mgmt_pkts:", "GREEN")
527
+ seq_ids = []
528
+ for p in pkts_collected:
529
+ if seq_ids == [] or p[SEQUENCE_ID] not in seq_ids:
530
+ seq_ids.append(p[SEQUENCE_ID])
531
+ print(p[MGMT_PKT].pkt)
532
+ ret_pkts.append(p)
533
+ found = True
534
+ break
535
+ if not found:
536
+ test.rc = TEST_FAILED
537
+ test.add_reason(f"Didn't receive {mgmt_type[0].__name__} pkt after {DEFAULT_BRG_FIELD_UPDATE_TIMEOUT} seconds!")
538
+ return test, ret_pkts
539
+
540
+ # Plotly graphing libraries documentation: https://plotly.com/python/
541
+
542
+ def display_data(df, csv=True, nfpkt=False, pkt_cntr_diff=False, cer_per_tag=False, tbc=False, rssi=False, ttfp=False, start_time=None, name_prefix="", dir=""):
543
+ print("\nGenerating data analysis graphs and CSV file\n")
544
+ df[DATETIME] = df[TIMESTAMP].apply(lambda x: datetime.datetime.fromtimestamp(x/1e3))
545
+ df = df.sort_values(by=DATETIME)
546
+ symbol_sequence = ["hourglass", "bowtie", "cross", "x"]
547
+ all_graphs = []
548
+ ttfp_graph = None
549
+ # insert new start_time to override timestamp_delta from data_scan()
550
+ if start_time:
551
+ df[TIMESTAMP_DELTA] = (df[TIMESTAMP] / 1000) - start_time.timestamp()
552
+ if nfpkt:
553
+ nfpkt_graph = px.scatter(df, title=NFPKT, x=DATETIME, y=NFPKT, color=TAG_ID, symbol=SRC_ID, symbol_sequence=symbol_sequence)
554
+ nfpkt_graph.update_traces(marker=dict(size=12, line=dict(width=2, color='DarkSlateGrey')), selector=dict(mode='markers'))
555
+ all_graphs.append(nfpkt_graph)
556
+ if rssi:
557
+ rssi_graph = px.scatter(df, title=RSSI, x=DATETIME, y=RSSI, color=TAG_ID, symbol=SRC_ID, symbol_sequence=symbol_sequence)
558
+ rssi_graph.update_traces(marker=dict(size=12, line=dict(width=2, color='DarkSlateGrey')), selector=dict(mode='markers'))
559
+ all_graphs.append(rssi_graph)
560
+ if pkt_cntr_diff:
561
+ pkt_cntr_diff_graph = px.scatter(df, title=PKT_CNTR_DIFF, x=DATETIME, y=PKT_CNTR_DIFF, color=TAG_ID, symbol=SRC_ID, symbol_sequence=symbol_sequence)
562
+ pkt_cntr_diff_graph.update_traces(marker=dict(size=12, line=dict(width=2, color='DarkSlateGrey')), selector=dict(mode='markers'))
563
+ all_graphs.append(pkt_cntr_diff_graph)
564
+ if cer_per_tag:
565
+ cer_per_tag_graph = px.scatter(df, title=CER, x=DATETIME, y=CER, color=TAG_ID, symbol=SRC_ID, symbol_sequence=symbol_sequence)
566
+ cer_per_tag_graph.update_traces(marker=dict(size=12, line=dict(width=2, color='DarkSlateGrey')), selector=dict(mode='markers'))
567
+ all_graphs.append(cer_per_tag_graph)
568
+ if tbc:
569
+ tbc_graph = px.scatter(df, title=TBC, x=DATETIME, y=TBC, color=TAG_ID, symbol=SRC_ID, symbol_sequence=symbol_sequence)
570
+ tbc_graph.update_traces(marker=dict(size=12, line=dict(width=2, color='DarkSlateGrey')), selector=dict(mode='markers'))
571
+ all_graphs.append(tbc_graph)
572
+ if ttfp:
573
+ data = {TIMESTAMP_DELTA:[], TAGS_COUNT:[], NEW_TAGS:[]}
574
+ tags_count = []
575
+ # iterate all integers from 0 to the largest timestamp_delta as values for X
576
+ for i in range(int(math.ceil(df[TIMESTAMP_DELTA].iloc[-1]))+1):
577
+ new_tags = []
578
+ # for every timestamp_delta value (i) add all NEW tags received in that timestamp_delta
579
+ for row in df.query('timestamp_delta < @i').itertuples(index=False):
580
+ if not row.tag_id in tags_count and not row.tag_id in new_tags:
581
+ new_tags += [row.tag_id]
582
+ tags_count += new_tags
583
+ data[TIMESTAMP_DELTA] += ([i])
584
+ data[TAGS_COUNT] += [len(tags_count)]
585
+ data[NEW_TAGS] += [new_tags]
586
+ ttfp_graph = px.line(pd.DataFrame(data), x=TIMESTAMP_DELTA, y=TAGS_COUNT, title=TTFP,hover_data=[TIMESTAMP_DELTA,TAGS_COUNT,NEW_TAGS], markers=True)
587
+ all_graphs.append(ttfp_graph)
588
+ #generate
589
+ with open(os.path.join(BASE_DIR, dir, f"{name_prefix}data_graphs.html"), 'w') as f:
590
+ for g in all_graphs:
591
+ f.write(g.to_html(full_html=False, include_plotlyjs='cdn', include_mathjax='cdn'))
592
+ f.write("<br>")
593
+ if csv:
594
+ df.to_csv(os.path.join(dir, f"{name_prefix}all_data.csv"), index=False)
595
+
596
+ return ttfp_graph
597
+
598
+ def single_log_search(test, s, found, fail_on_find=False, print_logs=True, additional_log=""):
599
+ res = False
600
+ for p in test.mqttc._userdata[PKTS].status:
601
+ if GW_LOGS in p.body:
602
+ logs = p.body[GW_LOGS][LOGS] if test.protobuf else p.body[GW_LOGS]
603
+ for log in logs:
604
+ if any([s in log]) and any([additional_log in log]) and (log not in found):
605
+ print(f"Log: {log}, Additional Log: {additional_log}")
606
+ found += [log]
607
+ res = True
608
+ if fail_on_find:
609
+ if test.rc == TEST_PASSED:
610
+ test= test.add_reason("Test functionality passed")
611
+ test.add_reason(f"Found {s}")
612
+ test.rc = TEST_FAILED
613
+ print(found)
614
+ return test, res, found
615
+ if print_logs:
616
+ print_pkt(s)
617
+ return test, res, found
618
+
619
+ def gw_logs_search(test, strings, scan_time=GW_LOG_PERIOD+5, print_logs=False, fail_on_find=False):
620
+ """searching for specific logs in mqtt status topic in GW_LOGS field
621
+
622
+ :param WltTest test: test running
623
+ :param [str] strings: list of logs to search
624
+ :param int scan_time: time to scan for logs, defaults to GW_LOG_PERIOD+5
625
+ :return WltTest: test with updated results
626
+ """
627
+ start_time = datetime.datetime.now()
628
+ print(f"Searching for {strings} log in MQTT status topic.\nFail on find is set to {fail_on_find}")
629
+ found = []
630
+ while (len(strings) > len(found)):
631
+ for s in strings:
632
+ test, res, found = single_log_search(test, s, found, fail_on_find, print_logs)
633
+ if res:
634
+ break
635
+ if (datetime.datetime.now() - start_time).seconds >= scan_time:
636
+ if not fail_on_find:
637
+ test.add_reason(f"Didnt find logs in [{scan_time}] seconds")
638
+ print(test.reason)
639
+ test.rc = TEST_FAILED
640
+ break
641
+ if test.rc == TEST_PASSED:
642
+ if not fail_on_find:
643
+ print(f"SUCCESS found all [{strings}]")
644
+ else:
645
+ print(f"SUCCESS Didnt find [{strings}]")
646
+ return test
647
+
648
+ def gw_action_status_search(test, action_idx, status_code):
649
+ """searching for action returned status code in mqtt status topic in ACTION field
650
+
651
+ :param WltTest test: test running
652
+ :param int action_idx: sent action index
653
+ :param int status_code: expected status code for action
654
+ :return WltTest: test with updated results
655
+ """
656
+ start_time = datetime.datetime.now()
657
+ print(f"Searching for action idx ({action_idx}) update log in MQTT status topic")
658
+ while (datetime.datetime.now() - start_time).seconds < GW_LOG_PERIOD:
659
+ for p in test.mqttc._userdata[PKTS].status:
660
+ # JSON
661
+ if ((ACTION in p.body) and (p.body[ACTION] == action_idx) and
662
+ (STATUS_CODE_STR in p.body) and (p.body[STATUS_CODE_STR] == status_code)):
663
+ return test
664
+ # Protobuf - when succeed status is not sent
665
+ if ((ACTION_STATUS in p.body) and (p.body[ACTION_STATUS][ACTION] == action_idx) and
666
+ (STATUS_CODE not in p.body[ACTION_STATUS])):
667
+ return test
668
+ test.add_reason(f"action_idx={action_idx} status_code={status_code} not found in logs after {GW_LOG_PERIOD} seconds\n")
669
+ print(test.reason)
670
+ test.rc = TEST_FAILED
671
+ return test
672
+
673
+ def get_gw_logs_packets(test, last=False, print_log=True):
674
+ """
675
+ gets gw logs pkts
676
+ :param WltTest test: test with gw that it's info will be retreived
677
+ :param bool last: set to True to get only the last pkt caught, defaults to False
678
+ :return pkt/list[pkt]: logs pkts list/last status pkt received
679
+ """
680
+ cert_config.gw_logs_action(test)
681
+ pkts = []
682
+ for p in test.mqttc._userdata[PKTS].status:
683
+ if GW_LOGS in p.body:
684
+ if print_log:
685
+ print("GW logs packet:\n", p.body[GW_LOGS])
686
+ logs = p.body[GW_LOGS][LOGS] if test.protobuf else p.body[GW_LOGS]
687
+ pkts += [log for log in logs]
688
+ if pkts and last:
689
+ return pkts[len(pkts)-1]
690
+ return pkts
691
+
692
+ def wait_time_n_print(secs):
693
+ utPrint(f"Waiting for {secs} seconds", "CYAN")
694
+ while secs:
695
+ print_update_wait()
696
+ secs -= 1
697
+
698
+ def get_module_if_pkt(test):
699
+ cert_config.send_brg_action(test, ag.ACTION_GET_MODULE, interface=1)
700
+ test, pkts = scan_for_mgmt_pkts(test, mgmt_type=[eval_pkt(f'ModuleIfV{test.active_brg.api_version}'),
701
+ eval_pkt(f'ModuleIfV{test.active_brg.api_version - 1}'),])
702
+ if test.rc == TEST_FAILED:
703
+ return test, NO_RESPONSE
704
+ else:
705
+ print(pkts[-1][MGMT_PKT].pkt)
706
+ return test, pkts[-1][MGMT_PKT].pkt
707
+
708
+ def get_cfg_hash(test):
709
+ utPrint(f"Fetching BRG cfg hash for BRG {test.active_brg.id_str}", "BLUE")
710
+ test, module_if_pkt = get_module_if_pkt(test)
711
+ if test.rc == TEST_FAILED:
712
+ return test, 0
713
+ else:
714
+ return test, module_if_pkt.cfg_hash
715
+
716
+ def module_ack_search(test, test_pkt, mgmt_type, wait=True):
717
+ """
718
+ module ack search
719
+ wait=False is for pwr mgmt off - in order to send the "off" pkt repeatidly while searching for the ack
720
+ """
721
+ if wait:
722
+ test, mgmt_pkts = scan_for_mgmt_pkts(test, [mgmt_type])
723
+ else:
724
+ mgmt_pkts = cert_mqtt.get_brg2gw_mgmt_pkts(test.mqttc, test, mgmt_types=[mgmt_type])
725
+ if not test.rc:
726
+ for p in mgmt_pkts:
727
+ pkt = p[MGMT_PKT].pkt
728
+ if (pkt == test_pkt.pkt):
729
+ return test, True
730
+ if wait:
731
+ test.rc = TEST_FAILED
732
+ test.add_reason(f"{mgmt_type} module does not match pkt received")
733
+ print(test.reason)
734
+ return test, False
735
+
736
+ def brg_restore_defaults_check(test):
737
+ print("Starting Restore Defaults Check")
738
+ start_time = datetime.datetime.now()
739
+ found = False
740
+ revived = False
741
+ output = ""
742
+ while not found:
743
+ last_pkt = get_brg_cfg_pkts(test=test, cfg_info=True, last=True)
744
+ if last_pkt:
745
+ print(f"Got pkt after {(datetime.datetime.now() - start_time).seconds} sec!")
746
+ wlt_pkt = WltPkt(last_pkt)
747
+ print(f"SUCCESS: Found pkt from brg: {wlt_pkt}")
748
+ found = True # exit
749
+ revived = True
750
+ output = "SUCCESS: brg is alive and restored to defaults!"
751
+ if (datetime.datetime.now() - start_time).seconds > ACTION_LONG_TIMEOUT:
752
+ print(f"FAILURE: Can't find bridge! Didn't get config pkt after {ACTION_LONG_TIMEOUT} seconds!")
753
+ break
754
+ print_update_wait()
755
+ return test, revived, output
756
+
757
+ def erase_sensors(test):
758
+ module = eval_pkt(f'ModuleExtSensorsV{test.active_brg.api_version}')
759
+ wltpkt = WltPkt(hdr=DEFAULT_HDR, pkt=eval_pkt(f'ModuleExtSensorsV{test.active_brg.api_version}')(brg_mac=test.active_brg.id_int, msg_type=ag.BRG_MGMT_MSG_TYPE_CFG_SET, seq_id=random.randrange(99),
760
+ sensor0=0, sensor1=0))
761
+ print("Erasing all sensors from BRG {}".format(test.active_brg.id_int))
762
+ test = cert_config.brg_configure(test=test, cfg_pkt=wltpkt)[0]
763
+
764
+ if test.rc == TEST_FAILED:
765
+ test.add_reason("Failed to erase sensors! Didn't receive module ext sensors pkt")
766
+ else:
767
+ utPrint("SUCCESS! Module ext_sensors returned to default!", "GREEN")
768
+ return test
769
+
770
+ # Pwr Mgmt
771
+ def brg_pwr_mgmt_turn_on(test):
772
+ utPrint("Sending pwr_mgmt static mode configuration - 30 seconds ON, 60 seconds SLEEP!", "BLUE")
773
+ module = eval_pkt(f'ModulePwrMgmtV{test.active_brg.api_version}')
774
+ # send pwr mgmt module packet
775
+ wltpkt = WltPkt(hdr=DEFAULT_HDR, pkt=module(module_type=ag.MODULE_PWR_MGMT, msg_type=ag.BRG_MGMT_MSG_TYPE_CFG_SET,
776
+ api_version=ag.API_VERSION_LATEST,seq_id=random.randrange(99),
777
+ brg_mac=test.active_brg.id_int, static_on_duration=30, static_sleep_duration=60,
778
+ dynamic_leds_on=0,dynamic_keep_alive_period=0, dynamic_keep_alive_scan=0,
779
+ dynamic_on_duration=0,dynamic_sleep_duration=0))
780
+ cert_config.gw_downlink(test, raw_tx_data=wltpkt.dump())
781
+ test = module_ack_search(test, test_pkt=wltpkt, mgmt_type=module)[0]
782
+
783
+ if test.rc == TEST_FAILED:
784
+ test.add_reason("Turning pwr mgmt ON failed, Didn't receive GW MEL pwr mgmt ON pkt")
785
+ else:
786
+ utPrint("SUCCESS! pwr mgmt static mode turned on!", "GREEN")
787
+ return test, wltpkt
788
+
789
+ def brg_pwr_mgmt_turn_off(test):
790
+ utPrint("Turning pwr mgmt OFF - sending default configuration!", "BLUE")
791
+ module = eval_pkt(f'ModulePwrMgmtV{test.active_brg.api_version}')
792
+ start_time = datetime.datetime.now()
793
+ wltpkt = WltPkt(hdr=DEFAULT_HDR, pkt=module(module_type=ag.MODULE_PWR_MGMT, msg_type=ag.BRG_MGMT_MSG_TYPE_CFG_SET,
794
+ api_version=ag.API_VERSION_LATEST,seq_id=random.randrange(99),
795
+ brg_mac=test.active_brg.id_int,static_leds_on=1,
796
+ static_keep_alive_period=0,static_keep_alive_scan=0,
797
+ static_on_duration=0,static_sleep_duration=0,
798
+ dynamic_leds_on=0,dynamic_keep_alive_period=0,
799
+ dynamic_keep_alive_scan=0,dynamic_on_duration=0,dynamic_sleep_duration=0))
800
+ found = False
801
+ while not found:
802
+ cert_config.gw_downlink(test, raw_tx_data=wltpkt.dump())
803
+ test, found = module_ack_search(test, wltpkt, module, wait=False)
804
+ if ((datetime.datetime.now() - start_time).seconds > (ag.PWR_MGMT_DEFAULTS_KEEP_ALIVE_PERIOD + 1)):
805
+ test.add_reason(f"Didn't receive GW MEL pwr mgmt OFF ack after {ag.PWR_MGMT_DEFAULTS_KEEP_ALIVE_PERIOD + 1} seconds")
806
+ test.rc = TEST_FAILED
807
+ break
808
+ print_update_wait()
809
+ if found:
810
+ utPrint(f"FOUND off pkt after {(datetime.datetime.now() - start_time)} secs", "GREEN")
811
+ utPrint("SUCCESS! pwr mgmt static mode turned off!", "GREEN")
812
+ return test
813
+
814
+ # LEDs tests funcs
815
+ def check_input_n_try_again(value):
816
+ # check for valid input char - only 'Y', 'y', 'N' or 'n'
817
+ while value.lower() != 'y' and value.lower() != 'n':
818
+ utPrint("Wrong input, Please try Again!\n", "RED")
819
+ value = input()
820
+ return value
821
+
822
+ # Executed only when the received value is 'n'!
823
+ def value_check_if_y(test, received_value, stage):
824
+ # check if the received value is different from the expected value
825
+ if 'y' != received_value.lower():
826
+ test.rc = TEST_FAILED
827
+ test.add_reason(f"{stage} failed")
828
+ return test