wiliot-certificate 4.4.2__py3-none-any.whl → 4.5.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 → certificate}/ag/wlt_cmd_if.html +10 -4
- {brg_certificate → certificate}/ag/wlt_types_ag.py +1878 -519
- certificate/cert_common.py +1488 -0
- certificate/cert_config.py +480 -0
- {brg_certificate → certificate}/cert_data_sim.py +134 -46
- {brg_certificate → certificate}/cert_defines.py +129 -128
- {brg_certificate → certificate}/cert_gw_sim.py +183 -53
- {brg_certificate → certificate}/cert_mqtt.py +179 -64
- {brg_certificate → certificate}/cert_prints.py +35 -33
- {brg_certificate → certificate}/cert_protobuf.py +15 -6
- {brg_certificate → certificate}/cert_results.py +240 -64
- certificate/cert_utils.py +634 -0
- certificate/certificate.py +205 -0
- certificate/certificate_cli.py +76 -0
- certificate/certificate_eth_test_list.txt +76 -0
- certificate/certificate_sanity_test_list.txt +66 -0
- certificate/certificate_test_list.txt +76 -0
- {brg_certificate → certificate}/tests/calibration/interval_test/interval_test.json +3 -2
- {brg_certificate → certificate}/tests/calibration/interval_test/interval_test.py +7 -6
- certificate/tests/calibration/output_power_test/output_power_test.json +23 -0
- certificate/tests/calibration/output_power_test/output_power_test.py +39 -0
- {brg_certificate → certificate}/tests/calibration/pattern_test/pattern_test.json +2 -1
- {brg_certificate → certificate}/tests/calibration/pattern_test/pattern_test.py +20 -15
- certificate/tests/cloud_connectivity/acl_ext_adv_test/acl_ext_adv_test.json +15 -0
- certificate/tests/cloud_connectivity/acl_ext_adv_test/acl_ext_adv_test.py +140 -0
- certificate/tests/cloud_connectivity/acl_test/acl_test.json +15 -0
- certificate/tests/cloud_connectivity/acl_test/acl_test.py +96 -0
- certificate/tests/cloud_connectivity/brg_ota_test/brg_ota_test.json +19 -0
- certificate/tests/cloud_connectivity/brg_ota_test/brg_ota_test.py +41 -0
- certificate/tests/cloud_connectivity/channel_scan_behaviour_test/channel_scan_behaviour_test.json +19 -0
- certificate/tests/cloud_connectivity/channel_scan_behaviour_test/channel_scan_behaviour_test.py +215 -0
- certificate/tests/cloud_connectivity/connection_test/connection_test.json +18 -0
- certificate/tests/cloud_connectivity/connection_test/connection_test.py +67 -0
- certificate/tests/cloud_connectivity/deduplication_test/deduplication_test.json +15 -0
- certificate/tests/cloud_connectivity/deduplication_test/deduplication_test.py +80 -0
- certificate/tests/cloud_connectivity/downlink_test/downlink_test.json +21 -0
- certificate/tests/cloud_connectivity/downlink_test/downlink_test.py +201 -0
- certificate/tests/cloud_connectivity/ext_adv_stress_test/ext_adv_stress_test.json +17 -0
- certificate/tests/cloud_connectivity/ext_adv_stress_test/ext_adv_stress_test.py +104 -0
- certificate/tests/cloud_connectivity/reboot_test/reboot_test.json +18 -0
- certificate/tests/cloud_connectivity/reboot_test/reboot_test.py +59 -0
- certificate/tests/cloud_connectivity/registration_test/registration_test.json +20 -0
- certificate/tests/cloud_connectivity/registration_test/registration_test.py +384 -0
- certificate/tests/cloud_connectivity/registration_test/registration_test_cli.py +90 -0
- certificate/tests/cloud_connectivity/stress_test/stress_test.json +17 -0
- certificate/tests/cloud_connectivity/stress_test/stress_test.py +101 -0
- certificate/tests/cloud_connectivity/uplink_ext_adv_test/uplink_ext_adv_test.json +25 -0
- certificate/tests/cloud_connectivity/uplink_ext_adv_test/uplink_ext_adv_test.py +92 -0
- certificate/tests/cloud_connectivity/uplink_test/uplink_test.json +20 -0
- certificate/tests/cloud_connectivity/uplink_test/uplink_test.py +169 -0
- {brg_certificate → certificate}/tests/datapath/aging_test/aging_test.json +2 -1
- certificate/tests/datapath/aging_test/aging_test.py +142 -0
- certificate/tests/datapath/event_ble5_test/event_ble5_test.json +17 -0
- certificate/tests/datapath/event_ble5_test/event_ble5_test.py +89 -0
- certificate/tests/datapath/event_test/event_test.json +17 -0
- certificate/tests/datapath/event_test/event_test.py +80 -0
- {brg_certificate → certificate}/tests/datapath/num_of_tags_test/num_of_tags_test.json +4 -3
- {brg_certificate → certificate}/tests/datapath/num_of_tags_test/num_of_tags_test.py +19 -13
- certificate/tests/datapath/output_power_test/output_power_test.json +23 -0
- {brg_certificate → certificate}/tests/datapath/output_power_test/output_power_test.py +17 -6
- {brg_certificate → certificate}/tests/datapath/pacer_interval_ble5_test/pacer_interval_ble5_test.json +2 -1
- {brg_certificate → certificate}/tests/datapath/pacer_interval_ble5_test/pacer_interval_ble5_test.py +13 -11
- {brg_certificate → certificate}/tests/datapath/pacer_interval_test/pacer_interval_test.json +2 -1
- {brg_certificate → certificate}/tests/datapath/pacer_interval_test/pacer_interval_test.py +9 -7
- {brg_certificate → certificate}/tests/datapath/pattern_test/pattern_test.json +3 -2
- {brg_certificate → certificate}/tests/datapath/pattern_test/pattern_test.py +18 -6
- certificate/tests/datapath/pkt_filter_ble5_chl21_test/pkt_filter_ble5_chl21_test.json +20 -0
- certificate/tests/datapath/pkt_filter_ble5_chl21_test/pkt_filter_ble5_chl21_test.py +61 -0
- {brg_certificate → certificate}/tests/datapath/pkt_filter_ble5_test/pkt_filter_ble5_test.json +2 -1
- {brg_certificate → certificate}/tests/datapath/pkt_filter_ble5_test/pkt_filter_ble5_test.py +15 -14
- certificate/tests/datapath/pkt_filter_brg2gw_ext_adv_test/pkt_filter_brg2gw_ext_adv_test.json +19 -0
- certificate/tests/datapath/pkt_filter_brg2gw_ext_adv_test/pkt_filter_brg2gw_ext_adv_test.py +85 -0
- {brg_certificate → certificate}/tests/datapath/pkt_filter_gen3_test/pkt_filter_gen3_test.json +2 -1
- {brg_certificate → certificate}/tests/datapath/pkt_filter_gen3_test/pkt_filter_gen3_test.py +10 -9
- {brg_certificate → certificate}/tests/datapath/pkt_filter_test/pkt_filter_test.json +2 -1
- {brg_certificate → certificate}/tests/datapath/pkt_filter_test/pkt_filter_test.py +10 -9
- {brg_certificate → certificate}/tests/datapath/rssi_threshold_test/rssi_threshold_test.json +3 -2
- {brg_certificate → certificate}/tests/datapath/rssi_threshold_test/rssi_threshold_test.py +9 -8
- brg_certificate/tests/datapath/output_power_test/output_power_test.json → certificate/tests/datapath/rx_channel_hopping_test/rx_channel_hopping_test.json +6 -4
- certificate/tests/datapath/rx_channel_hopping_test/rx_channel_hopping_test.py +77 -0
- {brg_certificate → certificate}/tests/datapath/rx_channel_test/rx_channel_test.json +3 -2
- {brg_certificate → certificate}/tests/datapath/rx_channel_test/rx_channel_test.py +7 -6
- {brg_certificate → certificate}/tests/datapath/rx_rate_gen2_test/rx_rate_gen2_test.json +8 -7
- {brg_certificate → certificate}/tests/datapath/rx_rate_gen2_test/rx_rate_gen2_test.py +113 -73
- {brg_certificate → certificate}/tests/datapath/rx_rate_gen3_test/rx_rate_gen3_test.json +8 -7
- {brg_certificate → certificate}/tests/datapath/rx_rate_gen3_test/rx_rate_gen3_test.py +112 -72
- {brg_certificate → certificate}/tests/datapath/stress_gen3_test/stress_gen3_test.json +4 -3
- {brg_certificate → certificate}/tests/datapath/stress_gen3_test/stress_gen3_test.py +15 -11
- {brg_certificate → certificate}/tests/datapath/stress_test/stress_test.json +4 -3
- {brg_certificate → certificate}/tests/datapath/stress_test/stress_test.py +15 -11
- {brg_certificate → certificate}/tests/datapath/tx_repetition_test/tx_repetition_test.json +3 -1
- {brg_certificate → certificate}/tests/datapath/tx_repetition_test/tx_repetition_test.py +14 -13
- certificate/tests/edge_mgmt/action_blink_test/action_blink_test.json +15 -0
- certificate/tests/edge_mgmt/action_blink_test/action_blink_test.py +24 -0
- certificate/tests/edge_mgmt/action_get_battery_sensor_test/action_get_battery_sensor_test.json +15 -0
- certificate/tests/edge_mgmt/action_get_battery_sensor_test/action_get_battery_sensor_test.py +43 -0
- certificate/tests/edge_mgmt/action_get_module_test/action_get_module_test.json +15 -0
- certificate/tests/edge_mgmt/action_get_module_test/action_get_module_test.py +42 -0
- certificate/tests/edge_mgmt/action_get_pof_data_test/action_get_pof_data_test.json +15 -0
- certificate/tests/edge_mgmt/action_get_pof_data_test/action_get_pof_data_test.py +44 -0
- certificate/tests/edge_mgmt/action_gw_hb_test/action_gw_hb_test.json +16 -0
- certificate/tests/edge_mgmt/action_gw_hb_test/action_gw_hb_test.py +42 -0
- certificate/tests/edge_mgmt/action_reboot_test/action_reboot_test.json +15 -0
- certificate/tests/edge_mgmt/action_reboot_test/action_reboot_test.py +49 -0
- certificate/tests/edge_mgmt/action_restore_defaults_test/action_restore_defaults_test.json +15 -0
- certificate/tests/edge_mgmt/action_restore_defaults_test/action_restore_defaults_test.py +102 -0
- certificate/tests/edge_mgmt/action_send_hb_test/action_send_hb_test.json +15 -0
- certificate/tests/edge_mgmt/action_send_hb_test/action_send_hb_test.py +45 -0
- {brg_certificate → certificate}/tests/edge_mgmt/periodic_msgs_test/periodic_msgs_test.json +3 -2
- {brg_certificate → certificate}/tests/edge_mgmt/periodic_msgs_test/periodic_msgs_test.py +22 -11
- {brg_certificate → certificate}/tests/energy2400/duty_cycle_test/duty_cycle_test.json +2 -1
- {brg_certificate → certificate}/tests/energy2400/duty_cycle_test/duty_cycle_test.py +7 -6
- certificate/tests/energy2400/output_power_test/output_power_test.json +23 -0
- {brg_certificate → certificate}/tests/energy2400/output_power_test/output_power_test.py +17 -6
- {brg_certificate → certificate}/tests/energy2400/pattern_test/pattern_test.json +2 -1
- {brg_certificate → certificate}/tests/energy2400/pattern_test/pattern_test.py +7 -6
- certificate/tests/energy2400/signal_indicator_ble5_test/signal_indicator_ble5_test.json +26 -0
- certificate/tests/energy2400/signal_indicator_ble5_test/signal_indicator_ble5_test.py +379 -0
- certificate/tests/energy2400/signal_indicator_ext_adv_test/signal_indicator_ext_adv_test.json +20 -0
- certificate/tests/energy2400/signal_indicator_ext_adv_test/signal_indicator_ext_adv_test.py +173 -0
- certificate/tests/energy2400/signal_indicator_test/signal_indicator_test.json +24 -0
- certificate/tests/energy2400/signal_indicator_test/signal_indicator_test.py +350 -0
- {brg_certificate → certificate}/tests/energy_sub1g/duty_cycle_test/duty_cycle_test.json +2 -1
- {brg_certificate → certificate}/tests/energy_sub1g/duty_cycle_test/duty_cycle_test.py +7 -6
- {brg_certificate → certificate}/tests/energy_sub1g/pattern_test/pattern_test.json +2 -1
- {brg_certificate → certificate}/tests/energy_sub1g/pattern_test/pattern_test.py +7 -6
- {brg_certificate → certificate}/tests/pwr_mgmt/pwr_mgmt_test/pwr_mgmt_test.json +2 -1
- {brg_certificate → certificate}/tests/pwr_mgmt/pwr_mgmt_test/pwr_mgmt_test.py +10 -10
- {brg_certificate → certificate}/tests/sensors/ext_sensor_test/ext_sensor_test.json +5 -4
- certificate/tests/sensors/ext_sensor_test/ext_sensor_test.py +450 -0
- certificate/wlt_types.py +122 -0
- {gw_certificate → common}/api_if/202/status.json +6 -0
- {gw_certificate → common}/api_if/203/status.json +6 -0
- {gw_certificate → common}/api_if/204/status.json +6 -0
- common/api_if/206/data.json +85 -0
- common/api_if/206/status.json +69 -0
- common/api_if/api_validation.py +91 -0
- common/web/templates/generator.html +210 -0
- common/web/templates/index.html +20 -0
- common/web/templates/menu.html +54 -0
- common/web/templates/parser.html +53 -0
- {brg_certificate/ag → common/web/templates}/wlt_types.html +1216 -191
- common/web/web_utils.py +399 -0
- {brg_certificate → common}/wltPb_pb2.py +14 -12
- {gw_certificate/common → common}/wltPb_pb2.pyi +16 -2
- gui_certificate/gui_certificate_cli.py +14 -0
- gui_certificate/server.py +1267 -0
- gui_certificate/templates/cert_run.html +1273 -0
- wiliot_certificate-4.5.0.dist-info/METADATA +99 -0
- wiliot_certificate-4.5.0.dist-info/RECORD +168 -0
- {wiliot_certificate-4.4.2.dist-info → wiliot_certificate-4.5.0.dist-info}/WHEEL +1 -1
- wiliot_certificate-4.5.0.dist-info/entry_points.txt +5 -0
- wiliot_certificate-4.5.0.dist-info/top_level.txt +3 -0
- brg_certificate/ag/energous_v0_defines.py +0 -925
- brg_certificate/ag/energous_v1_defines.py +0 -931
- brg_certificate/ag/energous_v2_defines.py +0 -925
- brg_certificate/ag/energous_v3_defines.py +0 -925
- brg_certificate/ag/energous_v4_defines.py +0 -925
- brg_certificate/ag/fanstel_lan_v0_defines.py +0 -925
- brg_certificate/ag/fanstel_lte_v0_defines.py +0 -925
- brg_certificate/ag/fanstel_wifi_v0_defines.py +0 -925
- brg_certificate/ag/minew_lte_v0_defines.py +0 -925
- brg_certificate/ag/wlt_types_ag_jsons/brg2brg_ota.json +0 -142
- brg_certificate/ag/wlt_types_ag_jsons/brg2gw_hb.json +0 -785
- brg_certificate/ag/wlt_types_ag_jsons/brg2gw_hb_sleep.json +0 -139
- brg_certificate/ag/wlt_types_ag_jsons/calibration.json +0 -394
- brg_certificate/ag/wlt_types_ag_jsons/custom.json +0 -515
- brg_certificate/ag/wlt_types_ag_jsons/datapath.json +0 -672
- brg_certificate/ag/wlt_types_ag_jsons/energy2400.json +0 -550
- brg_certificate/ag/wlt_types_ag_jsons/energySub1g.json +0 -595
- brg_certificate/ag/wlt_types_ag_jsons/externalSensor.json +0 -598
- brg_certificate/ag/wlt_types_ag_jsons/interface.json +0 -938
- brg_certificate/ag/wlt_types_ag_jsons/powerManagement.json +0 -1234
- brg_certificate/ag/wlt_types_ag_jsons/side_info_sensor.json +0 -105
- brg_certificate/ag/wlt_types_ag_jsons/signal_indicator_data.json +0 -77
- brg_certificate/ag/wlt_types_ag_jsons/unified_echo_ext_pkt.json +0 -61
- brg_certificate/ag/wlt_types_ag_jsons/unified_echo_pkt.json +0 -110
- brg_certificate/brg_certificate.py +0 -225
- brg_certificate/brg_certificate_cli.py +0 -63
- brg_certificate/cert_common.py +0 -923
- brg_certificate/cert_config.py +0 -402
- brg_certificate/cert_utils.py +0 -362
- brg_certificate/certificate_bcc_sanity_test_list.txt +0 -40
- brg_certificate/certificate_bcc_test_list.txt +0 -48
- brg_certificate/certificate_sanity_test_list.txt +0 -43
- brg_certificate/certificate_test_list.txt +0 -53
- brg_certificate/config/eclipse.json +0 -10
- brg_certificate/config/hivemq.json +0 -10
- brg_certificate/config/mosquitto.json +0 -10
- brg_certificate/config/mosquitto.md +0 -95
- brg_certificate/config/wiliot-dev.json +0 -10
- brg_certificate/restore_brg.py +0 -61
- brg_certificate/tests/calibration/output_power_test/output_power_test.json +0 -16
- brg_certificate/tests/calibration/output_power_test/output_power_test.py +0 -28
- brg_certificate/tests/datapath/aging_test/aging_test.py +0 -143
- brg_certificate/tests/datapath/pacer_interval_tags_count_test/pacer_interval_tags_count_test.json +0 -16
- brg_certificate/tests/datapath/pacer_interval_tags_count_test/pacer_interval_tags_count_test.py +0 -73
- brg_certificate/tests/datapath/tx_repetition_algo_test/tx_repetition_algo_test.json +0 -17
- brg_certificate/tests/datapath/tx_repetition_algo_test/tx_repetition_algo_test.py +0 -118
- brg_certificate/tests/edge_mgmt/actions_test/actions_test.json +0 -14
- brg_certificate/tests/edge_mgmt/actions_test/actions_test.py +0 -396
- brg_certificate/tests/edge_mgmt/brg2brg_ota_ble5_test/brg2brg_ota_ble5_test.json +0 -20
- brg_certificate/tests/edge_mgmt/brg2brg_ota_ble5_test/brg2brg_ota_ble5_test.py +0 -94
- brg_certificate/tests/edge_mgmt/brg2brg_ota_test/brg2brg_ota_test.json +0 -19
- brg_certificate/tests/edge_mgmt/brg2brg_ota_test/brg2brg_ota_test.py +0 -87
- brg_certificate/tests/edge_mgmt/leds_test/leds_test.json +0 -17
- brg_certificate/tests/edge_mgmt/leds_test/leds_test.py +0 -223
- brg_certificate/tests/edge_mgmt/ota_test/ota_test.json +0 -17
- brg_certificate/tests/edge_mgmt/ota_test/ota_test.py +0 -128
- brg_certificate/tests/energy2400/output_power_test/output_power_test.json +0 -16
- brg_certificate/tests/energy2400/signal_indicator_ble5_10_250k_test/signal_indicator_ble5_10_250k_test.json +0 -20
- brg_certificate/tests/energy2400/signal_indicator_ble5_10_250k_test/signal_indicator_ble5_10_250k_test.py +0 -321
- brg_certificate/tests/energy2400/signal_indicator_ble5_10_500k_test/signal_indicator_ble5_10_500k_test.json +0 -20
- brg_certificate/tests/energy2400/signal_indicator_ble5_10_500k_test/signal_indicator_ble5_10_500k_test.py +0 -321
- brg_certificate/tests/energy2400/signal_indicator_sub1g_2_4_test/signal_indicator_sub1g_2_4_test.json +0 -20
- brg_certificate/tests/energy2400/signal_indicator_sub1g_2_4_test/signal_indicator_sub1g_2_4_test.py +0 -141
- brg_certificate/tests/energy2400/signal_indicator_test/signal_indicator_test.json +0 -20
- brg_certificate/tests/energy2400/signal_indicator_test/signal_indicator_test.py +0 -276
- brg_certificate/tests/energy_sub1g/signal_indicator_functionality_test/signal_indicator_functionality_test.json +0 -20
- brg_certificate/tests/energy_sub1g/signal_indicator_functionality_test/signal_indicator_functionality_test.py +0 -390
- brg_certificate/tests/energy_sub1g/signal_indicator_test/signal_indicator_test.json +0 -16
- brg_certificate/tests/energy_sub1g/signal_indicator_test/signal_indicator_test.py +0 -28
- brg_certificate/tests/sensors/ext_sensor_test/ext_sensor_test.py +0 -305
- brg_certificate/wltPb_pb2.pyi +0 -234
- brg_certificate/wlt_types.py +0 -113
- gw_certificate/ag/ut_defines.py +0 -364
- gw_certificate/ag/wlt_types.py +0 -85
- gw_certificate/ag/wlt_types_ag.py +0 -5310
- gw_certificate/ag/wlt_types_data.py +0 -64
- gw_certificate/api/extended_api.py +0 -23
- gw_certificate/api_if/200/data.json +0 -106
- gw_certificate/api_if/200/status.json +0 -47
- gw_certificate/api_if/201/data.json +0 -98
- gw_certificate/api_if/201/status.json +0 -53
- gw_certificate/api_if/205/logs.json +0 -12
- gw_certificate/api_if/api_validation.py +0 -38
- gw_certificate/api_if/gw_capabilities.py +0 -54
- gw_certificate/cert_results.py +0 -145
- gw_certificate/common/analysis_data_bricks.py +0 -60
- gw_certificate/common/debug.py +0 -42
- gw_certificate/common/serialization_formatter.py +0 -93
- gw_certificate/common/utils.py +0 -8
- gw_certificate/common/utils_defines.py +0 -15
- gw_certificate/common/wltPb_pb2.py +0 -84
- gw_certificate/gw_certificate.py +0 -154
- gw_certificate/gw_certificate_cli.py +0 -87
- gw_certificate/interface/4.4.91_app.zip +0 -0
- gw_certificate/interface/4.4.91_sd_bl_app.zip +0 -0
- gw_certificate/interface/ble_simulator.py +0 -61
- gw_certificate/interface/ble_sniffer.py +0 -189
- gw_certificate/interface/flash_fw.py +0 -90
- gw_certificate/interface/if_defines.py +0 -36
- gw_certificate/interface/mqtt.py +0 -563
- gw_certificate/interface/nrfutil-linux +0 -0
- gw_certificate/interface/nrfutil-mac +0 -0
- gw_certificate/interface/nrfutil.exe +0 -0
- gw_certificate/interface/pkt_generator.py +0 -594
- gw_certificate/interface/uart_if.py +0 -236
- gw_certificate/interface/uart_ports.py +0 -20
- gw_certificate/templates/results.html +0 -241
- gw_certificate/templates/stage.html +0 -22
- gw_certificate/templates/table.html +0 -6
- gw_certificate/templates/test.html +0 -38
- gw_certificate/tests/__init__.py +0 -10
- gw_certificate/tests/actions.py +0 -289
- gw_certificate/tests/bad_crc_to_PER_quantization.csv +0 -51
- gw_certificate/tests/connection.py +0 -188
- gw_certificate/tests/downlink.py +0 -172
- gw_certificate/tests/generic.py +0 -238
- gw_certificate/tests/registration.py +0 -340
- gw_certificate/tests/static/__init__.py +0 -0
- gw_certificate/tests/static/connection_defines.py +0 -9
- gw_certificate/tests/static/downlink_defines.py +0 -9
- gw_certificate/tests/static/generated_packet_table.py +0 -195
- gw_certificate/tests/static/packet_table.csv +0 -10067
- gw_certificate/tests/static/references.py +0 -5
- gw_certificate/tests/static/uplink_defines.py +0 -14
- gw_certificate/tests/throughput.py +0 -240
- gw_certificate/tests/uplink.py +0 -853
- wiliot_certificate-4.4.2.dist-info/METADATA +0 -211
- wiliot_certificate-4.4.2.dist-info/RECORD +0 -210
- wiliot_certificate-4.4.2.dist-info/entry_points.txt +0 -3
- wiliot_certificate-4.4.2.dist-info/top_level.txt +0 -3
- {brg_certificate → certificate}/__init__.py +0 -0
- {gw_certificate → common}/api_if/202/data.json +0 -0
- {gw_certificate/api_if/200 → common/api_if/202}/logs.json +0 -0
- {gw_certificate → common}/api_if/203/data.json +0 -0
- {gw_certificate/api_if/201 → common/api_if/203}/logs.json +0 -0
- {gw_certificate → common}/api_if/204/data.json +0 -0
- {gw_certificate/api_if/202 → common/api_if/204}/logs.json +0 -0
- {gw_certificate → common}/api_if/205/data.json +0 -0
- {gw_certificate/api_if/203 → common/api_if/205}/logs.json +0 -0
- {gw_certificate → common}/api_if/205/status.json +0 -0
- {gw_certificate/api_if/204 → common/api_if/206}/logs.json +0 -0
- {gw_certificate → common/api_if}/__init__.py +0 -0
- {gw_certificate/api_if → gui_certificate}/__init__.py +0 -0
- {wiliot_certificate-4.4.2.dist-info → wiliot_certificate-4.5.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,1488 @@
|
|
|
1
|
+
from certificate.cert_prints import *
|
|
2
|
+
from certificate.cert_defines import *
|
|
3
|
+
from certificate.wlt_types import *
|
|
4
|
+
import certificate.cert_utils as cert_utils
|
|
5
|
+
import certificate.cert_config as cert_config
|
|
6
|
+
import certificate.cert_mqtt as cert_mqtt
|
|
7
|
+
import certificate.cert_data_sim as cert_data_sim
|
|
8
|
+
import datetime
|
|
9
|
+
# from ut_te import ut_rtsa
|
|
10
|
+
import pandas as pd
|
|
11
|
+
import os
|
|
12
|
+
import plotly.express as px
|
|
13
|
+
import math, random
|
|
14
|
+
|
|
15
|
+
DEFAULT_HDR = ag.Hdr(group_id=ag.GROUP_ID_GW2BRG)
|
|
16
|
+
|
|
17
|
+
# Returns a 12 chars long hex string
|
|
18
|
+
int2mac_get = lambda int_val: f"{int_val:012X}"
|
|
19
|
+
|
|
20
|
+
# Returns a 12 chars long masked alias_id from hex string
|
|
21
|
+
STATIC_RANDOM_ADDR_MASK = 0xC00000000000
|
|
22
|
+
hex2alias_id_get = lambda id_str: int2mac_get(int(id_str, 16) | STATIC_RANDOM_ADDR_MASK)
|
|
23
|
+
|
|
24
|
+
# Returns True if running from PyPi package, else False
|
|
25
|
+
is_cert_running = lambda : not (CERT_VERSION == LOCAL_DEV)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def name_to_val(name):
|
|
29
|
+
return globals()[name]
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def test_prolog(test, flush_mqtt=True):
|
|
33
|
+
"""
|
|
34
|
+
kicks off the test:
|
|
35
|
+
- sets test start time
|
|
36
|
+
- checks to see if brg is DB for DB-only tests
|
|
37
|
+
- setups spectrum analyzer configuration if needed
|
|
38
|
+
|
|
39
|
+
:param WltTest test: test to be started
|
|
40
|
+
:return test: returns the test
|
|
41
|
+
"""
|
|
42
|
+
test.start_time = datetime.datetime.now()
|
|
43
|
+
|
|
44
|
+
test_run_print(test)
|
|
45
|
+
|
|
46
|
+
# Clean all exsisting mqtt's before starting
|
|
47
|
+
if flush_mqtt:
|
|
48
|
+
test.flush_all_mqtt_packets()
|
|
49
|
+
|
|
50
|
+
#TODO - remove/check status later on in the test
|
|
51
|
+
test.set_phase_rc(PRE_CONFIG, rc=test.rc)
|
|
52
|
+
test.add_phase_reason(PRE_CONFIG, reason=test.reason)
|
|
53
|
+
#
|
|
54
|
+
|
|
55
|
+
return test
|
|
56
|
+
|
|
57
|
+
def test_epilog(test, revert_brgs=False, revert_gws=False, modules=[], brg1_modules=[], ble5=False,
|
|
58
|
+
flush_mqtt=True):
|
|
59
|
+
"""
|
|
60
|
+
closes off the test:
|
|
61
|
+
- sets test end time and duration
|
|
62
|
+
- reverts gw/brgs/both to defaults
|
|
63
|
+
- prints test results
|
|
64
|
+
|
|
65
|
+
:param WltTest test: test to be finished
|
|
66
|
+
:param bool revert_brgs: reverts brgs to defaults (default ep and config), defaults to False
|
|
67
|
+
:param bool revert_gws: reverts gws to defaults (default config), defaults to False
|
|
68
|
+
:return test: returns the test
|
|
69
|
+
"""
|
|
70
|
+
# TODO - REMOVE when rc is re-designed
|
|
71
|
+
if test.get_phase_by_name(TEST_BODY):
|
|
72
|
+
test.set_phase_rc(TEST_BODY, test.rc)
|
|
73
|
+
test.add_phase_reason(TEST_BODY, test.reason)
|
|
74
|
+
|
|
75
|
+
test.reset_result()
|
|
76
|
+
test.set_phase_rc(RESTORE_CONFIG, TEST_PASSED)
|
|
77
|
+
|
|
78
|
+
if revert_brgs:
|
|
79
|
+
res2 = DONE
|
|
80
|
+
test, res = cert_config.config_brg_defaults(test, modules=modules, ble5=ble5)
|
|
81
|
+
# TODO - REMOVE when rc is re-designed
|
|
82
|
+
test.set_phase_rc(RESTORE_CONFIG, test.rc)
|
|
83
|
+
test.reset_result()
|
|
84
|
+
#
|
|
85
|
+
if test.brg1 and test.multi_brg:
|
|
86
|
+
brg1_modules = modules if not brg1_modules else brg1_modules
|
|
87
|
+
test, res2 = cert_config.config_brg_defaults(test, modules=brg1_modules, ble5=ble5, target=BRG1)
|
|
88
|
+
# TODO - REMOVE when rc is re-designed
|
|
89
|
+
test.set_phase_rc(RESTORE_CONFIG, test.rc)
|
|
90
|
+
test.reset_result()
|
|
91
|
+
#
|
|
92
|
+
if res == NO_RESPONSE or res2 == NO_RESPONSE:
|
|
93
|
+
txt = "Failed: Revert BRGs to defaults"
|
|
94
|
+
utPrint(txt, "RED")
|
|
95
|
+
test.add_phase_reason(RESTORE_CONFIG, txt)
|
|
96
|
+
|
|
97
|
+
if revert_gws:
|
|
98
|
+
test, res = cert_config.config_gw_defaults(test)
|
|
99
|
+
# TODO - REMOVE when rc is re-designed
|
|
100
|
+
test.set_phase_rc(RESTORE_CONFIG, test.rc)
|
|
101
|
+
test.reset_result()
|
|
102
|
+
#
|
|
103
|
+
if res == NO_RESPONSE:
|
|
104
|
+
txt = "Failed: Revert GW to defaults"
|
|
105
|
+
utPrint(txt, "RED")
|
|
106
|
+
test.add_phase_reason(RESTORE_CONFIG, txt)
|
|
107
|
+
if flush_mqtt:
|
|
108
|
+
test.flush_all_mqtt_packets()
|
|
109
|
+
test.end_time = datetime.datetime.now()
|
|
110
|
+
test.duration = str(test.end_time - test.start_time).split(".")[0]
|
|
111
|
+
|
|
112
|
+
# patch for nightly pipeline - as long as brg ver is updated, continue
|
|
113
|
+
if ("ota_test" in test.module_name and not "brg2brg" in test.module_name and
|
|
114
|
+
(BRG_VER_SUCCESS in test.get_phase_reason(TEST_BODY) or WANTED_VER_SAME in test.get_phase_reason(TEST_BODY))
|
|
115
|
+
and test.get_phase_rc(TEST_BODY) == TEST_FAILED):
|
|
116
|
+
print("Setting rc to TEST_PASSED for pipeline after BRG OTA succeeded")
|
|
117
|
+
test.set_phase_rc(TEST_BODY, TEST_PASSED)
|
|
118
|
+
test.set_phase_rc(RESTORE_CONFIG, TEST_PASSED)
|
|
119
|
+
|
|
120
|
+
test_epilog_print(test)
|
|
121
|
+
return test
|
|
122
|
+
|
|
123
|
+
def get_gw_versions(test, target=DUT):
|
|
124
|
+
"""
|
|
125
|
+
returns gw ble and wifi versions
|
|
126
|
+
|
|
127
|
+
:param WltTest test: test (with gw) to be checked
|
|
128
|
+
:return dict[str, str]: dictionary with BLE_VERSION and WIFI_VERSION
|
|
129
|
+
"""
|
|
130
|
+
mqttc = test.get_mqttc_by_target(target)
|
|
131
|
+
mqttc.flush_pkts()
|
|
132
|
+
cert_config.gw_info_action(test)
|
|
133
|
+
found = False
|
|
134
|
+
gw_ble_version, gw_wifi_version = "", ""
|
|
135
|
+
start_time = datetime.datetime.now()
|
|
136
|
+
while not found:
|
|
137
|
+
for p in cert_mqtt.get_all_status_pkts(mqttc):
|
|
138
|
+
if GW_INFO in p:
|
|
139
|
+
print("Config pkts:")
|
|
140
|
+
print_pkt(p)
|
|
141
|
+
if test.tester.protobuf:
|
|
142
|
+
gw_ble_version = p[GW_INFO][ENTRIES][BLE_VERSION][STR_VAL]
|
|
143
|
+
gw_wifi_version = p[GW_INFO][ENTRIES][WIFI_VERSION][STR_VAL]
|
|
144
|
+
else:
|
|
145
|
+
gw_ble_version = p[GW_INFO][BLE_VERSION]
|
|
146
|
+
gw_wifi_version = p[GW_INFO][WIFI_VERSION]
|
|
147
|
+
print(f"current versions: wifi {gw_wifi_version} ble {gw_ble_version}")
|
|
148
|
+
found = True
|
|
149
|
+
print_update_wait()
|
|
150
|
+
if (datetime.datetime.now() - start_time).seconds > DEFAULT_GW_FIELD_UPDATE_TIMEOUT:
|
|
151
|
+
test.rc = TEST_FAILED
|
|
152
|
+
test.add_reason(f"{GW_INFO} not found after {DEFAULT_BRG_FIELD_UPDATE_TIMEOUT} seconds!")
|
|
153
|
+
break
|
|
154
|
+
return {BLE_VERSION:gw_ble_version, WIFI_VERSION:gw_wifi_version}
|
|
155
|
+
|
|
156
|
+
def get_gw_geolocation(test, target=DUT):
|
|
157
|
+
"""
|
|
158
|
+
returns gw latitude and longitude from a gw_info action
|
|
159
|
+
|
|
160
|
+
:param WltTest test: test (with gw) to be checked
|
|
161
|
+
:return dict[str, float]: dictionary with GW_LATITUDE and GW_LONGITUDE
|
|
162
|
+
"""
|
|
163
|
+
mqttc = test.get_mqttc_by_target(target)
|
|
164
|
+
mqttc.flush_pkts()
|
|
165
|
+
cert_config.gw_info_action(test)
|
|
166
|
+
found = False
|
|
167
|
+
gw_lat, gw_lng = 0.0, 0.0
|
|
168
|
+
start_time = datetime.datetime.now()
|
|
169
|
+
while not found:
|
|
170
|
+
for p in cert_mqtt.get_all_status_pkts(mqttc):
|
|
171
|
+
if GW_INFO in p:
|
|
172
|
+
print_pkt(p)
|
|
173
|
+
if test.protobuf:
|
|
174
|
+
gw_lat = p[GW_INFO][ENTRIES][GW_LATITUDE][NUM_VAL]
|
|
175
|
+
gw_lng = p[GW_INFO][ENTRIES][GW_LONGITUDE][NUM_VAL]
|
|
176
|
+
else:
|
|
177
|
+
gw_lat = p[GW_INFO][GW_LATITUDE]
|
|
178
|
+
gw_lng = p[GW_INFO][GW_LONGITUDE]
|
|
179
|
+
print(f"gw_lat:{gw_lat} \ngw_lng:{gw_lng}")
|
|
180
|
+
found = True
|
|
181
|
+
print_update_wait()
|
|
182
|
+
if (datetime.datetime.now() - start_time).seconds > DEFAULT_GW_FIELD_UPDATE_TIMEOUT:
|
|
183
|
+
test.rc = TEST_FAILED
|
|
184
|
+
test.add_reason(f"{GW_INFO} not found after {DEFAULT_BRG_FIELD_UPDATE_TIMEOUT} seconds!")
|
|
185
|
+
break
|
|
186
|
+
return test, {GW_LATITUDE:gw_lat, GW_LONGITUDE:gw_lng}
|
|
187
|
+
|
|
188
|
+
def get_gw_info(test, print=True, target=DUT):
|
|
189
|
+
"""
|
|
190
|
+
gets gw info json dict from a gw_info action
|
|
191
|
+
|
|
192
|
+
:param WltTest test: test with gw that it's info will be retreived
|
|
193
|
+
:return str/dict[str, str]: json info dict from an info pkt OR a NO_RESPONSE str
|
|
194
|
+
"""
|
|
195
|
+
gw = test.dut if target == DUT else test.tester
|
|
196
|
+
mqttc = test.get_mqttc_by_target(target)
|
|
197
|
+
mqttc.flush_pkts()
|
|
198
|
+
# Always send gw info in both JSON and protobuf
|
|
199
|
+
cert_config.gw_info_action(test, target=target)
|
|
200
|
+
gw.protobuf = not gw.protobuf
|
|
201
|
+
cert_config.gw_info_action(test, target=target)
|
|
202
|
+
gw.protobuf = not gw.protobuf
|
|
203
|
+
|
|
204
|
+
start_time = datetime.datetime.now()
|
|
205
|
+
while (datetime.datetime.now() - start_time).seconds < DEFAULT_GW_FIELD_UPDATE_TIMEOUT:
|
|
206
|
+
for p in cert_mqtt.get_all_status_pkts(mqttc):
|
|
207
|
+
if GW_INFO in p:
|
|
208
|
+
if print:
|
|
209
|
+
print_pkt(p)
|
|
210
|
+
return p
|
|
211
|
+
print_update_wait()
|
|
212
|
+
return NO_RESPONSE
|
|
213
|
+
|
|
214
|
+
def get_logs(test, target=DUT):
|
|
215
|
+
"""
|
|
216
|
+
gets logs info json dict from a gw_logs action
|
|
217
|
+
|
|
218
|
+
:param WltTest test: test with gw that it's info will be retreived
|
|
219
|
+
:return str/dict[str, str]: json info dict from an info pkt OR a NO_RESPONSE str
|
|
220
|
+
"""
|
|
221
|
+
mqttc = test.get_mqttc_by_target(target)
|
|
222
|
+
mqttc.flush_pkts()
|
|
223
|
+
cert_config.gw_logs_action(test)
|
|
224
|
+
start_time = datetime.datetime.now()
|
|
225
|
+
while (datetime.datetime.now() - start_time).seconds < DEFAULT_GW_FIELD_UPDATE_TIMEOUT:
|
|
226
|
+
for p in cert_mqtt.get_all_status_pkts(mqttc):
|
|
227
|
+
if GET_LOGS:
|
|
228
|
+
print_pkt(p)
|
|
229
|
+
return p
|
|
230
|
+
print_update_wait()
|
|
231
|
+
return NO_RESPONSE
|
|
232
|
+
|
|
233
|
+
def get_brg_cfg_pkts(test, last=False, cfg_info=False, target=DUT):
|
|
234
|
+
"""
|
|
235
|
+
gets brg cfg data pkts (payload)
|
|
236
|
+
|
|
237
|
+
:param WltTest test: test to be scanned (it's first brg is the default brg to be scanned for)
|
|
238
|
+
:param bool last: set to True to get only the last pkt caught, defaults to False
|
|
239
|
+
: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
|
|
240
|
+
: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
|
|
241
|
+
:param bool module: Indicates we look for a module pkt as ack for config change
|
|
242
|
+
:return str/list[str]: cfg pkts payloads list/last cfg pkt payload received
|
|
243
|
+
"""
|
|
244
|
+
pkts = []
|
|
245
|
+
msg_type = ag.BRG_MGMT_MSG_TYPE_CFG_SET
|
|
246
|
+
if cfg_info:
|
|
247
|
+
msg_type = ag.BRG_MGMT_MSG_TYPE_CFG_INFO
|
|
248
|
+
|
|
249
|
+
mqttc = test.get_mqttc_by_target(target)
|
|
250
|
+
brg = cert_config.get_brg_by_target(test, target)
|
|
251
|
+
for p in cert_mqtt.get_brg2gw_mgmt_pkts(mqttc, brg):
|
|
252
|
+
brg2gw_cfg = p[MGMT_PKT].pkt
|
|
253
|
+
if type(brg2gw_cfg).__name__ in [module.__name__ for module in brg.modules]:
|
|
254
|
+
if brg2gw_cfg.msg_type == msg_type:
|
|
255
|
+
pkts += [p[PAYLOAD]]
|
|
256
|
+
if pkts and last:
|
|
257
|
+
return pkts[-1]
|
|
258
|
+
return pkts
|
|
259
|
+
|
|
260
|
+
time_in_sec = lambda t : t.seconds + t.microseconds / 1000000
|
|
261
|
+
|
|
262
|
+
# Pandas DataFrame documentation: https://pandas.pydata.org/docs/reference/frame.html
|
|
263
|
+
|
|
264
|
+
def get_all_brg_pkts(test):
|
|
265
|
+
utPrint(f"Collecting all BRG pkts", "BLUE")
|
|
266
|
+
return cert_mqtt.get_unified_data_pkts(test, only_active_brg=True)
|
|
267
|
+
|
|
268
|
+
def get_all_brgs_pkts(test):
|
|
269
|
+
utPrint(f"Collecting all BRG pkts", "BLUE")
|
|
270
|
+
return cert_mqtt.get_unified_data_pkts(test, only_active_brg=False)
|
|
271
|
+
|
|
272
|
+
def get_pkts_data_frame(test, gw_data=False, brg_data=False, per_pkt_type=False):
|
|
273
|
+
pkts = []
|
|
274
|
+
tags_last_pkt_cntr = {}
|
|
275
|
+
tags_received_per_src = {}
|
|
276
|
+
tbc = None
|
|
277
|
+
nfpkt = None
|
|
278
|
+
event_flag = None
|
|
279
|
+
event_ctr = None
|
|
280
|
+
gw_pkts = 0
|
|
281
|
+
brg_pkts = 0
|
|
282
|
+
all_data = {TIMESTAMP:[],TAG_ID:[],SRC_ID:[],NFPKT:[],EVENT_CTR:[],EVENT_FLAG:[],TBC:[],PACKET_CNTR:[],PKT_CNTR_DIFF:[],CER:[],RSSI:[],BRG_LATENCY:[],PAYLOAD:[],SEQUENCE_ID:[],GW_ID:[], PACKET_TYPE:[]}
|
|
283
|
+
if gw_data:
|
|
284
|
+
pkts += cert_mqtt.get_internal_brg_unified_data_pkts(test)
|
|
285
|
+
if brg_data:
|
|
286
|
+
if test.brg1 and test.multi_brg:
|
|
287
|
+
pkts += get_all_brg_pkts(test)
|
|
288
|
+
test.active_brg = test.brg1
|
|
289
|
+
pkts += get_all_brg_pkts(test)
|
|
290
|
+
test.active_brg = test.dut.internal_brg if cert_config.is_gw(test.dut) else test.dut
|
|
291
|
+
else:
|
|
292
|
+
pkts += get_all_brg_pkts(test)
|
|
293
|
+
for p in pkts:
|
|
294
|
+
# Protection from pkts of type "test_mode" from old tags
|
|
295
|
+
if type(p[DECODED_DATA][PACKET_TYPE]) == str or p[DECODED_DATA][PACKET_TYPE] == None:
|
|
296
|
+
print(f"Skipped packet {p}")
|
|
297
|
+
continue
|
|
298
|
+
if per_pkt_type:
|
|
299
|
+
tag_id = p[DECODED_DATA][TAG_ID] + "_" + str(p[DECODED_DATA][PACKET_TYPE])
|
|
300
|
+
else:
|
|
301
|
+
tag_id = p[DECODED_DATA][TAG_ID]
|
|
302
|
+
|
|
303
|
+
if UNIFIED_PKT in p:
|
|
304
|
+
src_id = p[ALIAS_BRIDGE_ID]
|
|
305
|
+
rssi = p[UNIFIED_PKT].pkt.rssi
|
|
306
|
+
brg_latency = p[UNIFIED_PKT].pkt.brg_latency
|
|
307
|
+
if isinstance(p[UNIFIED_PKT].pkt, ag.UnifiedEchoPktV0):
|
|
308
|
+
nfpkt = p[UNIFIED_PKT].pkt.nfpkt
|
|
309
|
+
if isinstance(p[UNIFIED_PKT].pkt, ag.UnifiedEchoPktV1) or isinstance(p[UNIFIED_PKT].pkt, ag.UnifiedEchoExtPktV0):
|
|
310
|
+
tbc = p[UNIFIED_PKT].pkt.tbc
|
|
311
|
+
nfpkt = p[UNIFIED_PKT].pkt.nfpkt
|
|
312
|
+
if isinstance(p[UNIFIED_PKT].pkt, ag.UnifiedEchoPktV2) or isinstance(p[UNIFIED_PKT].pkt, ag.UnifiedEchoExtPktV1):
|
|
313
|
+
tbc = p[UNIFIED_PKT].pkt.tbc
|
|
314
|
+
event_flag = p[UNIFIED_PKT].pkt.event_flag
|
|
315
|
+
event_ctr = p[UNIFIED_PKT].pkt.event_ctr
|
|
316
|
+
|
|
317
|
+
all_data[TIMESTAMP] += [p[TIMESTAMP]]
|
|
318
|
+
all_data[TAG_ID] += [tag_id]
|
|
319
|
+
all_data[GW_ID] += [p[GW_ID]]
|
|
320
|
+
all_data[SRC_ID] += [src_id]
|
|
321
|
+
all_data[NFPKT] += [nfpkt]
|
|
322
|
+
all_data[TBC] += [tbc]
|
|
323
|
+
all_data[EVENT_FLAG] += [event_flag]
|
|
324
|
+
all_data[EVENT_CTR] += [event_ctr]
|
|
325
|
+
all_data[PACKET_CNTR] += [p[DECODED_DATA][PACKET_CNTR]]
|
|
326
|
+
all_data[RSSI] += [rssi]
|
|
327
|
+
all_data[BRG_LATENCY] += [brg_latency]
|
|
328
|
+
all_data[PAYLOAD] += [p[PAYLOAD]]
|
|
329
|
+
all_data[SEQUENCE_ID] += [p[SEQUENCE_ID]]
|
|
330
|
+
all_data[PACKET_TYPE] += [p[DECODED_DATA][PACKET_TYPE]]
|
|
331
|
+
|
|
332
|
+
# handling pkt_cntr_diff
|
|
333
|
+
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
|
|
334
|
+
all_data[PKT_CNTR_DIFF] += [pkt_cntr_diff]
|
|
335
|
+
cer = 1-(nfpkt/pkt_cntr_diff) if (pkt_cntr_diff and nfpkt != None) else None
|
|
336
|
+
all_data[CER] += [cer]
|
|
337
|
+
|
|
338
|
+
# saving last pkt_cntr per tag
|
|
339
|
+
tags_last_pkt_cntr[tag_id] = p[DECODED_DATA][PACKET_CNTR]
|
|
340
|
+
|
|
341
|
+
# saving all srcs a tag was received from
|
|
342
|
+
if tag_id and src_id:
|
|
343
|
+
if tag_id not in tags_received_per_src:
|
|
344
|
+
tags_received_per_src[tag_id] = [src_id]
|
|
345
|
+
elif not src_id in tags_received_per_src[tag_id]:
|
|
346
|
+
tags_received_per_src[tag_id] += [src_id]
|
|
347
|
+
|
|
348
|
+
if gw_data:
|
|
349
|
+
if src_id == test.internal_id_alias():
|
|
350
|
+
gw_pkts += 1
|
|
351
|
+
if brg_data:
|
|
352
|
+
if src_id != test.internal_id_alias():
|
|
353
|
+
brg_pkts += 1
|
|
354
|
+
|
|
355
|
+
if gw_data:
|
|
356
|
+
print(f"Found {gw_pkts} gw_tags_pkts")
|
|
357
|
+
if brg_data:
|
|
358
|
+
print(f"Found {brg_pkts} brg_tags_pkts")
|
|
359
|
+
|
|
360
|
+
df = pd.DataFrame.from_dict(all_data)
|
|
361
|
+
df = df.sort_values(by=TIMESTAMP)
|
|
362
|
+
return df
|
|
363
|
+
|
|
364
|
+
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, target=DUT):
|
|
365
|
+
# MQTT scan
|
|
366
|
+
mqttc = test.get_mqttc_by_target(target)
|
|
367
|
+
if flush_pkts:
|
|
368
|
+
mqttc.flush_pkts()
|
|
369
|
+
start_time = datetime.datetime.now()
|
|
370
|
+
if scan_time:
|
|
371
|
+
mqtt_scan_start(test, scan_time)
|
|
372
|
+
chars = ["|", "/", "-", "\\"]
|
|
373
|
+
start_time = datetime.datetime.now()
|
|
374
|
+
i = 0
|
|
375
|
+
while not test.rc:
|
|
376
|
+
cur_duration = (datetime.datetime.now() - start_time).seconds
|
|
377
|
+
if cur_duration >= scan_time:
|
|
378
|
+
break
|
|
379
|
+
if pipeline_running():
|
|
380
|
+
sys.stdout.write(".")
|
|
381
|
+
else:
|
|
382
|
+
sys.stdout.write("\r"+chars[i%4]*20+" "+str(cur_duration)+" "+chars[i%4]*20+" {} pkts captured".format(len(cert_mqtt.get_all_data_pkts(mqttc))))
|
|
383
|
+
sys.stdout.flush()
|
|
384
|
+
time.sleep(0.25)
|
|
385
|
+
i += 1
|
|
386
|
+
print("\n")
|
|
387
|
+
|
|
388
|
+
if per_pkt_type:
|
|
389
|
+
cert_mqtt.dump_pkts(test, log=str(pkt_filter_cfg))
|
|
390
|
+
if pkt_filter_cfg == ag.PKT_FILTER_RANDOM_FIRST_ARRIVING_PKT:
|
|
391
|
+
# When PKT_FILTER_RANDOM_FIRST_ARRIVING_PKT we don't want to split the tags to be per pkt_type
|
|
392
|
+
per_pkt_type = False
|
|
393
|
+
df = get_pkts_data_frame(test, gw_data=gw_data, brg_data=brg_data, per_pkt_type=per_pkt_type)
|
|
394
|
+
if not df.empty:
|
|
395
|
+
df['gw_id'] = test.internal_id_alias()
|
|
396
|
+
if first_pkt_is_start_time:
|
|
397
|
+
start_time = min(df[TIMESTAMP])
|
|
398
|
+
df[TIMESTAMP_DELTA] = (df[TIMESTAMP]- start_time) / 1000
|
|
399
|
+
else:
|
|
400
|
+
df[TIMESTAMP_DELTA] = (df[TIMESTAMP] / 1000) - start_time.timestamp()
|
|
401
|
+
return df
|
|
402
|
+
|
|
403
|
+
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, ext_adv_brg2gw=False,
|
|
404
|
+
event_time_unit=ag.BRG_DEFAULT_EVENT_TIME_UNIT, phase=""):
|
|
405
|
+
ROUND = 3
|
|
406
|
+
|
|
407
|
+
# Validate pkts amount
|
|
408
|
+
if df[TAG_ID].nunique() == 0:
|
|
409
|
+
if pkt_filter_cfg == ag.PKT_FILTER_DISABLE_FORWARDING:
|
|
410
|
+
print("Packets echo disabled and no packets were found accordingly")
|
|
411
|
+
else:
|
|
412
|
+
test.rc = TEST_FAILED
|
|
413
|
+
test.add_reason("No packets found!\nMake sure you have an energizing BRG around you.")
|
|
414
|
+
print(test.reason)
|
|
415
|
+
return test
|
|
416
|
+
elif pkt_filter_cfg == ag.PKT_FILTER_DISABLE_FORWARDING:
|
|
417
|
+
test.rc = TEST_FAILED
|
|
418
|
+
test.add_reason("Packets were found while packets echo is turned off!")
|
|
419
|
+
print(test.reason)
|
|
420
|
+
return test
|
|
421
|
+
|
|
422
|
+
# Verify received pkt types are correct when cfg is not PKT_FILTER_RANDOM_FIRST_ARRIVING_PKT
|
|
423
|
+
if pkt_filter_cfg != ag.PKT_FILTER_RANDOM_FIRST_ARRIVING_PKT:
|
|
424
|
+
for pkt_type in list(df[PACKET_TYPE].unique()):
|
|
425
|
+
if ((pkt_filter_cfg & (1 << pkt_type)) == 0
|
|
426
|
+
and not (is_ble5_test and (test.internal_brg or test.dut_is_combo() or ext_adv_brg2gw) and pkt_type == ag.PKT_TYPE_BLE5_EXTENDED_TEMP_ADVANCED)):
|
|
427
|
+
test.rc = TEST_FAILED
|
|
428
|
+
test.add_reason(f"Tag is of packet type {pkt_type} which is turned off in packet_types_mask configuration!")
|
|
429
|
+
return test
|
|
430
|
+
|
|
431
|
+
# Verify the tags count according to simulation data and pkt_filter_cfg
|
|
432
|
+
tags_count = len(list(df[TAG_ID].unique()))
|
|
433
|
+
if test.data == DATA_SIMULATION and num_of_pixels:
|
|
434
|
+
if is_ble5_test and (test.dut_is_combo() or ext_adv_brg2gw):
|
|
435
|
+
# In ble5 bcc packet type 2 extended uploaded as is without splitting to ble4 packets
|
|
436
|
+
expected_tags_count = num_of_pixels
|
|
437
|
+
elif pkt_filter_cfg == ag.PKT_FILTER_TEMP_AND_ADVANCED_PKTS or pkt_filter_cfg == ag.PKT_FILTER_TEMP_AND_DEBUG_PKTS:
|
|
438
|
+
expected_tags_count = num_of_pixels * 2
|
|
439
|
+
elif pkt_filter_cfg == ag.PKT_FILTER_TEMP_ADVANCED_AND_DEBUG_PKTS:
|
|
440
|
+
expected_tags_count = num_of_pixels * 3
|
|
441
|
+
else:
|
|
442
|
+
expected_tags_count = num_of_pixels
|
|
443
|
+
if tags_count != expected_tags_count:
|
|
444
|
+
test.rc = TEST_FAILED
|
|
445
|
+
test.add_reason(f"Expected {expected_tags_count} pixels but found {tags_count}!")
|
|
446
|
+
print(test.reason)
|
|
447
|
+
return test
|
|
448
|
+
|
|
449
|
+
# verify there is no event flag when not event test
|
|
450
|
+
event_test = True if "event" in phase else False
|
|
451
|
+
if not event_test and (df['event_flag'] == 1).any():
|
|
452
|
+
test.rc = TEST_FAILED
|
|
453
|
+
print(f"Got event flag when not testing events!")
|
|
454
|
+
test.add_reason(f"Got event flag when not testing events!")
|
|
455
|
+
|
|
456
|
+
# Verify the tags event pacing
|
|
457
|
+
tag_event = True if "new_tag" not in phase else False
|
|
458
|
+
if event_test:
|
|
459
|
+
|
|
460
|
+
if event_time_unit == ag.EVENT_TIME_UNIT_SECONDS:
|
|
461
|
+
pacing_window = TEST_EVENT_WINDOW_SEC_CFG if not tag_event else TEST_TAG_EVENT_WINDOW_CFG
|
|
462
|
+
elif event_time_unit == ag.EVENT_TIME_UNIT_MINUTES:
|
|
463
|
+
pacing_window = TEST_EVENT_WINDOW_MIN_CFG * 60
|
|
464
|
+
elif event_time_unit == ag.EVENT_TIME_UNIT_HOURS:
|
|
465
|
+
pacing_window = TEST_EVENT_WINDOW_HR_CFG * 3600
|
|
466
|
+
|
|
467
|
+
# In seconds phase we also test the dynamic pacer interval
|
|
468
|
+
if "rssi" in phase:
|
|
469
|
+
event_pacing = DATA_SIM_RSSI_EVENT_TESTING_DELAY_SEC
|
|
470
|
+
elif "seconds" in phase:
|
|
471
|
+
event_pacing = DATA_SIM_EVENT_PACER_INTERVAL_TESTING
|
|
472
|
+
else:
|
|
473
|
+
event_pacing = DATA_SIM_EVENT_TESTING_DELAY_SEC
|
|
474
|
+
|
|
475
|
+
expected_event_pkt_count = math.ceil(pacing_window / event_pacing)
|
|
476
|
+
|
|
477
|
+
if "rssi" in phase:
|
|
478
|
+
if not test.sterile_run:
|
|
479
|
+
# In non-sterile runs - rssi is less stable and can trigger more events
|
|
480
|
+
max_count_threshold = float('inf')
|
|
481
|
+
else:
|
|
482
|
+
# In rssi movement events the alpha filter takes about 13 packets to stabilize
|
|
483
|
+
max_count_threshold = 1 + (RSSI_EVENT_PKTS_TO_STABILIZE / expected_event_pkt_count)
|
|
484
|
+
else:
|
|
485
|
+
max_count_threshold = PACER_INTERVAL_CEIL_THRESHOLD
|
|
486
|
+
|
|
487
|
+
for tag in list(df[TAG_ID].unique()):
|
|
488
|
+
event_pkts = df.query('tag_id == @tag and event_flag == 1')
|
|
489
|
+
avg_event_pacer = round(event_pkts.timestamp.diff().mean(skipna=True)/1000, ROUND)
|
|
490
|
+
|
|
491
|
+
if not (PACER_INTERVAL_THRESHOLD <= len(event_pkts) / expected_event_pkt_count <= max_count_threshold):
|
|
492
|
+
test.rc = TEST_FAILED
|
|
493
|
+
msg = f"Packet count for dynamic tag {tag} is wrong! expected_event_pkt_count = {expected_event_pkt_count}, received pkt count = {len(event_pkts)}"
|
|
494
|
+
test.add_reason(msg)
|
|
495
|
+
utPrint(msg, "RED")
|
|
496
|
+
if not (PACER_INTERVAL_THRESHOLD <= avg_event_pacer / event_pacing <= PACER_INTERVAL_CEIL_THRESHOLD):
|
|
497
|
+
test.rc = TEST_FAILED
|
|
498
|
+
msg = f"Tag {tag} has a wrong avg time diff. diff_time {list(event_pkts.timestamp.diff().div(1000))}, avg_event_pacer={avg_event_pacer} exceeds threshold!"
|
|
499
|
+
test.add_reason(msg)
|
|
500
|
+
utPrint(msg, "RED")
|
|
501
|
+
|
|
502
|
+
# Verify the tags pacer interval (without event)
|
|
503
|
+
failed_tags = 0
|
|
504
|
+
max_received_pkts = max([len(df.query('tag_id == @tag and event_flag == 0')) for tag in list(df[TAG_ID].unique())])
|
|
505
|
+
for tag in list(df[TAG_ID].unique()):
|
|
506
|
+
if tag_event:
|
|
507
|
+
# No need to test regular pacing in tag event test
|
|
508
|
+
break
|
|
509
|
+
pkts = df.query('tag_id == @tag and event_flag == 0')
|
|
510
|
+
avg_pacer = round(pkts.timestamp.diff().mean(skipna=True)/1000, ROUND)
|
|
511
|
+
print(f"Tag: {tag} avg_pacer={avg_pacer} num_of_pkts={len(pkts)}")
|
|
512
|
+
if ((avg_pacer / pacer_interval) < PACER_INTERVAL_THRESHOLD_HIGH and (pacer_interval - avg_pacer) > 1):
|
|
513
|
+
failed_tags += 1
|
|
514
|
+
test.rc = TEST_FAILED
|
|
515
|
+
msg = f"Tag {tag} with diff_time {list(pkts.timestamp.diff().div(1000))}, avg_pacer={avg_pacer} exceeds {PACER_INTERVAL_THRESHOLD_HIGH} minimum threshold!"
|
|
516
|
+
utPrint(msg, "RED")
|
|
517
|
+
test.add_reason(msg)
|
|
518
|
+
# Pass the test with real tags when less than 5% tag failed
|
|
519
|
+
if test.data != DATA_SIMULATION and failed_tags / tags_count < 0.05:
|
|
520
|
+
test.rc = TEST_PASSED
|
|
521
|
+
|
|
522
|
+
if test.data == DATA_SIMULATION and (avg_pacer / pacer_interval) > PACER_INTERVAL_CEIL_THRESHOLD:
|
|
523
|
+
if max_received_pkts == len(pkts):
|
|
524
|
+
# we fail the tag only if it received all expected pkts and pacer caluculation is valid
|
|
525
|
+
failed_tags += 1
|
|
526
|
+
msg = f"Tag {tag} with diff_time {list(pkts.timestamp.diff().div(1000))}, avg_pacer={avg_pacer} exceeds {PACER_INTERVAL_CEIL_THRESHOLD} maximum threshold!"
|
|
527
|
+
utPrint(msg, "RED")
|
|
528
|
+
test.add_reason(msg)
|
|
529
|
+
else:
|
|
530
|
+
print(f"Tag {tag} received only {len(pkts)} pkts out of {max_received_pkts}, avg_pacer failed but skipping pacer ceil validation")
|
|
531
|
+
if failed_tags / tags_count > 0.2: # Fail the test on ceil threshold only when more than 20% tag failed
|
|
532
|
+
test.reason = f"{failed_tags}/{tags_count} tags with wrong time diff"
|
|
533
|
+
test.rc = TEST_FAILED
|
|
534
|
+
|
|
535
|
+
return test
|
|
536
|
+
|
|
537
|
+
|
|
538
|
+
def brg2brg_ota_init(test, is_bl_ota=False):
|
|
539
|
+
|
|
540
|
+
VERSIONS_SAME = "Both bridges FW versions are the same!"
|
|
541
|
+
BL_VERSIONS_SAME = "Both bridges Bootloader versions are the same!"
|
|
542
|
+
BOARDS_MISMATCH = "Bridges are of different board types!"
|
|
543
|
+
|
|
544
|
+
# Initialize bridges
|
|
545
|
+
# TODO - REMOVE CERT_CONFIG IMPORT
|
|
546
|
+
brg0 = test.dut.internal_brg if cert_config.is_gw(test.dut) else test.dut
|
|
547
|
+
brg1 = test.brg1
|
|
548
|
+
|
|
549
|
+
# Protections from same version & different board types
|
|
550
|
+
if not is_bl_ota and brg0.version == brg1.version:
|
|
551
|
+
utPrint(VERSIONS_SAME, "RED")
|
|
552
|
+
test.rc = TEST_FAILED
|
|
553
|
+
test.add_reason(VERSIONS_SAME)
|
|
554
|
+
if is_bl_ota and brg0.bl_version == brg1.bl_version:
|
|
555
|
+
utPrint(BL_VERSIONS_SAME, "RED")
|
|
556
|
+
test.rc = TEST_FAILED
|
|
557
|
+
test.add_reason(BL_VERSIONS_SAME)
|
|
558
|
+
if brg0.board_type != brg1.board_type:
|
|
559
|
+
utPrint(BOARDS_MISMATCH, "RED")
|
|
560
|
+
test.rc = TEST_FAILED
|
|
561
|
+
test.add_reason(BOARDS_MISMATCH)
|
|
562
|
+
|
|
563
|
+
# Active bridge will be the source bridge
|
|
564
|
+
if is_bl_ota:
|
|
565
|
+
test.active_brg = brg0 if brg0.bl_version > brg1.bl_version else brg1
|
|
566
|
+
else:
|
|
567
|
+
test.active_brg = brg0 if brg0.version > brg1.version else brg1
|
|
568
|
+
|
|
569
|
+
return test
|
|
570
|
+
|
|
571
|
+
|
|
572
|
+
def send_brg2brg_ota_msg(test, src_brg, dest_brg, is_bl_ota=False, target=DUT):
|
|
573
|
+
|
|
574
|
+
utPrint(f"Source {"bootloader" if is_bl_ota else "firmware"} bridge version: {src_brg.bl_version if is_bl_ota else src_brg.version}. "
|
|
575
|
+
f"Destination bridge {"bootloader" if is_bl_ota else "firmware"} version: {dest_brg.bl_version if is_bl_ota else dest_brg.version}", "BLUE")
|
|
576
|
+
|
|
577
|
+
# Send BRG2BRG_OTA message to source bridge
|
|
578
|
+
functionality_run_print(f"BRG2BRG OTA - Source Bridge MAC: {src_brg.id_str}, Destination Bridge MAC: {dest_brg.id_str}")
|
|
579
|
+
brg2brg_ota_pkt = eval_pkt(f'Brg2BrgOtaV{test.active_brg.api_version}')(src_brg_mac=src_brg.id_int,
|
|
580
|
+
dest_brg_mac=dest_brg.id_int,
|
|
581
|
+
seq_id=test.get_seq_id(),
|
|
582
|
+
bootloader=is_bl_ota)
|
|
583
|
+
brg2brg_ota_pkt_downlink = WltPkt(hdr=ag.Hdr(group_id=ag.GROUP_ID_GW2BRG), pkt=brg2brg_ota_pkt)
|
|
584
|
+
# BRG OTA - Flush pkts ONLY before starting to avoid deletion of needed GW Logs
|
|
585
|
+
test.get_mqttc_by_target(target).flush_pkts()
|
|
586
|
+
cert_config.gw_downlink(test, raw_tx_data=brg2brg_ota_pkt_downlink.dump(), target=target)
|
|
587
|
+
|
|
588
|
+
# Get version of the destination bridge
|
|
589
|
+
test.active_brg = dest_brg
|
|
590
|
+
# expected_hash=1 due to different cfgs and versions between builds
|
|
591
|
+
test = reboot_config_analysis(test=test, expected_hash=1, ble_version=src_brg.version if not is_bl_ota else None,
|
|
592
|
+
bl_version=src_brg.bl_version if is_bl_ota else None, timeout=VER_UPDATE_TIMEOUT)
|
|
593
|
+
# Update back to original bridge version if test failed:
|
|
594
|
+
if test.rc == TEST_FAILED:
|
|
595
|
+
cert_config.brg_ota(test, ble_version=test.gw_orig_versions[BLE_VERSION], search_ack=False)
|
|
596
|
+
|
|
597
|
+
return test
|
|
598
|
+
|
|
599
|
+
|
|
600
|
+
def run_event_test_phase(test, phase, datapath_module, values, scan_time, event_time_unit, ble5_test=False,
|
|
601
|
+
pkt_filter_cfg=ag.PKT_FILTER_RANDOM_FIRST_ARRIVING_PKT):
|
|
602
|
+
# Generic runner for events tests
|
|
603
|
+
|
|
604
|
+
fields = [BRG_EVENT_TIME_UNIT, BRG_EVENT_WINDOW, BRG_RX_CHANNEL, BRG_EVENT_TRIGGER, BRG_EVENT_PACER_INTERVAL]
|
|
605
|
+
scan_time_multiplier = 1
|
|
606
|
+
delay = DATA_SIM_EVENT_TESTING_DELAY_MS
|
|
607
|
+
if "rssi" in phase:
|
|
608
|
+
test.sterile_run = is_quiet_setup_running()
|
|
609
|
+
delay = DATA_SIM_RSSI_EVENT_TESTING_DELAY_MS
|
|
610
|
+
scan_time_multiplier = (1 / 3)
|
|
611
|
+
fields += [BRG_RSSI_MOVEMENT_THRESHOLD]
|
|
612
|
+
|
|
613
|
+
ble5 = ble5_test and test.dut_is_bridge() # ble5 only for bridge dut (with combo we don't need to wait)
|
|
614
|
+
test = cert_config.brg_configure(test, fields=fields, values=values, module=datapath_module, ble5=ble5)[0]
|
|
615
|
+
test.set_phase_rc(phase, test.rc)
|
|
616
|
+
test.add_phase_reason(phase, test.reason)
|
|
617
|
+
if test.rc == TEST_FAILED and test.exit_on_param_failure:
|
|
618
|
+
return test
|
|
619
|
+
|
|
620
|
+
num_of_pixels = 0
|
|
621
|
+
if test.data == DATA_SIMULATION:
|
|
622
|
+
num_of_pixels = 1
|
|
623
|
+
if ble5_test:
|
|
624
|
+
pixel_sim_thread = cert_data_sim.DataSimThread(test=test, num_of_pixels=num_of_pixels, duplicates=6,
|
|
625
|
+
delay=delay, pkt_types=[2],
|
|
626
|
+
pixels_type=GEN3_EXTENDED)
|
|
627
|
+
else:
|
|
628
|
+
pixel_sim_thread = cert_data_sim.DataSimThread(test=test, num_of_pixels=num_of_pixels, duplicates=6,
|
|
629
|
+
delay=delay, pkt_types=[0],
|
|
630
|
+
pixels_type=GEN3)
|
|
631
|
+
pixel_sim_thread.start()
|
|
632
|
+
else:
|
|
633
|
+
test.rc = TEST_FAILED
|
|
634
|
+
warning_txt = "This test should be ran with data simulator!"
|
|
635
|
+
utPrint(warning_txt, "RED")
|
|
636
|
+
test.add_reason(warning_txt)
|
|
637
|
+
return test
|
|
638
|
+
|
|
639
|
+
df = data_scan(test, scan_time=scan_time * scan_time_multiplier, pkt_filter_cfg=pkt_filter_cfg, brg_data=(not test.internal_brg),
|
|
640
|
+
gw_data=test.internal_brg, per_pkt_type=True)
|
|
641
|
+
|
|
642
|
+
if "rssi" in phase:
|
|
643
|
+
# Configure data simulator to change output power for rssi change test
|
|
644
|
+
test = cert_config.brg_configure(test, module=datapath_module, fields=[BRG_OUTPUT_POWER, BRG_RX_CHANNEL], values=[ag.OUTPUT_POWER_2_4_MAX_MINUS_26], wait=False, target=TESTER)[0]
|
|
645
|
+
df_ext = data_scan(test, scan_time=scan_time * (1 - scan_time_multiplier), pkt_filter_cfg=pkt_filter_cfg, brg_data=(not test.internal_brg),
|
|
646
|
+
gw_data=test.internal_brg, per_pkt_type=True)
|
|
647
|
+
df = pd.concat([df, df_ext]).sort_values(by=TIMESTAMP)
|
|
648
|
+
test = cert_config.brg_configure(test, module=datapath_module, fields=[BRG_OUTPUT_POWER, BRG_RX_CHANNEL], values=[ag.BRG_DEFAULT_DATAPATH_OUTPUT_POWER], target=TESTER)[0]
|
|
649
|
+
|
|
650
|
+
if test.data == DATA_SIMULATION:
|
|
651
|
+
pixel_sim_thread.stop()
|
|
652
|
+
time.sleep(5)
|
|
653
|
+
|
|
654
|
+
cert_mqtt.dump_pkts(test, log=phase)
|
|
655
|
+
display_data(df, event_flag=True, event_ctr=True, name_prefix=f"{phase}_", dir=test.dir)
|
|
656
|
+
|
|
657
|
+
test = pacing_analysis(test, df=df, pkt_filter_cfg=pkt_filter_cfg, pacer_interval=ag.BRG_DEFAULT_PACER_INTERVAL,
|
|
658
|
+
num_of_pixels=num_of_pixels, event_time_unit=event_time_unit, is_ble5_test=ble5_test, phase=phase)
|
|
659
|
+
test.set_phase_rc(phase, test.rc)
|
|
660
|
+
test.add_phase_reason(phase, test.reason)
|
|
661
|
+
return test
|
|
662
|
+
|
|
663
|
+
def reboot_config_analysis(test, expected_hash, timeout=ACTION_LONG_TIMEOUT, ble_version=None, bl_version=None, target=DUT):
|
|
664
|
+
utPrint("Analyzing Reboot", "BLUE")
|
|
665
|
+
# start with a 5 sec wait time before searching interface to allow the BRG to reboot
|
|
666
|
+
time.sleep(5)
|
|
667
|
+
|
|
668
|
+
start_time = datetime.datetime.now()
|
|
669
|
+
seq_ids = []
|
|
670
|
+
found = {ag.MODULE_IF : False, ag.MODULE_DATAPATH: False}
|
|
671
|
+
received_hash = 0
|
|
672
|
+
mqttc = test.get_mqttc_by_target(target)
|
|
673
|
+
# Flush data pkts only to keep the GW logs which are in status topic
|
|
674
|
+
mqttc.flush_data_pkts()
|
|
675
|
+
|
|
676
|
+
while not all(found.values()):
|
|
677
|
+
# scan for ModuleIf and ModuleDatapath pkts of all api versions to support api version change on update
|
|
678
|
+
# ModuleDatapath arrival shows that the BLE really rebooted
|
|
679
|
+
if_pkts_list = [eval_pkt(f'ModuleIfV{i}') for i in range(ag.API_VERSION_V9, ag.API_VERSION_LATEST+1)]
|
|
680
|
+
datapath_pkts_list = [eval_pkt(f'ModuleDatapathV{i}') for i in range(ag.API_VERSION_V9, ag.API_VERSION_LATEST+1)]
|
|
681
|
+
pkts = cert_mqtt.get_brg2gw_mgmt_pkts(mqttc, test.active_brg, mgmt_types=if_pkts_list+datapath_pkts_list)
|
|
682
|
+
for p in pkts:
|
|
683
|
+
if p[SEQUENCE_ID] not in seq_ids:
|
|
684
|
+
seq_ids.append(p[SEQUENCE_ID])
|
|
685
|
+
module_pkt = p[MGMT_PKT].pkt
|
|
686
|
+
if not found[module_pkt.module_type]:
|
|
687
|
+
print("\nGot {} packet after {} sec!".format(type(module_pkt).__name__, (datetime.datetime.now() - start_time).seconds))
|
|
688
|
+
print(module_pkt)
|
|
689
|
+
if module_pkt.module_type == ag.MODULE_IF:
|
|
690
|
+
test.active_brg.api_version = module_pkt.api_version
|
|
691
|
+
print(f"received ModuleIfV{test.active_brg.api_version} pkt:")
|
|
692
|
+
# get received cfg_hash & expected cfg_hash
|
|
693
|
+
received_hash = module_pkt.cfg_hash
|
|
694
|
+
print(f"\nexpected cfg_hash: {hex(expected_hash)}")
|
|
695
|
+
print(f"received cfg_hash: {hex(received_hash)}")
|
|
696
|
+
# brg version update (OTA) analysis
|
|
697
|
+
if ble_version:
|
|
698
|
+
brg_version = f"{module_pkt.major_ver}.{module_pkt.minor_ver}.{module_pkt.patch_ver}"
|
|
699
|
+
print(f"\nBRG version: {brg_version}, expected version: {ble_version}")
|
|
700
|
+
# compare wanted version to received version
|
|
701
|
+
if brg_version == ble_version:
|
|
702
|
+
test.active_brg.version = brg_version
|
|
703
|
+
test.add_reason(BRG_VER_SUCCESS)
|
|
704
|
+
# ALSO compare received cfg_hash to expected cfg_hash
|
|
705
|
+
# expected_hash will be 1 if api_version was updated
|
|
706
|
+
if received_hash == expected_hash or expected_hash == 1:
|
|
707
|
+
found[module_pkt.module_type] = True
|
|
708
|
+
elif bl_version:
|
|
709
|
+
brg_bl_version = module_pkt.bl_version
|
|
710
|
+
print(f"\nBRG bootloader version: {brg_bl_version}, expected bootloader version: {bl_version}")
|
|
711
|
+
# compare wanted version to received version
|
|
712
|
+
if brg_bl_version == bl_version:
|
|
713
|
+
test.active_brg.bl_version = brg_bl_version
|
|
714
|
+
test.add_reason(BRG_BL_VER_SUCCESS)
|
|
715
|
+
found[module_pkt.module_type] = True
|
|
716
|
+
# analysis of any other reboot actions with no version update (relevant only for api version 8 or higher)
|
|
717
|
+
# compare received cfg_hash to expected cfg_hash
|
|
718
|
+
elif received_hash == expected_hash:
|
|
719
|
+
found[module_pkt.module_type] = True
|
|
720
|
+
else:
|
|
721
|
+
found[module_pkt.module_type] = True
|
|
722
|
+
print_update_wait()
|
|
723
|
+
|
|
724
|
+
if (datetime.datetime.now() - start_time).seconds > timeout:
|
|
725
|
+
test.rc = TEST_FAILED
|
|
726
|
+
unfound = [f'{ag.MODULES_DICT[m]}{test.active_brg.api_version}' for m in found if not found[m]]
|
|
727
|
+
test.add_reason(f"{unfound} not received in {timeout} sec.")
|
|
728
|
+
break
|
|
729
|
+
return test
|
|
730
|
+
|
|
731
|
+
def scan_for_mgmt_pkts(test, mgmt_type, target=DUT):
|
|
732
|
+
|
|
733
|
+
start_time = datetime.datetime.now()
|
|
734
|
+
# Search for module packets
|
|
735
|
+
found = False
|
|
736
|
+
ret_pkts = []
|
|
737
|
+
mqttc = test.get_mqttc_by_target(target)
|
|
738
|
+
while DEFAULT_BRG_FIELD_UPDATE_TIMEOUT > (datetime.datetime.now() - start_time).seconds:
|
|
739
|
+
print_update_wait()
|
|
740
|
+
pkts_collected = cert_mqtt.get_brg2gw_mgmt_pkts(mqttc, test.active_brg, mgmt_types=mgmt_type)
|
|
741
|
+
if pkts_collected:
|
|
742
|
+
seq_ids = []
|
|
743
|
+
for p in pkts_collected:
|
|
744
|
+
if seq_ids == [] or p[SEQUENCE_ID] not in seq_ids:
|
|
745
|
+
seq_ids.append(p[SEQUENCE_ID])
|
|
746
|
+
ret_pkts.append(p)
|
|
747
|
+
found = True
|
|
748
|
+
break
|
|
749
|
+
if not found:
|
|
750
|
+
test.rc = TEST_FAILED
|
|
751
|
+
error = f"Didn't receive {mgmt_type[0].__name__} pkt after {DEFAULT_BRG_FIELD_UPDATE_TIMEOUT} seconds!"
|
|
752
|
+
test.add_reason(error)
|
|
753
|
+
utPrint(error, "RED")
|
|
754
|
+
return test, ret_pkts
|
|
755
|
+
|
|
756
|
+
# Actions test functions
|
|
757
|
+
# modules should receive a list of module names to look for - identical to their actual classes' names!
|
|
758
|
+
def scan_for_modules(test, modules=[]):
|
|
759
|
+
modules = test.active_brg.modules if not modules else modules
|
|
760
|
+
found = {module.__name__: False for module in modules}
|
|
761
|
+
start_time = datetime.datetime.now()
|
|
762
|
+
|
|
763
|
+
# Search for packets
|
|
764
|
+
while not all(found.values()):
|
|
765
|
+
for module in found:
|
|
766
|
+
pkts = cert_mqtt.get_brg2gw_mgmt_pkts(
|
|
767
|
+
test.get_mqttc_by_target(DUT),
|
|
768
|
+
test.active_brg,
|
|
769
|
+
mgmt_types=[eval_pkt(module)],
|
|
770
|
+
)
|
|
771
|
+
if pkts and not found[module]:
|
|
772
|
+
found[module] = True
|
|
773
|
+
print("\nGot {} packet after {} sec!".format(module, (datetime.datetime.now() - start_time).seconds))
|
|
774
|
+
print(pkts[-1][MGMT_PKT].pkt)
|
|
775
|
+
print_update_wait()
|
|
776
|
+
if (datetime.datetime.now() - start_time).seconds > DEFAULT_BRG_FIELD_UPDATE_TIMEOUT:
|
|
777
|
+
test.rc = TEST_FAILED
|
|
778
|
+
err_print = ','.join([module for module, value in found.items() if not value])
|
|
779
|
+
test.add_reason("Didn't receive {} after {} seconds!".format(err_print, DEFAULT_BRG_FIELD_UPDATE_TIMEOUT))
|
|
780
|
+
break
|
|
781
|
+
return test
|
|
782
|
+
|
|
783
|
+
|
|
784
|
+
def search_action_ack(test, action_id, **kwargs):
|
|
785
|
+
test, mgmt_pkts = scan_for_mgmt_pkts(test, mgmt_type=[eval_pkt(f'{ag.ACTIONS_DICT[action_id]}{test.active_brg.api_version}')])
|
|
786
|
+
if test.rc == TEST_FAILED:
|
|
787
|
+
return test
|
|
788
|
+
print("\nReceived ACK pkts:")
|
|
789
|
+
for p in mgmt_pkts:
|
|
790
|
+
print(p[MGMT_PKT].pkt)
|
|
791
|
+
pkt = cert_config.get_default_brg_pkt(test,
|
|
792
|
+
pkt_type=eval_pkt(f'{ag.ACTIONS_DICT[action_id]}{test.active_brg.api_version}'),
|
|
793
|
+
**kwargs).pkt
|
|
794
|
+
if p[MGMT_PKT].pkt == pkt:
|
|
795
|
+
utPrint("Received ACK for action", "GREEN")
|
|
796
|
+
return test
|
|
797
|
+
test.rc = TEST_FAILED
|
|
798
|
+
test.add_reason(f"Didn't find action ACK for action id {action_id} {ag.ACTIONS_DICT[action_id]}")
|
|
799
|
+
return test
|
|
800
|
+
|
|
801
|
+
|
|
802
|
+
def get_brg_non_default_module_pkt(test, module):
|
|
803
|
+
if 'Energy2400' in module.__name__:
|
|
804
|
+
if test.active_brg.board_type in [ag.BOARD_TYPE_ENERGOUS_V0, ag.BOARD_TYPE_ENERGOUS_V2,
|
|
805
|
+
ag.BOARD_TYPE_ENERGOUS_V3, ag.BOARD_TYPE_ENERGOUS_V4]:
|
|
806
|
+
# Increase output power offset by 1
|
|
807
|
+
op_offset = BRG_NON_DEFAULT_OP_OFFSET_2_4 + 1
|
|
808
|
+
else:
|
|
809
|
+
op_offset = BRG_NON_DEFAULT_OP_OFFSET_2_4
|
|
810
|
+
return cert_config.get_default_brg_pkt(test, pkt_type=test.active_brg.energy2400,
|
|
811
|
+
duty_cycle=BRG_NON_DEFAULT_DUTY_CYCLE,
|
|
812
|
+
output_power=op_offset, pattern=BRG_NON_DEFAULT_EP_2_4,
|
|
813
|
+
signal_indicator_cycle=BRG_NON_DEFAULT_SIGNAL_INDICATOR_CYCLE_2_4,
|
|
814
|
+
signal_indicator_rep=BRG_NON_DEFAULT_SIGNAL_INDICATOR_REP_2_4)
|
|
815
|
+
elif 'EnergySub1G' in module.__name__:
|
|
816
|
+
return cert_config.get_default_brg_pkt(test, pkt_type=test.active_brg.energy_sub1g,
|
|
817
|
+
duty_cycle=BRG_NON_DEFAULT_DUTY_CYCLE,
|
|
818
|
+
signal_indicator_cycle=BRG_NON_DEFAULT_SIGNAL_INDICATOR_CYCLE_SUB1G,
|
|
819
|
+
signal_indicator_rep=BRG_NON_DEFAULT_SIGNAL_INDICATOR_REP_SUB1G)
|
|
820
|
+
elif 'PwrMgmt' in module.__name__:
|
|
821
|
+
return cert_config.get_default_brg_pkt(test, pkt_type=test.active_brg.pwr_mgmt,
|
|
822
|
+
dynamic_keep_alive_scan=BRG_NON_DEFAULT_PWR_MGMT_KEEP_ALIVE_SCAN)
|
|
823
|
+
elif 'Custom' in module.__name__:
|
|
824
|
+
return cert_config.get_default_brg_pkt(test, pkt_type=test.active_brg.custom,
|
|
825
|
+
motion_sensitivity_threshold=LIS2DW12_NON_DEFAULT_STATE_THRESHOLD,
|
|
826
|
+
s2d_transition_time=LIS2DW12_NON_DEFAULT_WAKE_UP_DURATION,
|
|
827
|
+
d2s_transition_time=LIS2DW12_NON_DEFAULT_SLEEP_DURATION)
|
|
828
|
+
elif 'Datapath' in module.__name__:
|
|
829
|
+
if test.active_brg.board_type in [ag.BOARD_TYPE_ENERGOUS_V0, ag.BOARD_TYPE_ENERGOUS_V2,
|
|
830
|
+
ag.BOARD_TYPE_ENERGOUS_V3, ag.BOARD_TYPE_ENERGOUS_V4]:
|
|
831
|
+
# Increase output power offset by 1
|
|
832
|
+
op_offset = BRG_NON_DEFAULT_OP_OFFSET_2_4 + 1
|
|
833
|
+
else:
|
|
834
|
+
op_offset = BRG_NON_DEFAULT_OP_OFFSET_2_4
|
|
835
|
+
return cert_config.get_default_brg_pkt(test, pkt_type=test.active_brg.datapath,
|
|
836
|
+
tx_repetition=BRG_NON_DEFAULT_TX_REPETITION,
|
|
837
|
+
pkt_filter=BRG_NON_DEFAULT_PKT_FILTER,
|
|
838
|
+
output_power=op_offset,
|
|
839
|
+
pattern=ag.DATAPATH_PATTERN_EU_PATTERN,
|
|
840
|
+
pacer_interval=BRG_NON_DEFAULT_PACER_INTERVAL,
|
|
841
|
+
rssi_threshold=BRG_NON_DEFAULT_RSSI_THRESHOLD,
|
|
842
|
+
event_time_unit=BRG_NON_DEFAULT_EVENT_TIME_UNIT,
|
|
843
|
+
event_window=BRG_NON_DEFAULT_EVENT_WINDOW,
|
|
844
|
+
event_trigger=BRG_NON_DEFAULT_EVENT_TRIGGER,
|
|
845
|
+
event_pacer_interval=BRG_NON_DEFAULT_EVENT_PACER_INTERVAL,
|
|
846
|
+
rssi_movement_threshold=BRG_NON_DEFAULT_RSSI_MOVEMENT_THRESHOLD)
|
|
847
|
+
elif 'Calibration' in module.__name__:
|
|
848
|
+
if test.active_brg.board_type in [ag.BOARD_TYPE_ENERGOUS_V0, ag.BOARD_TYPE_ENERGOUS_V2,
|
|
849
|
+
ag.BOARD_TYPE_ENERGOUS_V3, ag.BOARD_TYPE_ENERGOUS_V4]:
|
|
850
|
+
# Increase output power offset by 1
|
|
851
|
+
op_offset = BRG_NON_DEFAULT_CALIB_OUTPUT_POWER_OFFSET + 1
|
|
852
|
+
else:
|
|
853
|
+
op_offset = BRG_NON_DEFAULT_CALIB_OUTPUT_POWER_OFFSET
|
|
854
|
+
return cert_config.get_default_brg_pkt(test, pkt_type=test.active_brg.calibration,
|
|
855
|
+
output_power=op_offset,
|
|
856
|
+
interval=BRG_NON_DEFAULT_CALIB_INTERVAL,
|
|
857
|
+
pattern=BRG_NON_DEFAULT_CALIB_PATTERN)
|
|
858
|
+
elif 'ExtSensors' in module.__name__:
|
|
859
|
+
return cert_config.get_default_brg_pkt(test, pkt_type=test.active_brg.sensors,
|
|
860
|
+
sensor0=ag.EXTERNAL_SENSORS_MINEWS1,
|
|
861
|
+
sensor1=ag.EXTERNAL_SENSORS_ZEBRA_PRINTER,
|
|
862
|
+
sensor2=ag.EXTERNAL_SENSORS_ERM_SMART_MS,
|
|
863
|
+
rssi_threshold=BRG_NON_DEFAULT_RSSI_THRESHOLD,
|
|
864
|
+
sub1g_rssi_threshold=BRG_NON_DEFAULT_RSSI_THRESHOLD)
|
|
865
|
+
return None
|
|
866
|
+
|
|
867
|
+
|
|
868
|
+
def brg_non_default_modules_cfg(test):
|
|
869
|
+
for module in test.active_brg.modules:
|
|
870
|
+
cfg_pkt = get_brg_non_default_module_pkt(test, module)
|
|
871
|
+
if cfg_pkt:
|
|
872
|
+
utPrint(f"Configuring {module.__name__} non-default cfg", "BLUE")
|
|
873
|
+
test = cert_config.brg_configure(test=test, cfg_pkt=cfg_pkt)[0]
|
|
874
|
+
if test.rc == TEST_FAILED and test.exit_on_param_failure:
|
|
875
|
+
test.add_reason(f"{module.__name__} non-default cfg pkt was not found after {DEFAULT_BRG_FIELD_UPDATE_TIMEOUT} sec!")
|
|
876
|
+
return test
|
|
877
|
+
return test
|
|
878
|
+
|
|
879
|
+
# Plotly graphing libraries documentation: https://plotly.com/python/
|
|
880
|
+
|
|
881
|
+
def display_data(df, csv=True, pkt_cntr_diff=False, cer_per_tag=False, tbc=False, rssi=False, ttfp=False, event_flag=False, event_ctr=False,
|
|
882
|
+
start_time=None, name_prefix="", dir=""):
|
|
883
|
+
print("\nGenerating data analysis graphs and CSV file\n")
|
|
884
|
+
df[DATETIME] = df[TIMESTAMP].apply(lambda x: datetime.datetime.fromtimestamp(x/1e3))
|
|
885
|
+
df = df.sort_values(by=DATETIME)
|
|
886
|
+
symbol_sequence = ["hourglass", "bowtie", "cross", "x"]
|
|
887
|
+
all_graphs = []
|
|
888
|
+
ttfp_graph = None
|
|
889
|
+
# insert new start_time to override timestamp_delta from data_scan()
|
|
890
|
+
if start_time:
|
|
891
|
+
df[TIMESTAMP_DELTA] = (df[TIMESTAMP] / 1000) - start_time.timestamp()
|
|
892
|
+
if rssi:
|
|
893
|
+
rssi_graph = px.scatter(df, title=RSSI, x=DATETIME, y=RSSI, color=TAG_ID, symbol=SRC_ID, symbol_sequence=symbol_sequence)
|
|
894
|
+
rssi_graph.update_traces(marker=dict(size=12, line=dict(width=2, color='DarkSlateGrey')), selector=dict(mode='markers'))
|
|
895
|
+
all_graphs.append(rssi_graph)
|
|
896
|
+
if pkt_cntr_diff:
|
|
897
|
+
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)
|
|
898
|
+
pkt_cntr_diff_graph.update_traces(marker=dict(size=12, line=dict(width=2, color='DarkSlateGrey')), selector=dict(mode='markers'))
|
|
899
|
+
all_graphs.append(pkt_cntr_diff_graph)
|
|
900
|
+
if cer_per_tag:
|
|
901
|
+
cer_per_tag_graph = px.scatter(df, title=CER, x=DATETIME, y=CER, color=TAG_ID, symbol=SRC_ID, symbol_sequence=symbol_sequence)
|
|
902
|
+
cer_per_tag_graph.update_traces(marker=dict(size=12, line=dict(width=2, color='DarkSlateGrey')), selector=dict(mode='markers'))
|
|
903
|
+
all_graphs.append(cer_per_tag_graph)
|
|
904
|
+
if tbc:
|
|
905
|
+
tbc_graph = px.scatter(df, title=TBC, x=DATETIME, y=TBC, color=TAG_ID, symbol=SRC_ID, symbol_sequence=symbol_sequence)
|
|
906
|
+
tbc_graph.update_traces(marker=dict(size=12, line=dict(width=2, color='DarkSlateGrey')), selector=dict(mode='markers'))
|
|
907
|
+
all_graphs.append(tbc_graph)
|
|
908
|
+
if event_flag:
|
|
909
|
+
event_flag_graph = px.scatter(df, title=EVENT_FLAG, x=DATETIME, y=EVENT_FLAG, color=TAG_ID, symbol=SRC_ID, symbol_sequence=symbol_sequence)
|
|
910
|
+
event_flag_graph.update_traces(marker=dict(size=12, line=dict(width=2, color='DarkSlateGrey')), selector=dict(mode='markers'))
|
|
911
|
+
all_graphs.append(event_flag_graph)
|
|
912
|
+
if event_ctr:
|
|
913
|
+
event_ctr_graph = px.scatter(df, title=EVENT_CTR, x=DATETIME, y=EVENT_CTR, color=TAG_ID, symbol=SRC_ID, symbol_sequence=symbol_sequence)
|
|
914
|
+
event_ctr_graph.update_traces(marker=dict(size=12, line=dict(width=2, color='DarkSlateGrey')), selector=dict(mode='markers'))
|
|
915
|
+
all_graphs.append(event_ctr_graph)
|
|
916
|
+
if ttfp:
|
|
917
|
+
data = {TIMESTAMP_DELTA:[], TAGS_COUNT:[], NEW_TAGS:[]}
|
|
918
|
+
tags_count = []
|
|
919
|
+
# iterate all integers from 0 to the largest timestamp_delta as values for X
|
|
920
|
+
for i in range(int(math.ceil(df[TIMESTAMP_DELTA].iloc[-1]))+1):
|
|
921
|
+
new_tags = []
|
|
922
|
+
# for every timestamp_delta value (i) add all NEW tags received in that timestamp_delta
|
|
923
|
+
for row in df.query('timestamp_delta < @i').itertuples(index=False):
|
|
924
|
+
if not row.tag_id in tags_count and not row.tag_id in new_tags:
|
|
925
|
+
new_tags += [row.tag_id]
|
|
926
|
+
tags_count += new_tags
|
|
927
|
+
data[TIMESTAMP_DELTA] += ([i])
|
|
928
|
+
data[TAGS_COUNT] += [len(tags_count)]
|
|
929
|
+
data[NEW_TAGS] += [new_tags]
|
|
930
|
+
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)
|
|
931
|
+
all_graphs.append(ttfp_graph)
|
|
932
|
+
#generate
|
|
933
|
+
file_path = os.path.join(ARTIFACTS_DIR, dir, f"{name_prefix}data_graphs.html")
|
|
934
|
+
if not os.path.exists(os.path.dirname(file_path)):
|
|
935
|
+
os.makedirs(os.path.dirname(file_path))
|
|
936
|
+
with open(file_path, 'w') as f:
|
|
937
|
+
for g in all_graphs:
|
|
938
|
+
f.write(g.to_html(full_html=False, include_plotlyjs='cdn', include_mathjax='cdn'))
|
|
939
|
+
f.write("<br>")
|
|
940
|
+
if csv:
|
|
941
|
+
df.to_csv(os.path.join(ARTIFACTS_DIR, dir, f"{name_prefix}all_data.csv"), index=False)
|
|
942
|
+
|
|
943
|
+
return ttfp_graph
|
|
944
|
+
|
|
945
|
+
def single_log_search(test, s, found, fail_on_find=False, print_logs=True, additional_log="", target=DUT):
|
|
946
|
+
mqttc = test.get_mqttc_by_target(target)
|
|
947
|
+
res = False
|
|
948
|
+
for p in cert_mqtt.get_all_status_pkts(mqttc):
|
|
949
|
+
if GW_LOGS in p:
|
|
950
|
+
if cert_config.get_protobuf_by_target(test, target) and p[GW_LOGS]:
|
|
951
|
+
# handle protobuf structure (when GW_LOGS is not empty)
|
|
952
|
+
logs = p[GW_LOGS][LOGS]
|
|
953
|
+
else:
|
|
954
|
+
logs = p[GW_LOGS]
|
|
955
|
+
for log in logs:
|
|
956
|
+
if any([s in log]) and any([additional_log in log]) and (log not in found):
|
|
957
|
+
print(f"Log: {log}, Additional Log: {additional_log}")
|
|
958
|
+
found += [log]
|
|
959
|
+
res = True
|
|
960
|
+
if fail_on_find:
|
|
961
|
+
if test.rc == TEST_PASSED:
|
|
962
|
+
test= test.add_reason("Test functionality passed")
|
|
963
|
+
test.add_reason(f"Found {s}")
|
|
964
|
+
test.rc = TEST_FAILED
|
|
965
|
+
print(found)
|
|
966
|
+
return test, res, found
|
|
967
|
+
if print_logs:
|
|
968
|
+
print_pkt(s)
|
|
969
|
+
return test, res, found
|
|
970
|
+
|
|
971
|
+
def gw_logs_search(test, strings, scan_time=GW_LOG_PERIOD+5, print_logs=False, fail_on_find=False):
|
|
972
|
+
"""searching for specific logs in mqtt status topic in GW_LOGS field
|
|
973
|
+
|
|
974
|
+
:param WltTest test: test running
|
|
975
|
+
:param [str] strings: list of logs to search
|
|
976
|
+
:param int scan_time: time to scan for logs, defaults to GW_LOG_PERIOD+5
|
|
977
|
+
:return WltTest: test with updated results
|
|
978
|
+
"""
|
|
979
|
+
start_time = datetime.datetime.now()
|
|
980
|
+
print(f"Searching for {strings} log in MQTT status topic.\nFail on find is set to {fail_on_find}")
|
|
981
|
+
found = []
|
|
982
|
+
while (len(strings) > len(found)):
|
|
983
|
+
for s in strings:
|
|
984
|
+
test, res, found = single_log_search(test, s, found, fail_on_find, print_logs)
|
|
985
|
+
if res:
|
|
986
|
+
break
|
|
987
|
+
if (datetime.datetime.now() - start_time).seconds >= scan_time:
|
|
988
|
+
if not fail_on_find:
|
|
989
|
+
test.add_reason(f"Didnt find logs in [{scan_time}] seconds")
|
|
990
|
+
print(test.reason)
|
|
991
|
+
test.rc = TEST_FAILED
|
|
992
|
+
break
|
|
993
|
+
if test.rc == TEST_PASSED:
|
|
994
|
+
if not fail_on_find:
|
|
995
|
+
print(f"SUCCESS found all [{strings}]")
|
|
996
|
+
else:
|
|
997
|
+
print(f"SUCCESS Didnt find [{strings}]")
|
|
998
|
+
return test
|
|
999
|
+
|
|
1000
|
+
def gw_action_status_search(test, action_idx, status_code, target=DUT):
|
|
1001
|
+
"""searching for action returned status code in mqtt status topic in ACTION field
|
|
1002
|
+
|
|
1003
|
+
:param WltTest test: test running
|
|
1004
|
+
:param int action_idx: sent action index
|
|
1005
|
+
:param int status_code: expected status code for action
|
|
1006
|
+
:return WltTest: test with updated results
|
|
1007
|
+
"""
|
|
1008
|
+
mqttc = test.get_mqttc_by_target(target)
|
|
1009
|
+
start_time = datetime.datetime.now()
|
|
1010
|
+
print(f"Searching for action idx ({action_idx}) update log in MQTT status topic")
|
|
1011
|
+
while (datetime.datetime.now() - start_time).seconds < GW_LOG_PERIOD:
|
|
1012
|
+
for p in cert_mqtt.get_all_status_pkts(mqttc):
|
|
1013
|
+
# JSON
|
|
1014
|
+
if ((ACTION in p) and (p[ACTION] == action_idx) and
|
|
1015
|
+
(STATUS_CODE_STR in p) and (p[STATUS_CODE_STR] == status_code) and
|
|
1016
|
+
(STEP not in p or p[STEP] == FINAL_OTA_STEP)):
|
|
1017
|
+
return test
|
|
1018
|
+
# Protobuf - when succeed status is not sent
|
|
1019
|
+
if ((ACTION_STATUS in p) and (p[ACTION_STATUS][ACTION] == action_idx) and
|
|
1020
|
+
STATUS_CODE not in p[ACTION_STATUS] and
|
|
1021
|
+
(STEP not in p[ACTION_STATUS] or p[ACTION_STATUS][STEP] == FINAL_OTA_STEP)):
|
|
1022
|
+
return test
|
|
1023
|
+
test.add_reason(f"ActionStatus message (idx={action_idx} status={status_code}) not found in {GW_LOG_PERIOD} sec")
|
|
1024
|
+
print(test.reason)
|
|
1025
|
+
test.rc = TEST_FAILED
|
|
1026
|
+
return test
|
|
1027
|
+
|
|
1028
|
+
def get_gw_logs_packets(test, last=False, print_log=True, target=DUT):
|
|
1029
|
+
"""
|
|
1030
|
+
gets gw logs pkts
|
|
1031
|
+
:param WltTest test: test with gw that it's info will be retreived
|
|
1032
|
+
:param bool last: set to True to get only the last pkt caught, defaults to False
|
|
1033
|
+
:return pkt/list[pkt]: logs pkts list/last status pkt received
|
|
1034
|
+
"""
|
|
1035
|
+
mqttc = test.get_mqttc_by_target(target)
|
|
1036
|
+
cert_config.gw_logs_action(test)
|
|
1037
|
+
pkts = []
|
|
1038
|
+
for p in cert_mqtt.get_all_status_pkts(mqttc):
|
|
1039
|
+
if GW_LOGS in p:
|
|
1040
|
+
if print_log:
|
|
1041
|
+
print("GW logs packet:\n", p[GW_LOGS])
|
|
1042
|
+
logs = p[GW_LOGS][LOGS] if test.tester.protobuf else p[GW_LOGS]
|
|
1043
|
+
pkts += [log for log in logs]
|
|
1044
|
+
if pkts and last:
|
|
1045
|
+
return pkts[len(pkts)-1]
|
|
1046
|
+
return pkts
|
|
1047
|
+
|
|
1048
|
+
def get_gw_type(mqttc):
|
|
1049
|
+
messages = cert_mqtt.get_all_status_pkts(mqttc)
|
|
1050
|
+
for msg in messages:
|
|
1051
|
+
if GW_STATUS in msg: # protobuf
|
|
1052
|
+
return msg[GW_STATUS][GW_TYPE], msg
|
|
1053
|
+
if GW_CONF in msg: # JSON
|
|
1054
|
+
return msg[GW_TYPE], msg
|
|
1055
|
+
return None, None
|
|
1056
|
+
|
|
1057
|
+
def get_module_if_pkt(test):
|
|
1058
|
+
cert_config.send_brg_action(test, ag.ACTION_GET_MODULE, interface=1)
|
|
1059
|
+
mgmt_type = [m for m in ag.MODULES_LIST if "ModuleIf" in m.__name__]
|
|
1060
|
+
test, pkts = scan_for_mgmt_pkts(test, mgmt_type=mgmt_type)
|
|
1061
|
+
|
|
1062
|
+
if test.rc == TEST_FAILED:
|
|
1063
|
+
return test, NO_RESPONSE
|
|
1064
|
+
else:
|
|
1065
|
+
print(pkts[-1][MGMT_PKT].pkt)
|
|
1066
|
+
return test, pkts[-1][MGMT_PKT].pkt
|
|
1067
|
+
|
|
1068
|
+
def get_gw_api_version(mqttc):
|
|
1069
|
+
messages = cert_mqtt.get_all_status_pkts(mqttc)
|
|
1070
|
+
for msg in messages:
|
|
1071
|
+
if GW_CONF in msg: # JSON
|
|
1072
|
+
return msg[GW_CONF][GW_API_VERSION]
|
|
1073
|
+
if GW_STATUS in msg: # protobuf
|
|
1074
|
+
return msg[GW_STATUS][GW_API_VERSION]
|
|
1075
|
+
return None
|
|
1076
|
+
|
|
1077
|
+
def get_cfg_hash(test):
|
|
1078
|
+
utPrint(f"Fetching BRG cfg hash for BRG {test.active_brg.id_str}", "BLUE")
|
|
1079
|
+
test, module_if_pkt = get_module_if_pkt(test)
|
|
1080
|
+
if test.rc == TEST_FAILED:
|
|
1081
|
+
return test, 0
|
|
1082
|
+
else:
|
|
1083
|
+
return test, module_if_pkt.cfg_hash
|
|
1084
|
+
|
|
1085
|
+
|
|
1086
|
+
def brg_restore_defaults_check(test, target=DUT):
|
|
1087
|
+
print("Starting Restore Defaults Check")
|
|
1088
|
+
start_time = datetime.datetime.now()
|
|
1089
|
+
found = False
|
|
1090
|
+
revived = False
|
|
1091
|
+
output = ""
|
|
1092
|
+
while not found:
|
|
1093
|
+
last_pkt = get_brg_cfg_pkts(test=test, cfg_info=True, last=True, target=target)
|
|
1094
|
+
if last_pkt:
|
|
1095
|
+
print(f"Got pkt after {(datetime.datetime.now() - start_time).seconds} sec!")
|
|
1096
|
+
wlt_pkt = WltPkt(last_pkt)
|
|
1097
|
+
print(f"SUCCESS: Found pkt from brg: {wlt_pkt}")
|
|
1098
|
+
found = True # exit
|
|
1099
|
+
revived = True
|
|
1100
|
+
output = "SUCCESS: brg is alive and restored to defaults!"
|
|
1101
|
+
if (datetime.datetime.now() - start_time).seconds > ACTION_LONG_TIMEOUT:
|
|
1102
|
+
print(f"FAILURE: Can't find bridge! Didn't get config pkt after {ACTION_LONG_TIMEOUT} seconds!")
|
|
1103
|
+
break
|
|
1104
|
+
print_update_wait()
|
|
1105
|
+
return test, revived, output
|
|
1106
|
+
|
|
1107
|
+
# Pwr Mgmt
|
|
1108
|
+
def brg_pwr_mgmt_turn_on(test):
|
|
1109
|
+
utPrint("Sending pwr_mgmt static mode configuration - 30 seconds ON, 60 seconds SLEEP!", "BLUE")
|
|
1110
|
+
module = test.active_brg.pwr_mgmt
|
|
1111
|
+
# send pwr mgmt module packet
|
|
1112
|
+
wltpkt = WltPkt(hdr=DEFAULT_HDR, pkt=module(module_type=ag.MODULE_PWR_MGMT, msg_type=ag.BRG_MGMT_MSG_TYPE_CFG_SET,
|
|
1113
|
+
api_version=ag.API_VERSION_LATEST,seq_id=random.randrange(99),
|
|
1114
|
+
brg_mac=test.active_brg.id_int, static_on_duration=30, static_sleep_duration=60,
|
|
1115
|
+
dynamic_leds_on=0,dynamic_keep_alive_period=0, dynamic_keep_alive_scan=0,
|
|
1116
|
+
dynamic_on_duration=0,dynamic_sleep_duration=0))
|
|
1117
|
+
test = cert_config.brg_configure(test=test, cfg_pkt=wltpkt, module=module)[0]
|
|
1118
|
+
|
|
1119
|
+
if test.rc == TEST_FAILED:
|
|
1120
|
+
test.add_reason("Turning pwr mgmt ON failed, Didn't receive GW MEL pwr mgmt ON pkt")
|
|
1121
|
+
else:
|
|
1122
|
+
utPrint("SUCCESS! pwr mgmt static mode turned on!", "GREEN")
|
|
1123
|
+
return test, wltpkt
|
|
1124
|
+
|
|
1125
|
+
def brg_pwr_mgmt_turn_off(test):
|
|
1126
|
+
utPrint("Turning pwr mgmt OFF - sending default configuration!", "BLUE")
|
|
1127
|
+
module = test.active_brg.pwr_mgmt
|
|
1128
|
+
start_time = datetime.datetime.now()
|
|
1129
|
+
wltpkt = WltPkt(hdr=DEFAULT_HDR, pkt=module(module_type=ag.MODULE_PWR_MGMT, msg_type=ag.BRG_MGMT_MSG_TYPE_CFG_SET,
|
|
1130
|
+
api_version=ag.API_VERSION_LATEST,seq_id=random.randrange(99),
|
|
1131
|
+
brg_mac=test.active_brg.id_int,static_leds_on=1,
|
|
1132
|
+
static_keep_alive_period=0,static_keep_alive_scan=0,
|
|
1133
|
+
static_on_duration=0,static_sleep_duration=0,
|
|
1134
|
+
dynamic_leds_on=0,dynamic_keep_alive_period=0,
|
|
1135
|
+
dynamic_keep_alive_scan=0,dynamic_on_duration=0,dynamic_sleep_duration=0))
|
|
1136
|
+
found = NOT_FOUND
|
|
1137
|
+
while found != DONE:
|
|
1138
|
+
test, found = cert_config.brg_configure(test=test, cfg_pkt=wltpkt, module=module, wait=False)
|
|
1139
|
+
if ((datetime.datetime.now() - start_time).seconds > (ag.PWR_MGMT_DEFAULTS_KEEP_ALIVE_PERIOD + 1)):
|
|
1140
|
+
test.add_reason(f"Didn't receive GW MEL pwr mgmt OFF ack after {ag.PWR_MGMT_DEFAULTS_KEEP_ALIVE_PERIOD + 1} seconds")
|
|
1141
|
+
test.rc = TEST_FAILED
|
|
1142
|
+
break
|
|
1143
|
+
print_update_wait()
|
|
1144
|
+
if found == DONE:
|
|
1145
|
+
utPrint(f"FOUND off pkt after {(datetime.datetime.now() - start_time)} secs", "GREEN")
|
|
1146
|
+
utPrint("SUCCESS! pwr mgmt static mode turned off!", "GREEN")
|
|
1147
|
+
return test
|
|
1148
|
+
|
|
1149
|
+
# LEDs tests funcs
|
|
1150
|
+
def check_input_n_try_again(value):
|
|
1151
|
+
# check for valid input char - only 'Y', 'y', 'N' or 'n'
|
|
1152
|
+
while value.lower() != 'y' and value.lower() != 'n':
|
|
1153
|
+
utPrint("Wrong input, Please try Again!\n", "RED")
|
|
1154
|
+
value = input()
|
|
1155
|
+
return value
|
|
1156
|
+
|
|
1157
|
+
# Executed only when the received value is 'n'!
|
|
1158
|
+
def value_check_if_y(test, received_value, stage):
|
|
1159
|
+
# check if the received value is different from the expected value
|
|
1160
|
+
if 'y' != received_value.lower():
|
|
1161
|
+
test.rc = TEST_FAILED
|
|
1162
|
+
test.add_reason(f"{stage} failed")
|
|
1163
|
+
return test
|
|
1164
|
+
|
|
1165
|
+
|
|
1166
|
+
##########################################
|
|
1167
|
+
# Signal Indicator functions
|
|
1168
|
+
##########################################
|
|
1169
|
+
def dual_polarization_ant_boards_get():
|
|
1170
|
+
return [ag.BOARD_TYPE_MINEW_SINGLE_BAND_V0, ag.BOARD_TYPE_MINEW_DUAL_BAND_V0,
|
|
1171
|
+
ag.BOARD_TYPE_ENERGOUS_V2, ag.BOARD_TYPE_ERM_V0, ag.BOARD_TYPE_ERM_V1,
|
|
1172
|
+
ag.BOARD_TYPE_MINEW_POE_V0]
|
|
1173
|
+
|
|
1174
|
+
def exp_sig_ind_pkts(tx_brg, rx_brg, cycles):
|
|
1175
|
+
if tx_brg.board_type in dual_polarization_ant_boards_get():
|
|
1176
|
+
tx_brg_ant_polarization_num = 2
|
|
1177
|
+
else:
|
|
1178
|
+
tx_brg_ant_polarization_num = 1
|
|
1179
|
+
if rx_brg.board_type in dual_polarization_ant_boards_get():
|
|
1180
|
+
rx_brg_ant_polarization_num = 2
|
|
1181
|
+
else:
|
|
1182
|
+
rx_brg_ant_polarization_num = 1
|
|
1183
|
+
|
|
1184
|
+
expected = cycles * tx_brg_ant_polarization_num * rx_brg_ant_polarization_num
|
|
1185
|
+
# Allow missing 1 pkt
|
|
1186
|
+
return [expected - 1, expected]
|
|
1187
|
+
|
|
1188
|
+
def exp_sig_ind_pkts2(tx_brg, rx_brg, cycles):
|
|
1189
|
+
if tx_brg.board_type in dual_polarization_ant_boards_get():
|
|
1190
|
+
tx_brg_ant_polarization_num = 2
|
|
1191
|
+
else:
|
|
1192
|
+
tx_brg_ant_polarization_num = 1
|
|
1193
|
+
if rx_brg.board_type in dual_polarization_ant_boards_get():
|
|
1194
|
+
rx_brg_ant_polarization_num = 2
|
|
1195
|
+
else:
|
|
1196
|
+
rx_brg_ant_polarization_num = 1
|
|
1197
|
+
|
|
1198
|
+
expected = cycles * tx_brg_ant_polarization_num * rx_brg_ant_polarization_num
|
|
1199
|
+
return expected
|
|
1200
|
+
|
|
1201
|
+
def sig_ind_pkts_fail_analysis(tx_brg, rx_brg, cycles, received_pkts):
|
|
1202
|
+
|
|
1203
|
+
expected = exp_sig_ind_pkts2(tx_brg, rx_brg, cycles)
|
|
1204
|
+
print(f"Expected pkts: {expected}, Received pkts: {len(received_pkts)}")
|
|
1205
|
+
# Allow missing 25% max
|
|
1206
|
+
if int(0.75 * expected) <= len(received_pkts) <= int(1.25 * expected):
|
|
1207
|
+
return False
|
|
1208
|
+
return True
|
|
1209
|
+
|
|
1210
|
+
def get_all_sig_ind_pkts(test=None, rx_brg=None, tx_brg=None):
|
|
1211
|
+
if rx_brg == test.brg1:
|
|
1212
|
+
all_sensor_packets = cert_mqtt.get_all_brg1_ext_sensor_pkts(test=test, is_unified=True, target=TESTER)
|
|
1213
|
+
elif rx_brg == (test.dut.internal_brg if cert_config.is_gw(test.dut) else test.dut):
|
|
1214
|
+
all_sensor_packets = cert_mqtt.get_all_sensor_pkts(test=test, is_unified=True, target=DUT)
|
|
1215
|
+
signal_ind_pkts = []
|
|
1216
|
+
for p in all_sensor_packets:
|
|
1217
|
+
sensor_id = (f"{p[UNIFIED_SENSOR_PKT].pkt.sensor_ad_type:02X}"
|
|
1218
|
+
f"{p[UNIFIED_SENSOR_PKT].pkt.sensor_uuid_msb:02X}"
|
|
1219
|
+
f"{p[UNIFIED_SENSOR_PKT].pkt.sensor_uuid_lsb:02X}")
|
|
1220
|
+
if (sensor_id == f"{ag.SENSOR_SERVICE_ID_SIGNAL_INDICATOR:06X}" and
|
|
1221
|
+
p[ALIAS_BRIDGE_ID] == rx_brg.id_alias and f"{p[UNIFIED_SENSOR_PKT].pkt.sensor_mac:012X}" == tx_brg.id_alias):
|
|
1222
|
+
signal_ind_pkts.append(p)
|
|
1223
|
+
return signal_ind_pkts
|
|
1224
|
+
|
|
1225
|
+
def output_power_check(test, received_signal_ind_pkts, tx_brg_):
|
|
1226
|
+
output_power_default = tx_brg_.max_output_power_dbm - tx_brg_.datapath().output_power
|
|
1227
|
+
|
|
1228
|
+
for p in received_signal_ind_pkts:
|
|
1229
|
+
if p[UNIFIED_SENSOR_PKT].pkt.signal_indicator_payload.output_power != output_power_default:
|
|
1230
|
+
test.rc = TEST_FAILED
|
|
1231
|
+
test.add_reason("output power of internal brg is incorrect!\n"
|
|
1232
|
+
f"got:{p[UNIFIED_SENSOR_PKT].pkt.signal_indicator_payload.output_power}, expected: {output_power_default}\n")
|
|
1233
|
+
return test
|
|
1234
|
+
|
|
1235
|
+
def rssi_check(test, received_signal_ind_pkts):
|
|
1236
|
+
threshold_rssi = [0, 80]
|
|
1237
|
+
for p in received_signal_ind_pkts:
|
|
1238
|
+
if not threshold_rssi[0] < p[UNIFIED_SENSOR_PKT].pkt.rssi < threshold_rssi[1]:
|
|
1239
|
+
test.rc = TEST_FAILED
|
|
1240
|
+
test.add_reason("rssi value is wrong, out of 0 to 80 ")
|
|
1241
|
+
|
|
1242
|
+
return test
|
|
1243
|
+
|
|
1244
|
+
|
|
1245
|
+
def rx_tx_antenna_check(test, received_signal_ind_pkts, tx_brg_, rx_brg_, cycles):
|
|
1246
|
+
|
|
1247
|
+
# Allow to miss 1 packet or get 1 extra packet
|
|
1248
|
+
expected = range(int(cycles * 0.5), cycles + 2)
|
|
1249
|
+
|
|
1250
|
+
received = len(get_polar_signal_ind_pkt(received_signal_ind_pkts, rx_ant=0, tx_ant=0))
|
|
1251
|
+
if received not in expected:
|
|
1252
|
+
test.rc = TEST_FAILED
|
|
1253
|
+
test.add_reason(f"rx_ant=0 tx_ant=0 expected={cycles} received={received}")
|
|
1254
|
+
|
|
1255
|
+
if tx_brg_.board_type in dual_polarization_ant_boards_get():
|
|
1256
|
+
received = len(get_polar_signal_ind_pkt(received_signal_ind_pkts, rx_ant=0, tx_ant=1))
|
|
1257
|
+
if received not in expected:
|
|
1258
|
+
test.rc = TEST_FAILED
|
|
1259
|
+
test.add_reason(f"rx_ant=0 tx_ant=1 expected={cycles} received={received}")
|
|
1260
|
+
|
|
1261
|
+
if rx_brg_.board_type in dual_polarization_ant_boards_get():
|
|
1262
|
+
received = len(get_polar_signal_ind_pkt(received_signal_ind_pkts, rx_ant=1, tx_ant=0))
|
|
1263
|
+
if received not in expected:
|
|
1264
|
+
test.rc = TEST_FAILED
|
|
1265
|
+
test.add_reason(f"rx_ant=1 tx_ant=0 expected={cycles} received={received}")
|
|
1266
|
+
|
|
1267
|
+
if (rx_brg_.board_type in dual_polarization_ant_boards_get() and
|
|
1268
|
+
tx_brg_.board_type in dual_polarization_ant_boards_get()):
|
|
1269
|
+
received = len(get_polar_signal_ind_pkt(received_signal_ind_pkts, rx_ant=1, tx_ant=1))
|
|
1270
|
+
if received not in expected:
|
|
1271
|
+
test.rc = TEST_FAILED
|
|
1272
|
+
test.add_reason(f"rx_ant=1 tx_ant=1 expected={cycles} received={received}")
|
|
1273
|
+
return test
|
|
1274
|
+
|
|
1275
|
+
|
|
1276
|
+
def get_polar_signal_ind_pkt(pkts, rx_ant, tx_ant):
|
|
1277
|
+
return [p for p in pkts if p[UNIFIED_SENSOR_PKT].pkt.signal_indicator_payload.rx_antenna ==
|
|
1278
|
+
rx_ant and p[UNIFIED_SENSOR_PKT].pkt.signal_indicator_payload.tx_antenna == tx_ant]
|
|
1279
|
+
|
|
1280
|
+
|
|
1281
|
+
def output_power_supported(board_type, output_power):
|
|
1282
|
+
if board_type in [ag.BOARD_TYPE_FANSTEL_WIFI_V0, ag.BOARD_TYPE_FANSTEL_LAN_V0]:
|
|
1283
|
+
return output_power in FANSTEL_GW_SUPPORTED_VALUES
|
|
1284
|
+
elif board_type in ENERGOUS_BOARD_TYPES_GROUP:
|
|
1285
|
+
return output_power in ENERGOUS_GROUP_SUPPORTED_VALUES
|
|
1286
|
+
elif board_type == ag.BOARD_TYPE_ENERGOUS_V1:
|
|
1287
|
+
return output_power in ENERGOUS_V1_SUPPORTED_VALUES
|
|
1288
|
+
else:
|
|
1289
|
+
return output_power in ag.OUTPUT_POWER_2_4_SUPPORTED_VALUES
|
|
1290
|
+
|
|
1291
|
+
|
|
1292
|
+
def validate_received_packets(pkts_array):
|
|
1293
|
+
for pkt in pkts_array:
|
|
1294
|
+
# Check all required fields are present
|
|
1295
|
+
if TIMESTAMP not in pkt:
|
|
1296
|
+
return False, "timestamp field is missing in some of the packets"
|
|
1297
|
+
if ALIAS_BRIDGE_ID not in pkt:
|
|
1298
|
+
return False, "alias_bridge_id field is missing in some of the packets"
|
|
1299
|
+
if PAYLOAD not in pkt:
|
|
1300
|
+
return False, "payload field is missing in some of the packets"
|
|
1301
|
+
if SEQUENCE_ID not in pkt:
|
|
1302
|
+
return False, "sequence_id field is missing in some of the packets"
|
|
1303
|
+
# Check that the payload length is either 62 or 74 hex characters (equevelnt to 31 or 37 bytes)
|
|
1304
|
+
if len(pkt[PAYLOAD]) != 62 and len(pkt[PAYLOAD]) !=74:
|
|
1305
|
+
return False, f"Payload length is invalid for packet {pkt[PAYLOAD]}"
|
|
1306
|
+
return True, ""
|
|
1307
|
+
|
|
1308
|
+
|
|
1309
|
+
def wiliot_pkts_validation(test, all_messages_in_test, all_data_pkts):
|
|
1310
|
+
PHASE_NAME = "Wiliot packets validation"
|
|
1311
|
+
phase_run_print(PHASE_NAME)
|
|
1312
|
+
wiliot_pkts_validation_phase = cert_utils.Phase(PHASE_NAME, rc=TEST_PASSED)
|
|
1313
|
+
|
|
1314
|
+
if len(all_messages_in_test) == 0:
|
|
1315
|
+
wiliot_pkts_validation_phase.rc = TEST_FAILED
|
|
1316
|
+
wiliot_pkts_validation_phase.reason = "No packets to validate"
|
|
1317
|
+
|
|
1318
|
+
if wiliot_pkts_validation_phase.rc != TEST_FAILED:
|
|
1319
|
+
wiliot_pkts_validation_phase = timestamps_validation(wiliot_pkts_validation_phase, all_messages_in_test, test.dut.upload_wait_time)
|
|
1320
|
+
|
|
1321
|
+
if wiliot_pkts_validation_phase.rc != TEST_FAILED:
|
|
1322
|
+
wiliot_pkts_validation_phase = seq_id_validation(wiliot_pkts_validation_phase, all_data_pkts)
|
|
1323
|
+
|
|
1324
|
+
field_functionality_pass_fail_print(wiliot_pkts_validation_phase, PHASE_NAME)
|
|
1325
|
+
test.add_phase(wiliot_pkts_validation_phase)
|
|
1326
|
+
return test
|
|
1327
|
+
|
|
1328
|
+
|
|
1329
|
+
def seq_id_validation(wiliot_pkts_validation_phase, all_data_pkts):
|
|
1330
|
+
# Dedup packet if it is aggregated packets with the same sequenceId
|
|
1331
|
+
all_data_pkts = dedup_aggregated_packets(all_data_pkts)
|
|
1332
|
+
required_sequenceId = 0
|
|
1333
|
+
# check that for every packet received the sequenceId is incremental:
|
|
1334
|
+
for idx, pkt in enumerate(all_data_pkts):
|
|
1335
|
+
# check that there is sequenceId in all packets
|
|
1336
|
+
if SEQUENCE_ID not in pkt:
|
|
1337
|
+
wiliot_pkts_validation_phase.rc = TEST_FAILED
|
|
1338
|
+
wiliot_pkts_validation_phase.reason = f'No sequenceId in packet {pkt[PAYLOAD]}.'
|
|
1339
|
+
break
|
|
1340
|
+
if idx == 0:
|
|
1341
|
+
required_sequenceId = all_data_pkts[0][SEQUENCE_ID]
|
|
1342
|
+
pkt_sequenceId = pkt[SEQUENCE_ID]
|
|
1343
|
+
if pkt_sequenceId != required_sequenceId:
|
|
1344
|
+
wiliot_pkts_validation_phase.rc = TEST_FAILED
|
|
1345
|
+
wiliot_pkts_validation_phase.reason = (f'SequenceId is not incremental. Expected {required_sequenceId}, received {pkt_sequenceId}, '
|
|
1346
|
+
'this may be caused by packets drops in the wifi chip side')
|
|
1347
|
+
break
|
|
1348
|
+
required_sequenceId += 1
|
|
1349
|
+
if len(all_data_pkts) == 0:
|
|
1350
|
+
wiliot_pkts_validation_phase.rc = TEST_FAILED
|
|
1351
|
+
wiliot_pkts_validation_phase.reason = "No packets to validate"
|
|
1352
|
+
return wiliot_pkts_validation_phase
|
|
1353
|
+
|
|
1354
|
+
|
|
1355
|
+
def dedup_aggregated_packets(all_data_pkts):
|
|
1356
|
+
deduped_packets = []
|
|
1357
|
+
for pkt in all_data_pkts:
|
|
1358
|
+
if AGGREGATED_PAYLOAD not in pkt:
|
|
1359
|
+
deduped_packets.append(pkt)
|
|
1360
|
+
else:
|
|
1361
|
+
# Check if a packet with the same AGGREGATED_PAYLOAD already exists
|
|
1362
|
+
already_exists = any(existing_pkt[AGGREGATED_PAYLOAD] == pkt[AGGREGATED_PAYLOAD]
|
|
1363
|
+
for existing_pkt in deduped_packets
|
|
1364
|
+
if AGGREGATED_PAYLOAD in existing_pkt)
|
|
1365
|
+
if not already_exists:
|
|
1366
|
+
deduped_packets.append(pkt)
|
|
1367
|
+
|
|
1368
|
+
return deduped_packets
|
|
1369
|
+
|
|
1370
|
+
|
|
1371
|
+
def timestamps_validation(wiliot_pkts_validation_phase, all_messages_in_test, upload_wait_time):
|
|
1372
|
+
previous_ts = 0
|
|
1373
|
+
for full_pkt in all_messages_in_test:
|
|
1374
|
+
if full_pkt.mqtt_timestamp - full_pkt.body[TIMESTAMP] >= 10000:
|
|
1375
|
+
wiliot_pkts_validation_phase.rc = TEST_FAILED
|
|
1376
|
+
wiliot_pkts_validation_phase.reason = f'More then 10 seconds GW publication and MQTT receive time'
|
|
1377
|
+
return wiliot_pkts_validation_phase
|
|
1378
|
+
|
|
1379
|
+
if PACKETS in full_pkt.body_ex:
|
|
1380
|
+
for idx, inner_pkt in enumerate(full_pkt.body_ex[PACKETS]):
|
|
1381
|
+
if TIMESTAMP not in inner_pkt:
|
|
1382
|
+
wiliot_pkts_validation_phase.rc = TEST_FAILED
|
|
1383
|
+
wiliot_pkts_validation_phase.reason = f"No timestamps in inner packet, for pkt {inner_pkt}"
|
|
1384
|
+
return wiliot_pkts_validation_phase
|
|
1385
|
+
if idx == 0:
|
|
1386
|
+
if full_pkt.body[TIMESTAMP] - inner_pkt[TIMESTAMP] >= 10000 + upload_wait_time and \
|
|
1387
|
+
previous_ts < inner_pkt[TIMESTAMP]:
|
|
1388
|
+
wiliot_pkts_validation_phase.rc = TEST_FAILED
|
|
1389
|
+
wiliot_pkts_validation_phase.reason = f'More then {10 + upload_wait_time}'
|
|
1390
|
+
f' seconds between publication and inner message,for ts {inner_pkt[TIMESTAMP]}'
|
|
1391
|
+
return wiliot_pkts_validation_phase
|
|
1392
|
+
previous_ts = inner_pkt[TIMESTAMP]
|
|
1393
|
+
else:
|
|
1394
|
+
if inner_pkt[TIMESTAMP] < previous_ts:
|
|
1395
|
+
wiliot_pkts_validation_phase.rc = TEST_FAILED
|
|
1396
|
+
wiliot_pkts_validation_phase.reason = f'Timestamp is not incremental for inner packet {inner_pkt[PAYLOAD]}'
|
|
1397
|
+
return wiliot_pkts_validation_phase
|
|
1398
|
+
previous_ts = inner_pkt[TIMESTAMP]
|
|
1399
|
+
return wiliot_pkts_validation_phase
|
|
1400
|
+
|
|
1401
|
+
################### Stress test helper functions ###################
|
|
1402
|
+
|
|
1403
|
+
def generate_graph_stress_test(test, results, test_pkts_received):
|
|
1404
|
+
# Create DataFrame from results list [pps1, percentage1, pps2, percentage2, ...]
|
|
1405
|
+
graph_data = []
|
|
1406
|
+
for i in range(0, len(results), 2):
|
|
1407
|
+
if i + 1 < len(results):
|
|
1408
|
+
graph_data.append({'pkts_per_sec': results[i], 'received_pps': results[i + 1]})
|
|
1409
|
+
|
|
1410
|
+
graph_df = pd.DataFrame(graph_data)
|
|
1411
|
+
html_file_path = os.path.join(ARTIFACTS_DIR, test.dir, 'stress_graph.html')
|
|
1412
|
+
|
|
1413
|
+
# First graph: percentage received vs packets per second
|
|
1414
|
+
fig1 = px.line(graph_df, x='pkts_per_sec', y='received_pps',
|
|
1415
|
+
title='Packets Per Second Uploaded vs Packets Per Second Advertised',
|
|
1416
|
+
labels={'pkts_per_sec': 'Advertised PPS', 'received_pps': 'Uploaded PPS'},
|
|
1417
|
+
markers=True, text='received_pps')
|
|
1418
|
+
|
|
1419
|
+
# Set y-axis to [0 - highest_pps] scale
|
|
1420
|
+
fig1.update_yaxes(range=[0, results[-2]])
|
|
1421
|
+
|
|
1422
|
+
# Position text labels next to the markers
|
|
1423
|
+
fig1.update_traces(textposition="top right")
|
|
1424
|
+
|
|
1425
|
+
# Second graph: sequenceID vs time
|
|
1426
|
+
seq_id_fig = None
|
|
1427
|
+
seq_id_data = []
|
|
1428
|
+
for pkt in test_pkts_received:
|
|
1429
|
+
if SEQUENCE_ID in pkt and TIMESTAMP in pkt:
|
|
1430
|
+
seq_id_data.append({
|
|
1431
|
+
SEQUENCE_ID: pkt[SEQUENCE_ID],
|
|
1432
|
+
TIMESTAMP: pkt[TIMESTAMP]
|
|
1433
|
+
})
|
|
1434
|
+
|
|
1435
|
+
if seq_id_data:
|
|
1436
|
+
seq_id_df = pd.DataFrame(seq_id_data)
|
|
1437
|
+
seq_id_df = seq_id_df.sort_values(by=TIMESTAMP)
|
|
1438
|
+
# Convert timestamp to datetime for better display
|
|
1439
|
+
seq_id_df['datetime'] = seq_id_df[TIMESTAMP].apply(lambda x: datetime.datetime.fromtimestamp(x/1e3))
|
|
1440
|
+
seq_id_fig = px.scatter(seq_id_df, x='datetime', y=SEQUENCE_ID,
|
|
1441
|
+
title='Sequence ID vs Time',
|
|
1442
|
+
labels={'datetime': 'Time', SEQUENCE_ID: 'Sequence ID'})
|
|
1443
|
+
|
|
1444
|
+
# Write both graphs to HTML file
|
|
1445
|
+
with open(html_file_path, 'w') as f:
|
|
1446
|
+
f.write(fig1.to_html(full_html=False, include_plotlyjs='cdn', include_mathjax='cdn'))
|
|
1447
|
+
f.write("<br>")
|
|
1448
|
+
if seq_id_fig:
|
|
1449
|
+
f.write(seq_id_fig.to_html(full_html=False, include_plotlyjs='cdn', include_mathjax='cdn'))
|
|
1450
|
+
|
|
1451
|
+
|
|
1452
|
+
def stress_analysis(test, pps, sent_pkts, received_pkts):
|
|
1453
|
+
|
|
1454
|
+
_sent_pkts = [p[12:] for p in sent_pkts]
|
|
1455
|
+
sent_df = pd.DataFrame(_sent_pkts, columns=[PACKETS])
|
|
1456
|
+
received_df = pd.DataFrame(received_pkts, columns=[PACKETS])
|
|
1457
|
+
|
|
1458
|
+
# No need to drop duplicates, in the stress test each packet is sent only once
|
|
1459
|
+
merged_df = pd.merge(sent_df, received_df, on=PACKETS, how='inner')
|
|
1460
|
+
pkts_sent_count = len(sent_df)
|
|
1461
|
+
pkts_received_count = len(merged_df)
|
|
1462
|
+
|
|
1463
|
+
# Prints and calculations
|
|
1464
|
+
percentage_received = round(pkts_received_count * 100 / pkts_sent_count)
|
|
1465
|
+
utPrint(f'Sent: {pkts_sent_count}, Received: {pkts_received_count} ({percentage_received}%)', "BLUE")
|
|
1466
|
+
received_pps = pps * percentage_received / 100
|
|
1467
|
+
|
|
1468
|
+
# PASS/FAIL logic
|
|
1469
|
+
if percentage_received < 1: # If less than 1% of the packets were received, fail the test
|
|
1470
|
+
test.set_phase_rc(str(pps), TEST_FAILED)
|
|
1471
|
+
test.add_phase_reason(str(pps), f"{percentage_received}% of the packets were scanned & uploaded by the gateway")
|
|
1472
|
+
else:
|
|
1473
|
+
test.set_phase_rc(str(pps), TEST_PASSED)
|
|
1474
|
+
test.add_phase_reason(str(pps), f"received pps: {received_pps} ({percentage_received}% of packets)")
|
|
1475
|
+
|
|
1476
|
+
return test, received_pps
|
|
1477
|
+
|
|
1478
|
+
|
|
1479
|
+
def generate_adv_payload(test_indicator, unique_pkt=False):
|
|
1480
|
+
# Keep last 4 bytes as zeroes so for incrementing them in FW 'ble_sim'
|
|
1481
|
+
adva = hex2alias_id_get(get_random_hex_str(12))
|
|
1482
|
+
unique_pkt_byte = get_random_hex_str(2) if unique_pkt == False else "00"
|
|
1483
|
+
payload = (ag.Hdr(group_id=ag.GROUP_ID_UNIFIED_PKT_V2).dump() + test_indicator +
|
|
1484
|
+
get_random_hex_str(32) + unique_pkt_byte + "00000000")
|
|
1485
|
+
return adva + payload
|
|
1486
|
+
|
|
1487
|
+
def change_endianness(hex_str: str) -> str:
|
|
1488
|
+
return ''.join(f"{b:02X}" for b in bytes.fromhex(hex_str)[::-1])
|