wiliot-certificate 1.5.2a1__py3-none-any.whl → 1.5.3a1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. brg_certificate/ag/energous_v0_defines.py +3 -3
  2. brg_certificate/ag/energous_v1_defines.py +3 -3
  3. brg_certificate/ag/energous_v2_defines.py +3 -3
  4. brg_certificate/ag/energous_v3_defines.py +3 -3
  5. brg_certificate/ag/energous_v4_defines.py +3 -3
  6. brg_certificate/ag/fanstel_lan_v0_defines.py +3 -3
  7. brg_certificate/ag/fanstel_lte_v0_defines.py +3 -3
  8. brg_certificate/ag/fanstel_wifi_v0_defines.py +3 -3
  9. brg_certificate/ag/minew_lte_v0_defines.py +3 -3
  10. brg_certificate/ag/wlt_types.html +3 -3
  11. brg_certificate/ag/wlt_types_ag.py +8 -8
  12. brg_certificate/cert_common.py +61 -11
  13. brg_certificate/cert_config.py +12 -7
  14. brg_certificate/cert_utils.py +3 -1
  15. brg_certificate/certificate_bcc_test_list.txt +2 -2
  16. brg_certificate/certificate_test_list.txt +2 -2
  17. brg_certificate/tests/calibration/interval_test/interval_test.py +1 -1
  18. brg_certificate/tests/calibration/output_power_test/output_power_test.py +1 -1
  19. brg_certificate/tests/calibration/pattern_test/pattern_test.py +2 -2
  20. brg_certificate/tests/datapath/aging_test/aging_test.py +1 -1
  21. brg_certificate/tests/datapath/num_of_tags_test/num_of_tags_test.py +1 -1
  22. brg_certificate/tests/datapath/output_power_test/output_power_test.py +1 -1
  23. brg_certificate/tests/datapath/pacer_interval_ble5_test/pacer_interval_ble5_test.py +1 -1
  24. brg_certificate/tests/datapath/pacer_interval_tags_count_test/pacer_interval_tags_count_test.py +1 -1
  25. brg_certificate/tests/datapath/pacer_interval_test/pacer_interval_test.py +1 -1
  26. brg_certificate/tests/datapath/pattern_test/pattern_test.py +1 -1
  27. brg_certificate/tests/datapath/pkt_filter_gen3_test/pkt_filter_gen3_test.py +1 -1
  28. brg_certificate/tests/datapath/pkt_filter_test/pkt_filter_test.py +1 -1
  29. brg_certificate/tests/datapath/rssi_threshold_test/rssi_threshold_test.py +1 -1
  30. brg_certificate/tests/datapath/rx_channel_test/rx_channel_test.py +1 -1
  31. brg_certificate/tests/datapath/rx_rate_gen2_test/rx_rate_gen2_test.py +1 -1
  32. brg_certificate/tests/datapath/rx_rate_gen3_test/rx_rate_gen3_test.py +1 -1
  33. brg_certificate/tests/datapath/stress_gen3_test/stress_gen3_test.py +1 -1
  34. brg_certificate/tests/datapath/stress_test/stress_test.py +1 -1
  35. brg_certificate/tests/datapath/tx_repetition_algo_test/tx_repetition_algo_test.py +1 -1
  36. brg_certificate/tests/datapath/tx_repetition_test/tx_repetition_test.py +1 -1
  37. brg_certificate/tests/edge_mgmt/actions_test/actions_test.py +9 -9
  38. brg_certificate/tests/edge_mgmt/brg2brg_ota_ble5_test/brg2brg_ota_ble5_test.py +1 -1
  39. brg_certificate/tests/edge_mgmt/leds_test/leds_test.py +2 -2
  40. brg_certificate/tests/energy2400/duty_cycle_test/duty_cycle_test.py +1 -1
  41. brg_certificate/tests/energy2400/output_power_test/output_power_test.py +1 -1
  42. brg_certificate/tests/energy2400/pattern_test/pattern_test.py +1 -1
  43. brg_certificate/tests/energy2400/signal_indicator_ble5_10_250k_test/signal_indicator_ble5_10_250k_test.json +2 -2
  44. brg_certificate/tests/energy2400/signal_indicator_ble5_10_250k_test/signal_indicator_ble5_10_250k_test.py +256 -278
  45. brg_certificate/tests/energy2400/signal_indicator_ble5_10_500k_test/signal_indicator_ble5_10_500k_test.json +2 -2
  46. brg_certificate/tests/energy2400/signal_indicator_ble5_10_500k_test/signal_indicator_ble5_10_500k_test.py +256 -278
  47. brg_certificate/tests/energy2400/signal_indicator_sub1g_2_4_test/signal_indicator_sub1g_2_4_test.py +3 -3
  48. brg_certificate/tests/energy2400/signal_indicator_test/signal_indicator_test.py +24 -87
  49. brg_certificate/tests/energy_sub1g/duty_cycle_test/duty_cycle_test.py +1 -1
  50. brg_certificate/tests/energy_sub1g/pattern_test/pattern_test.py +1 -1
  51. brg_certificate/tests/energy_sub1g/signal_indicator_functionality_test/signal_indicator_functionality_test.py +2 -2
  52. brg_certificate/tests/energy_sub1g/signal_indicator_test/signal_indicator_test.py +1 -1
  53. brg_certificate/tests/pwr_mgmt/pwr_mgmt_test/pwr_mgmt_test.py +2 -2
  54. brg_certificate/tests/sensors/ext_sensor_test/ext_sensor_test.py +2 -2
  55. gw_certificate/api_if/gw_capabilities.py +37 -1
  56. gw_certificate/common/serialization_formatter.py +80 -0
  57. gw_certificate/common/wltPb_pb2.py +50 -38
  58. gw_certificate/common/wltPb_pb2.pyi +40 -34
  59. gw_certificate/gw_certificate.py +4 -2
  60. gw_certificate/gw_certificate_cli.py +5 -4
  61. gw_certificate/interface/4.4.82_app.zip +0 -0
  62. gw_certificate/interface/{4.4.52_sd_bl_app.zip → 4.4.82_sd_bl_app.zip} +0 -0
  63. gw_certificate/interface/mqtt.py +39 -23
  64. gw_certificate/interface/pkt_generator.py +0 -44
  65. gw_certificate/interface/uart_if.py +20 -9
  66. gw_certificate/tests/actions.py +33 -5
  67. gw_certificate/tests/connection.py +3 -1
  68. gw_certificate/tests/generic.py +1 -1
  69. gw_certificate/tests/registration.py +4 -4
  70. gw_certificate/tests/static/generated_packet_table.py +47 -25
  71. gw_certificate/tests/static/packet_table.csv +10067 -10051
  72. gw_certificate/tests/static/uplink_defines.py +1 -0
  73. gw_certificate/tests/uplink.py +142 -22
  74. {wiliot_certificate-1.5.2a1.dist-info → wiliot_certificate-1.5.3a1.dist-info}/METADATA +1 -1
  75. {wiliot_certificate-1.5.2a1.dist-info → wiliot_certificate-1.5.3a1.dist-info}/RECORD +79 -78
  76. gw_certificate/interface/4.4.52_app.zip +0 -0
  77. {wiliot_certificate-1.5.2a1.dist-info → wiliot_certificate-1.5.3a1.dist-info}/WHEEL +0 -0
  78. {wiliot_certificate-1.5.2a1.dist-info → wiliot_certificate-1.5.3a1.dist-info}/entry_points.txt +0 -0
  79. {wiliot_certificate-1.5.2a1.dist-info → wiliot_certificate-1.5.3a1.dist-info}/licenses/LICENSE +0 -0
  80. {wiliot_certificate-1.5.2a1.dist-info → wiliot_certificate-1.5.3a1.dist-info}/top_level.txt +0 -0
@@ -62,6 +62,28 @@ class UplinkMessage(_message.Message):
62
62
  actionStatus: ActionStatus
63
63
  def __init__(self, gatewayStatus: _Optional[_Union[GatewayStatus, _Mapping]] = ..., gatewayInfo: _Optional[_Union[GatewayInfo, _Mapping]] = ..., gatewayLogs: _Optional[_Union[GatewayLogs, _Mapping]] = ..., actionStatus: _Optional[_Union[ActionStatus, _Mapping]] = ...) -> None: ...
64
64
 
65
+ class ACL(_message.Message):
66
+ __slots__ = ("mode_allow", "ids")
67
+ MODE_ALLOW_FIELD_NUMBER: _ClassVar[int]
68
+ IDS_FIELD_NUMBER: _ClassVar[int]
69
+ mode_allow: bool
70
+ ids: _containers.RepeatedScalarFieldContainer[bytes]
71
+ def __init__(self, mode_allow: bool = ..., ids: _Optional[_Iterable[bytes]] = ...) -> None: ...
72
+
73
+ class GatewayConfigValue(_message.Message):
74
+ __slots__ = ("integerValue", "numberValue", "stringValue", "boolValue", "aclValue")
75
+ INTEGERVALUE_FIELD_NUMBER: _ClassVar[int]
76
+ NUMBERVALUE_FIELD_NUMBER: _ClassVar[int]
77
+ STRINGVALUE_FIELD_NUMBER: _ClassVar[int]
78
+ BOOLVALUE_FIELD_NUMBER: _ClassVar[int]
79
+ ACLVALUE_FIELD_NUMBER: _ClassVar[int]
80
+ integerValue: int
81
+ numberValue: float
82
+ stringValue: str
83
+ boolValue: bool
84
+ aclValue: ACL
85
+ def __init__(self, integerValue: _Optional[int] = ..., numberValue: _Optional[float] = ..., stringValue: _Optional[str] = ..., boolValue: bool = ..., aclValue: _Optional[_Union[ACL, _Mapping]] = ...) -> None: ...
86
+
65
87
  class GatewayStatus(_message.Message):
66
88
  __slots__ = ("gatewayId", "gatewayType", "downlinkSupported", "bridgeOtaUpgradeSupported", "apiVersion", "version", "bleSwVersion", "interfaceSwVersion", "location", "config", "bleAddress")
67
89
  class ConfigEntry(_message.Message):
@@ -69,8 +91,8 @@ class GatewayStatus(_message.Message):
69
91
  KEY_FIELD_NUMBER: _ClassVar[int]
70
92
  VALUE_FIELD_NUMBER: _ClassVar[int]
71
93
  key: str
72
- value: Value
73
- def __init__(self, key: _Optional[str] = ..., value: _Optional[_Union[Value, _Mapping]] = ...) -> None: ...
94
+ value: GatewayConfigValue
95
+ def __init__(self, key: _Optional[str] = ..., value: _Optional[_Union[GatewayConfigValue, _Mapping]] = ...) -> None: ...
74
96
  GATEWAYID_FIELD_NUMBER: _ClassVar[int]
75
97
  GATEWAYTYPE_FIELD_NUMBER: _ClassVar[int]
76
98
  DOWNLINKSUPPORTED_FIELD_NUMBER: _ClassVar[int]
@@ -91,9 +113,9 @@ class GatewayStatus(_message.Message):
91
113
  bleSwVersion: str
92
114
  interfaceSwVersion: str
93
115
  location: Location
94
- config: _containers.MessageMap[str, Value]
116
+ config: _containers.MessageMap[str, GatewayConfigValue]
95
117
  bleAddress: str
96
- def __init__(self, gatewayId: _Optional[str] = ..., gatewayType: _Optional[str] = ..., downlinkSupported: bool = ..., bridgeOtaUpgradeSupported: bool = ..., apiVersion: _Optional[int] = ..., version: _Optional[str] = ..., bleSwVersion: _Optional[str] = ..., interfaceSwVersion: _Optional[str] = ..., location: _Optional[_Union[Location, _Mapping]] = ..., config: _Optional[_Mapping[str, Value]] = ..., bleAddress: _Optional[str] = ...) -> None: ...
118
+ def __init__(self, gatewayId: _Optional[str] = ..., gatewayType: _Optional[str] = ..., downlinkSupported: bool = ..., bridgeOtaUpgradeSupported: bool = ..., apiVersion: _Optional[int] = ..., version: _Optional[str] = ..., bleSwVersion: _Optional[str] = ..., interfaceSwVersion: _Optional[str] = ..., location: _Optional[_Union[Location, _Mapping]] = ..., config: _Optional[_Mapping[str, GatewayConfigValue]] = ..., bleAddress: _Optional[str] = ...) -> None: ...
97
119
 
98
120
  class GatewayInfo(_message.Message):
99
121
  __slots__ = ("entries",)
@@ -115,28 +137,32 @@ class GatewayLogs(_message.Message):
115
137
  def __init__(self, logs: _Optional[_Iterable[str]] = ...) -> None: ...
116
138
 
117
139
  class ActionStatus(_message.Message):
118
- __slots__ = ("action", "status")
140
+ __slots__ = ("action", "status", "step", "progress", "bridgeId")
119
141
  ACTION_FIELD_NUMBER: _ClassVar[int]
120
142
  STATUS_FIELD_NUMBER: _ClassVar[int]
143
+ STEP_FIELD_NUMBER: _ClassVar[int]
144
+ PROGRESS_FIELD_NUMBER: _ClassVar[int]
145
+ BRIDGEID_FIELD_NUMBER: _ClassVar[int]
121
146
  action: int
122
147
  status: int
123
- def __init__(self, action: _Optional[int] = ..., status: _Optional[int] = ...) -> None: ...
148
+ step: int
149
+ progress: int
150
+ bridgeId: bytes
151
+ def __init__(self, action: _Optional[int] = ..., status: _Optional[int] = ..., step: _Optional[int] = ..., progress: _Optional[int] = ..., bridgeId: _Optional[bytes] = ...) -> None: ...
124
152
 
125
153
  class DownlinkMessage(_message.Message):
126
- __slots__ = ("txPacket", "gatewayAction", "bridgeUpgrade", "gatewayConfig", "customBroker", "customMessage")
154
+ __slots__ = ("txPacket", "gatewayAction", "bridgeUpgrade", "gatewayConfig", "customMessage")
127
155
  TXPACKET_FIELD_NUMBER: _ClassVar[int]
128
156
  GATEWAYACTION_FIELD_NUMBER: _ClassVar[int]
129
157
  BRIDGEUPGRADE_FIELD_NUMBER: _ClassVar[int]
130
158
  GATEWAYCONFIG_FIELD_NUMBER: _ClassVar[int]
131
- CUSTOMBROKER_FIELD_NUMBER: _ClassVar[int]
132
159
  CUSTOMMESSAGE_FIELD_NUMBER: _ClassVar[int]
133
160
  txPacket: TxPacket
134
161
  gatewayAction: GatewayAction
135
162
  bridgeUpgrade: BridgeUpgrade
136
163
  gatewayConfig: GatewayConfig
137
- customBroker: CustomBroker
138
164
  customMessage: CustomMessage
139
- def __init__(self, txPacket: _Optional[_Union[TxPacket, _Mapping]] = ..., gatewayAction: _Optional[_Union[GatewayAction, _Mapping]] = ..., bridgeUpgrade: _Optional[_Union[BridgeUpgrade, _Mapping]] = ..., gatewayConfig: _Optional[_Union[GatewayConfig, _Mapping]] = ..., customBroker: _Optional[_Union[CustomBroker, _Mapping]] = ..., customMessage: _Optional[_Union[CustomMessage, _Mapping]] = ...) -> None: ...
165
+ def __init__(self, txPacket: _Optional[_Union[TxPacket, _Mapping]] = ..., gatewayAction: _Optional[_Union[GatewayAction, _Mapping]] = ..., bridgeUpgrade: _Optional[_Union[BridgeUpgrade, _Mapping]] = ..., gatewayConfig: _Optional[_Union[GatewayConfig, _Mapping]] = ..., customMessage: _Optional[_Union[CustomMessage, _Mapping]] = ...) -> None: ...
140
166
 
141
167
  class TxPacket(_message.Message):
142
168
  __slots__ = ("payload", "maxRetries", "maxDurationMs")
@@ -179,8 +205,8 @@ class GatewayConfig(_message.Message):
179
205
  KEY_FIELD_NUMBER: _ClassVar[int]
180
206
  VALUE_FIELD_NUMBER: _ClassVar[int]
181
207
  key: str
182
- value: Value
183
- def __init__(self, key: _Optional[str] = ..., value: _Optional[_Union[Value, _Mapping]] = ...) -> None: ...
208
+ value: GatewayConfigValue
209
+ def __init__(self, key: _Optional[str] = ..., value: _Optional[_Union[GatewayConfigValue, _Mapping]] = ...) -> None: ...
184
210
  VERSION_FIELD_NUMBER: _ClassVar[int]
185
211
  BLESWVERSION_FIELD_NUMBER: _ClassVar[int]
186
212
  INTERFACESWVERSION_FIELD_NUMBER: _ClassVar[int]
@@ -190,28 +216,8 @@ class GatewayConfig(_message.Message):
190
216
  bleSwVersion: str
191
217
  interfaceSwVersion: str
192
218
  location: Location
193
- config: _containers.MessageMap[str, Value]
194
- def __init__(self, version: _Optional[str] = ..., bleSwVersion: _Optional[str] = ..., interfaceSwVersion: _Optional[str] = ..., location: _Optional[_Union[Location, _Mapping]] = ..., config: _Optional[_Mapping[str, Value]] = ...) -> None: ...
195
-
196
- class CustomBroker(_message.Message):
197
- __slots__ = ("customBroker", "port", "brokerUrl", "username", "password", "updateTopic", "statusTopic", "dataTopic")
198
- CUSTOMBROKER_FIELD_NUMBER: _ClassVar[int]
199
- PORT_FIELD_NUMBER: _ClassVar[int]
200
- BROKERURL_FIELD_NUMBER: _ClassVar[int]
201
- USERNAME_FIELD_NUMBER: _ClassVar[int]
202
- PASSWORD_FIELD_NUMBER: _ClassVar[int]
203
- UPDATETOPIC_FIELD_NUMBER: _ClassVar[int]
204
- STATUSTOPIC_FIELD_NUMBER: _ClassVar[int]
205
- DATATOPIC_FIELD_NUMBER: _ClassVar[int]
206
- customBroker: bool
207
- port: int
208
- brokerUrl: str
209
- username: str
210
- password: str
211
- updateTopic: str
212
- statusTopic: str
213
- dataTopic: str
214
- def __init__(self, customBroker: bool = ..., port: _Optional[int] = ..., brokerUrl: _Optional[str] = ..., username: _Optional[str] = ..., password: _Optional[str] = ..., updateTopic: _Optional[str] = ..., statusTopic: _Optional[str] = ..., dataTopic: _Optional[str] = ...) -> None: ...
219
+ config: _containers.MessageMap[str, GatewayConfigValue]
220
+ def __init__(self, version: _Optional[str] = ..., bleSwVersion: _Optional[str] = ..., interfaceSwVersion: _Optional[str] = ..., location: _Optional[_Union[Location, _Mapping]] = ..., config: _Optional[_Mapping[str, GatewayConfigValue]] = ...) -> None: ...
215
221
 
216
222
  class CustomMessage(_message.Message):
217
223
  __slots__ = ("entries",)
@@ -18,8 +18,9 @@ from gw_certificate.interface.ble_simulator import BLESimulator
18
18
  from gw_certificate.interface.mqtt import MqttClient
19
19
  from gw_certificate.tests import *
20
20
  from gw_certificate.interface.uart_ports import get_uart_ports
21
- from gw_certificate.api_if.gw_capabilities import GWCapabilities
21
+ from gw_certificate.api_if.gw_capabilities import GWCapabilities, ConfigurationData
22
22
  from gw_certificate.tests import TESTS_NO_UART
23
+
23
24
  import gw_certificate.cert_results as cert_results
24
25
 
25
26
  GW_CERT_VERSION = importlib.metadata.version("wiliot-certificate")
@@ -58,6 +59,7 @@ class GWCertificate:
58
59
  self.result_pdf_path = os.path.join(self.certificate_dir, f'results_{self.current_datetime.strftime('%Y%m%d_%H%M%S')}.pdf')
59
60
  self.template_engine = TemplateEngine()
60
61
  self.env = env
62
+ self.error = ""
61
63
 
62
64
  # Version
63
65
  self.gw_cert_version = GW_CERT_VERSION
@@ -71,7 +73,7 @@ class GWCertificate:
71
73
  self.stress_pps = stress_pps
72
74
  self.aggregation_time = aggregation_time
73
75
  self.actions = actions
74
- self.error = ""
76
+ self.cfg_data = ConfigurationData()
75
77
 
76
78
  # UART-related. Require only when running tests that need it
77
79
  self.use_uart = not all(test in TESTS_NO_UART for test in tests)
@@ -1,6 +1,6 @@
1
1
 
2
2
  import time
3
- from argparse import ArgumentParser
3
+ from argparse import ArgumentParser, SUPPRESS
4
4
 
5
5
  from gw_certificate.common.debug import debug_print
6
6
  from gw_certificate.gw_certificate import GWCertificate, GW_CERT_VERSION
@@ -27,7 +27,7 @@ def filter_actions(actions_names):
27
27
  def main():
28
28
  usage = (
29
29
  "usage: wlt-gw-certificate [-h] -owner OWNER -gw GW\n"
30
- f" [-tests {{connection, uplink, downlink, actions, stress}}] [-update] [-pps {STRESS_DEFAULT_PPS}]\n"
30
+ f" [-tests {{connection, uplink, downlink, actions, stress}}] [-noupdate] [-pps {STRESS_DEFAULT_PPS}]\n"
31
31
  f" [-actions {{info, reboot, bridgeota}}] [-agg AGG] [-env {{prod, test, dev}}]"
32
32
  )
33
33
 
@@ -44,13 +44,14 @@ def main():
44
44
  default=['connection', 'uplink', 'downlink', 'actions', 'stress'])
45
45
  optional.add_argument('-actions', type=str, choices=['info', 'reboot', 'bridgeota'],
46
46
  help="Action stages to run under ActionsTest", required=False, nargs='+', default=['info', 'reboot', 'bridgeota'])
47
- optional.add_argument('-update', action='store_true', help='Update test board firmware', default=False, required=False)
48
47
  optional.add_argument('-pps', type=int, help='Single packets-per-second rate to simulate in the stress test',
49
48
  choices=STRESS_DEFAULT_PPS, default=None, required=False)
50
49
  optional.add_argument('-agg', type=int, help='Aggregation time [seconds] the Uplink stages wait before processing results',
51
50
  default=0, required=False)
52
51
  optional.add_argument('-env', type=str, help='Environment for the RegistrationTest & BridgeOTAStage',
53
52
  choices=['prod', 'test', 'dev'], default='prod', required=False)
53
+ optional.add_argument('-update', action='store_true', help=SUPPRESS, default=True, required=False)
54
+ optional.add_argument('-noupdate', action='store_true', help='Skip the default certification kit firmware update', default=False, required=False)
54
55
  args = parser.parse_args()
55
56
 
56
57
  topic_suffix = '' if args.suffix == '' else '-'+args.suffix
@@ -72,7 +73,7 @@ def main():
72
73
  parser.error("When running any test other than registration, the gateway must be registered to an owner which should be provided using the '-owner' flag.")
73
74
 
74
75
 
75
- gwc = GWCertificate(gw_id=args.gw, owner_id=args.owner, topic_suffix=topic_suffix, tests=tests, update_fw=args.update,
76
+ gwc = GWCertificate(gw_id=args.gw, owner_id=args.owner, topic_suffix=topic_suffix, tests=tests, update_fw=(not args.noupdate),
76
77
  stress_pps=args.pps, aggregation_time=args.agg, env=args.env, actions=actions)
77
78
  debug_print(f"All arguments: {vars(args)}")
78
79
  gwc.run_tests()
Binary file
@@ -346,7 +346,7 @@ class MqttClient:
346
346
  return message.body_ex
347
347
  return None
348
348
 
349
- def get_gw_configuration(self):
349
+ def get_gw_configuration_reboot(self):
350
350
  self.flush_messages()
351
351
  self.send_action(GwAction.REBOOT_GW)
352
352
  debug_print('---GW CONFIG---')
@@ -360,20 +360,29 @@ class MqttClient:
360
360
  if mqtt_mode == 'legacy':
361
361
  return self.send_action(GwAction.DISABLE_DEV_MODE)
362
362
  elif mqtt_mode == 'automatic':
363
- custom_mqtt = {
364
- "customBroker": False,
365
- "brokerUrl": "",
366
- "port": 8883,
367
- "username": "",
368
- "password": "",
369
- "updateTopic": f"update/{self.owner_id}/{self.gw_id}",
370
- "statusTopic": f"status/{self.owner_id}/{self.gw_id}",
371
- "dataTopic": f"data/{self.owner_id}/{self.gw_id}"
372
- }
373
363
  if self.get_serialization() in {Serialization.UNKNOWN, Serialization.JSON}:
364
+ custom_mqtt = {
365
+ "customBroker": False,
366
+ "brokerUrl": "",
367
+ "port": 8883,
368
+ "username": "",
369
+ "password": "",
370
+ "updateTopic": f"update/{self.owner_id}/{self.gw_id}",
371
+ "statusTopic": f"status/{self.owner_id}/{self.gw_id}",
372
+ "dataTopic": f"data/{self.owner_id}/{self.gw_id}"
373
+ }
374
374
  self.send_payload(custom_mqtt)
375
375
  if self.get_serialization() in {Serialization.UNKNOWN, Serialization.PB}:
376
- self.send_payload({'customBroker': custom_mqtt})
376
+ custom_mqtt = wltPb_pb2.DownlinkMessage()
377
+ custom_mqtt.customMessage.entries['customBroker'].CopyFrom(wltPb_pb2.Value(boolValue=False))
378
+ custom_mqtt.customMessage.entries['brokerUrl'].CopyFrom(wltPb_pb2.Value(stringValue=""))
379
+ custom_mqtt.customMessage.entries['port'].CopyFrom(wltPb_pb2.Value(integerValue=8883))
380
+ custom_mqtt.customMessage.entries['username'].CopyFrom(wltPb_pb2.Value(stringValue=""))
381
+ custom_mqtt.customMessage.entries['password'].CopyFrom(wltPb_pb2.Value(stringValue=""))
382
+ custom_mqtt.customMessage.entries['updateTopic'].CopyFrom(wltPb_pb2.Value(stringValue=f"update/{self.owner_id}/{self.gw_id}"))
383
+ custom_mqtt.customMessage.entries['statusTopic'].CopyFrom(wltPb_pb2.Value(stringValue=f"status/{self.owner_id}/{self.gw_id}"))
384
+ custom_mqtt.customMessage.entries['dataTopic'].CopyFrom(wltPb_pb2.Value(stringValue=f"data/{self.owner_id}/{self.gw_id}"))
385
+ self.send_payload(custom_mqtt)
377
386
  elif mqtt_mode == 'manual':
378
387
  debug_print(f"Make sure GW {self.gw_id} is set to Wiliot MQTT broker")
379
388
  return True
@@ -383,6 +392,15 @@ class MqttClient:
383
392
  self.userdata = {'messages': WltMqttMessages(), 'gw_seen': False , 'logger': self.logger, 'serialization':self.get_serialization(), 'published':[]}
384
393
  self.client.user_data_set(self.userdata)
385
394
 
395
+ def flush_messages_topic(self, topic:Literal['status', 'data', 'update']):
396
+ if topic == 'data':
397
+ self.userdata['messages'].data = []
398
+ elif topic == 'status':
399
+ self.userdata['messages'].status = []
400
+ elif topic == 'update':
401
+ self.userdata['messages'].update = []
402
+
403
+
386
404
  def get_all_messages_from_topic(self, topic:Literal['status', 'data', 'update']):
387
405
  return getattr(self.userdata['messages'], topic)
388
406
 
@@ -406,19 +424,21 @@ class MqttClient:
406
424
  elif GATEWAYSTATUS in message.body_ex.keys():
407
425
  return message.body_ex[GATEWAYSTATUS]
408
426
  return None
409
-
427
+
410
428
  def get_action_status_message(self):
429
+ # Implemented with a list since we can't expect when the GW will publish a msg. To avoid flushing it.
411
430
  messages = self.get_all_messages_from_topic('status')
431
+ action_status_msgs = []
412
432
  for message in messages:
413
433
  if GW_LOGS not in message.body_ex.keys():
414
434
  if STATUS_CODE_STR in message.body_ex.keys():
415
- return message.body_ex
435
+ action_status_msgs.append(message.body_ex)
416
436
  elif ACTIONSTATUS in message.body_ex.keys():
417
- if 'status' not in message.body_ex[ACTIONSTATUS].keys():
418
- # Default values are omitted in protobuf, set 0 for explicitness
419
- message.body_ex[ACTIONSTATUS]['status'] = 0
420
- return message.body_ex[ACTIONSTATUS]
421
- return None
437
+ message.body_ex[ACTIONSTATUS].setdefault('status', 0)
438
+ action_status_msgs.append(message.body_ex[ACTIONSTATUS])
439
+ if len(action_status_msgs) == 0:
440
+ return None
441
+ return action_status_msgs[-1]
422
442
 
423
443
  def get_coupled_tags_pkts(self):
424
444
  return [p for p in self.get_all_pkts_from_topic('data') if NFPKT in p]
@@ -517,9 +537,6 @@ def on_message_protobuf(mqttc, userdata, message):
517
537
  try:
518
538
  pb_message = wltPb_pb2.GatewayData()
519
539
  pb_message.ParseFromString(message.payload)
520
- # # Decode packets payloads as hex
521
- # for idx, packet in enumerate(pb_message.packets):
522
- # pb_message.packets[idx].payload = packet.payload.hex().upper().encode('utf-8')
523
540
  except DecodeError as e:
524
541
  userdata['logger'].debug(f'{message.topic}: An exception occured:\n{e}\n(could be a JSON msg or pb msg that is not UplinkMessage)###########')
525
542
  userdata['logger'].debug(f'Raw Payload: {message.payload}')
@@ -528,7 +545,6 @@ def on_message_protobuf(mqttc, userdata, message):
528
545
  userdata['logger'].debug(f'{message.topic}: {message.payload}')
529
546
  if pb_message is not None:
530
547
  pb_message_dict = MessageToDict(pb_message)
531
- # Decode b64 packet payloads to hex
532
548
  if 'data' in message.topic and 'packets' in pb_message_dict.keys():
533
549
  for idx, packet in enumerate(pb_message_dict['packets']):
534
550
  pb_message_dict['packets'][idx]['payload'] = base64.b64decode(packet['payload']).hex().upper()
@@ -185,15 +185,6 @@ class TagPktGenerator:
185
185
  assert len(pkt) == 62, "packet must be 74 / 62 hex chars long!"
186
186
  self.data_packet.set(pkt)
187
187
 
188
- def get_expected_mqtt(self):
189
- timestamp = int(datetime.datetime.now().timestamp() * 1000)
190
- expected = {
191
- TIMESTAMP: timestamp,
192
- PAYLOAD: self.get_packet()[ADVA_LENGTH+GAP_LENGTH:]
193
- }
194
- return expected
195
-
196
-
197
188
 
198
189
  class BrgPktGenerator:
199
190
  """Bridge Packet Generator - represents 1 wiliot Bridge"""
@@ -451,41 +442,6 @@ class BrgPktGenerator:
451
442
  }
452
443
  return [expected_data, expected_si]
453
444
 
454
- def get_expected_mqtt_unified(self, full_data_pkt, tag_idx:int=None):
455
- if tag_idx is None:
456
- tag_idx = 0
457
- assert tag_idx <= len(self.tag_list), f'Tag index must be in {[i for i in range(len(self.tag_list))]}'
458
-
459
- def extract_param_from_pkt():
460
- # Take only the relevant digis from the data packet
461
- param_hex_string = full_data_pkt[46:-22]
462
- if len(param_hex_string) != 6:
463
- raise ValueError("The parameters hex representation must be 6 digits long")
464
-
465
- # Convert to decimal from binari and assign
466
- param_binari_string = bin(int(param_hex_string, 16))[2:].zfill(24)
467
- nfpkt = int(param_binari_string[:8], 2)
468
- rssi = int(param_binari_string[8:14], 2)
469
- # Note: rssi here is -40 then the actual value. This portion is to be added on cloud
470
- brg_latency = int(param_binari_string[14:20], 2)
471
- brg_global_pacing_group = int(param_binari_string[20:], 2)
472
- return [nfpkt, rssi, brg_latency, brg_global_pacing_group]
473
-
474
- """generates expected MQTT packet"""
475
- timestamp = int(datetime.datetime.now().timestamp() * 1000)
476
- pkt_param = extract_param_from_pkt()
477
-
478
- expected_data = {
479
- TIMESTAMP: timestamp,
480
- BRIDGE_ID: self.bridge_id,
481
- NFPKT: pkt_param[0],
482
- RSSI: pkt_param[1],
483
- BRG_LATENCY: pkt_param[2],
484
- BRG_GLOBAL_PACING_GROUP: pkt_param[3],
485
- PAYLOAD: full_data_pkt[(ADVA_LENGTH+GAP_LENGTH):]
486
- }
487
- return [expected_data]
488
-
489
445
  def get_expected_hb_mqtt(self):
490
446
  timestamp = int(datetime.datetime.now().timestamp() * 1000)
491
447
  expected = {
@@ -12,7 +12,7 @@ import pkg_resources
12
12
  from gw_certificate.common.debug import debug_print
13
13
  from gw_certificate.interface.if_defines import *
14
14
 
15
- LATEST_VERSION = '4.4.52'
15
+ LATEST_VERSION = '4.4.82'
16
16
  LATEST_VERSION_FILE = f'{LATEST_VERSION}_sd_bl_app.zip'
17
17
  LATEST_VERSION_PATH = pkg_resources.resource_filename(__name__, LATEST_VERSION_FILE)
18
18
  LATEST_VERSION_FILE_APP = f'{LATEST_VERSION}_app.zip'
@@ -43,7 +43,8 @@ class UARTInterface:
43
43
  if not update_status:
44
44
  raise UARTError('Update Failed! Update FW manually using NRF Tools')
45
45
  if self.fw_version >= version.Version('3.17.0'):
46
- self.write_ble_command(GATEWAY_APP)
46
+ if self.fw_version < version.Version('4.4.0'):
47
+ self.write_ble_command(GATEWAY_APP)
47
48
  self.flush()
48
49
  debug_print(f'Serial Connection {comport} Initialized')
49
50
 
@@ -79,14 +80,16 @@ class UARTInterface:
79
80
  debug_print(answer)
80
81
  return answer
81
82
 
82
- def flush(self):
83
+ def flush(self, request_power_cycle=False):
83
84
  self.serial.close()
85
+ if request_power_cycle:
86
+ input('Please power cycle (unplug and replug from your pc) the certificate kit. Press enter when plugged')
84
87
  time.sleep(2)
85
88
  self.serial.open()
86
89
  self.serial.flushInput()
87
90
  self.serial.flush()
88
91
  self.serial.reset_output_buffer()
89
-
92
+
90
93
  def reset_gw(self, stop_advertising=True):
91
94
  self.flush()
92
95
  self.write_ble_command(RESET_GW)
@@ -104,16 +107,20 @@ class UARTInterface:
104
107
  if self.gw_app_rx is None:
105
108
  self.reset_gw()
106
109
 
107
- if self.fw_version >= version.Version('3.17.0'):
110
+ if self.fw_version >= version.Version('4.4.0'):
111
+ # full_cfg isn't supported anymore. RX channels are configured by set_sniffer.
112
+ pass
113
+ elif self.fw_version >= version.Version('3.17.0'):
108
114
  # from 3.17.0, only full_cfg can be used to configure channels. sending it with:
109
115
  # Data coupling(DC) off, wifi(NW) and mqtt(MQ) on.
110
116
  rx_ch_to_fw_enums = {37: 2, 38: 3, 39: 4}
111
117
  cmd = f'!full_cfg DM {rx_ch_to_fw_enums[rx_channel]} DC 0 NW 1 MQ 1 CH {rx_channel}'
112
118
  # cmd = '!gateway_app'
119
+ self.write_ble_command(cmd)
113
120
  else:
114
121
  cmd = f'!gateway_app {rx_channel} 30 0 17'
122
+ self.write_ble_command(cmd)
115
123
 
116
- self.write_ble_command(cmd)
117
124
  self.gw_app_rx = rx_channel
118
125
 
119
126
  def set_sniffer(self, rx_channel):
@@ -128,7 +135,11 @@ class UARTInterface:
128
135
  time.sleep(1)
129
136
 
130
137
  def cancel_sniffer(self):
131
- self.write_ble_command(CANCEL_SNIFFER)
138
+ if self.fw_version >= version.Version('4.4.0'):
139
+ # Set_logger_mode must have 2 args, even when disabled.
140
+ self.write_ble_command(f'{CANCEL_SNIFFER} 37')
141
+ else:
142
+ self.write_ble_command(CANCEL_SNIFFER)
132
143
  self.flush()
133
144
 
134
145
  def get_version_mac(self):
@@ -197,8 +208,8 @@ class UARTInterface:
197
208
  return_code = dfu_full_process.returncode
198
209
  for line in dfu_full_process.stderr:
199
210
  if NRFUTIL_FW_TOO_LOW_ERROR in line:
200
- debug_print(f"DFU failed due to firmware (bootloader/application) version being too low.")
201
- debug_print(f"Probably since bootloader is already upgraded. Attempting to upgrade application only..")
211
+ debug_print(f"DFU failed because bootloader/application version is too high.")
212
+ debug_print(f"Attempting to upgrade application only..")
202
213
  dfu_app_process = subprocess.Popen(f'{nrfutil_file} dfu serial --package "{LATEST_VERSION_PATH_APP}" -p {self.comport} -fc 0 -b 115200 -t 10',
203
214
  stderr=subprocess.PIPE, shell=True, text=True)
204
215
  dfu_app_process.wait()
@@ -131,7 +131,7 @@ class BridgeOTAStage(GenericActionsStage):
131
131
  self.error_summary = "Bridge wasn't upgraded."
132
132
  self.action = "Bridge Upgrade"
133
133
 
134
- OTA_VERSIONS_TO_USE = ("4.4.52", "4.4.53")
134
+ OTA_VERSIONS_TO_USE = ("4.4.82", "4.4.83")
135
135
  if version.parse(OTA_VERSIONS_TO_USE[0]) != self.uart.fw_version:
136
136
  self.desired_version = version.parse(OTA_VERSIONS_TO_USE[0])
137
137
  else:
@@ -144,6 +144,28 @@ class BridgeOTAStage(GenericActionsStage):
144
144
  debug_print(f"BridgeOTAStage attempt: {str(self.uart.fw_version)} -> {str(self.desired_version)}")
145
145
  # Reset to remove any log/cert mode we had in the kit so it behaves as a bridge
146
146
  self.uart.reset_gw()
147
+
148
+ def is_final_action_status(self, msg):
149
+ LAST_OTA_STEP = 7
150
+ if not isinstance(msg, dict):
151
+ return False
152
+
153
+ step = msg.get('step')
154
+ progress = msg.get('progress')
155
+ status = msg.get('statusCode')
156
+ if status == None:
157
+ # Both json/pb
158
+ status = msg.get('status')
159
+
160
+ if step == None:
161
+ # Old action status
162
+ if status != None:
163
+ return True
164
+ else:
165
+ # New progress action status
166
+ if (step == LAST_OTA_STEP and progress == 100) or (status != 0):
167
+ return True
168
+ return False
147
169
 
148
170
  def run(self):
149
171
  super().run()
@@ -156,15 +178,21 @@ class BridgeOTAStage(GenericActionsStage):
156
178
  self.mqttc.send_bridge_ota_action(self.uart.mac, str(self.desired_version), 200, False, self.gw_id, "aws", self.env)
157
179
  debug_print("Sent a BridgeOTA action to the gateway")
158
180
  debug_print("Waiting for an actionStatus message from the gateway... (timeout=10)")
181
+
159
182
  while datetime.datetime.now() < timeout and self.action_status is None:
160
183
  line = self.uart.read_line()
161
184
  if line != None and 'reset' in line:
162
- self.uart.reset_gw(stop_advertising=False)
163
185
  self.reboot_packet_ts = datetime.datetime.now()
164
186
  debug_print("A reboot packet was received by the bridge")
165
- self.action_status = self.mqttc.get_action_status_message()
187
+ self.uart.reset_gw(stop_advertising=False)
188
+
189
+ # Ignoring progress report until test supported
190
+ msg = self.mqttc.get_action_status_message()
191
+ if self.is_final_action_status(msg):
192
+ self.action_status = msg
166
193
  time.sleep(2)
167
194
 
195
+ debug_print(f'{self.action_status}')
168
196
  if self.action_status != None:
169
197
  debug_print("actionStatus was received from the gateway")
170
198
  self.action_status_ts = datetime.datetime.now()
@@ -181,8 +209,8 @@ class BridgeOTAStage(GenericActionsStage):
181
209
 
182
210
  cur_ver = self.uart.get_version()
183
211
  if cur_ver == None:
184
- debug_print("ERROR: The certificate kit, acting as bridge in this stage, is not responding!")
185
- self.uart.flush()
212
+ debug_print("ERROR: The certificate kit, acting as bridge in this stage, is not responding.")
213
+ self.uart.flush(request_power_cycle=True)
186
214
  cur_ver = self.uart.get_version()
187
215
  if cur_ver == None:
188
216
  raise UARTError("Communication to the certificate kit halted! "
@@ -35,6 +35,7 @@ class ConnectionStage(GenericStage):
35
35
  self.status_message = None
36
36
 
37
37
  while datetime.datetime.now() < timeout and self.status_message is None:
38
+ time.sleep(2)
38
39
  self.status_message = self.mqttc.get_status_message()
39
40
 
40
41
  if self.status_message is not None:
@@ -49,6 +50,7 @@ class ConnectionStage(GenericStage):
49
50
  for key, value in self.status_message.items():
50
51
  if key in GWCapabilities.get_capabilities() and type(value) is bool:
51
52
  self.gw_capabilities.set_capability(key, value)
53
+ self.cfg_data.status_msg_set(self.status_message, self.mqttc.get_serialization())
52
54
 
53
55
  def generate_stage_report(self):
54
56
  self.add_report_header()
@@ -73,7 +75,7 @@ class ConnectionStage(GenericStage):
73
75
 
74
76
  self.add_report_topic_validation('status')
75
77
  else:
76
- self.error_summary = "No message recieved from GW in status topic after 3 mins."
78
+ self.error_summary = f"No message recieved from GW in status topic after {STATUS_MSG_TIMEOUT} mins."
77
79
  self.add_to_stage_report(self.error_summary)
78
80
 
79
81
  self.report_html = self.template_engine.render_template('stage.html', stage=self,
@@ -161,7 +161,7 @@ class GenericStage():
161
161
  self.result_indication = kwargs.get('result_indication', SCORE_BASED)
162
162
  self.stage_pass = MINIMUM_SCORE
163
163
  self.pass_min = kwargs.get('pass_min', PASS_MINIMUM)
164
- self.inconclusive_min = INCONCLUSIVE_MINIMUM
164
+ self.inconclusive_min = kwargs.get('inconclusive_min', INCONCLUSIVE_MINIMUM)
165
165
  self.report = ''
166
166
  self.report_html = ''
167
167
  self.start_time = None
@@ -41,7 +41,7 @@ class Status(Enum):
41
41
  APPROVED = 'approved'
42
42
  ACTIVE = 'active'
43
43
 
44
- class SharedData():
44
+ class RegistrationData():
45
45
  """
46
46
  Hold variables which values must be shared between different stages.
47
47
  gw_online_ts hold the time in which the gateway status became online
@@ -205,7 +205,7 @@ class OnlineStage(GenericRegistrationStage):
205
205
  self.add_to_stage_report("Token acquisition and MQTT connection were done succesfully.")
206
206
  self.add_to_stage_report("Gateway is online.")
207
207
  debug_print("Gateway connected to MQTT successfully, it is online")
208
- self.shared_data.gw_online_ts = datetime.datetime.now()
208
+ self.reg_data.gw_online_ts = datetime.datetime.now()
209
209
 
210
210
  self.report_html = self.template_engine.render_template('stage.html', stage=self,
211
211
  stage_report=self.report.split('\n'))
@@ -259,7 +259,7 @@ class RefreshStage(GenericRegistrationStage):
259
259
  def run(self):
260
260
  super().run()
261
261
  debug_print(f"Waiting for the token to expire..")
262
- timeout = self.shared_data.gw_online_ts + datetime.timedelta(minutes=TOKEN_EXPIRY_MINUTES)
262
+ timeout = self.reg_data.gw_online_ts + datetime.timedelta(minutes=TOKEN_EXPIRY_MINUTES)
263
263
  while datetime.datetime.now() < timeout:
264
264
  time.sleep(BUSY_WAIT_DELAY_SEC)
265
265
 
@@ -313,7 +313,7 @@ class RegistrationTest(GenericTest):
313
313
  raise Exception(f"An API security key must be set to the envrionment variable {self.env_variable} in order to run the RegistrationTest")
314
314
  self.edge = ExtendedEdgeClient(api_sec_key, REG_CERT_OWNER_ID, env=self.env)
315
315
 
316
- self.shared_data = SharedData()
316
+ self.reg_data = RegistrationData()
317
317
 
318
318
  super().__init__(**self.__dict__, test_name=type(self).__name__)
319
319
  stages = STAGES