16
16
#
17
17
18
18
import argparse
19
- import json
20
19
import os
21
20
import pathlib
22
21
import sys
28
27
# Add the path to python_testing folder, in order to be able to import from matter_testing_support
29
28
sys .path .append (os .path .abspath (sys .path [0 ] + "/../../python_testing" ))
30
29
from matter_testing_support import MatterBaseTest , async_test_body , default_matter_test_main # noqa: E402
30
+ from spec_parsing_support import build_xml_clusters # noqa: E402
31
31
32
32
console = None
33
+ xml_clusters = None
33
34
34
35
35
36
def GenerateDevicePicsXmlFiles (clusterName , clusterPicsCode , featurePicsList , attributePicsList , acceptedCommandPicsList , generatedCommandPicsList , outputPathStr ):
36
37
37
38
xmlPath = xmlTemplatePathStr
38
39
fileName = ""
39
40
40
- print (f"Handling PICS for { clusterName } " )
41
+ console . print (f"Handling PICS for { clusterName } " )
41
42
42
43
# Map clusters to common XML template if needed
43
- otaProviderCluster = "OTA Software Update Provider Cluster"
44
- otaRequestorCluster = "OTA Software Update Requestor Cluster"
45
- onOffCluster = "On/Off Cluster"
46
- groupKeyManagementCluster = "Group Key Management Cluster"
47
- nodeOperationalCredentialsCluster = "Node Operational Credentials Cluster"
48
- basicInformationCluster = "Basic Information Cluster"
49
- networkCommissioningCluster = "Network Commissioning Cluster"
50
-
51
- if otaProviderCluster in clusterName or otaRequestorCluster in clusterName :
44
+ if "ICDManagement" == clusterName :
45
+ clusterName = "ICD Management"
46
+
47
+ elif "OTA Software Update Provider" in clusterName or "OTA Software Update Requestor" in clusterName :
52
48
clusterName = "OTA Software Update"
53
49
54
- elif onOffCluster == clusterName :
50
+ elif "On/Off" == clusterName :
55
51
clusterName = clusterName .replace ("/" , "-" )
56
52
57
- elif groupKeyManagementCluster == clusterName :
53
+ elif "Group Key Management" == clusterName :
58
54
clusterName = "Group Communication"
59
55
60
- elif nodeOperationalCredentialsCluster == clusterName or basicInformationCluster == clusterName or networkCommissioningCluster == clusterName :
61
- clusterName = clusterName .replace ("Cluster" , "" ).strip ()
56
+ elif "Wake On LAN" == clusterName or "Low Power" == clusterName :
57
+ clusterName = "Media Cluster"
58
+
59
+ elif "Operational Credentials" == clusterName :
60
+ clusterName = "Node Operational Credentials"
61
+
62
+ elif "Laundry Washer Controls" == clusterName :
63
+ clusterName = "Washer Controls"
64
+
65
+ # Workaround for naming colisions with current logic
66
+ elif "Thermostat" == clusterName :
67
+ clusterName = "Thermostat Cluster"
68
+
69
+ elif "Boolean State" == clusterName :
70
+ clusterName = "Boolean State Cluster"
71
+
72
+ if "AccessControl" in clusterName :
73
+ clusterName = "Access Control cluster"
62
74
63
75
# Determine if file has already been handled and use this file
64
76
for outputFolderFileName in os .listdir (outputPathStr ):
@@ -108,57 +120,61 @@ def GenerateDevicePicsXmlFiles(clusterName, clusterPicsCode, featurePicsList, at
108
120
# Feature PICS
109
121
# console.print(featurePicsList)
110
122
featureNode = root .find ("./clusterSide[@type='Server']/features" )
111
- for picsItem in featureNode :
112
- itemNumberElement = picsItem .find ('itemNumber' )
123
+ if featureNode is not None :
124
+ for picsItem in featureNode :
125
+ itemNumberElement = picsItem .find ('itemNumber' )
113
126
114
- console .print (f"Searching for { itemNumberElement .text } " )
127
+ console .print (f"Searching for { itemNumberElement .text } " )
115
128
116
- if f"{ itemNumberElement .text } " in featurePicsList :
117
- console .print ("Found feature PICS value in XML template ✅" )
118
- supportElement = picsItem .find ('support' )
119
- supportElement .text = "true"
129
+ if f"{ itemNumberElement .text } " in featurePicsList :
130
+ console .print ("Found feature PICS value in XML template ✅" )
131
+ supportElement = picsItem .find ('support' )
132
+ supportElement .text = "true"
120
133
121
134
# Attributes PICS
122
135
# TODO: Only check if list is not empty
123
136
# console.print(attributePicsList)
124
137
serverAttributesNode = root .find ("./clusterSide[@type='Server']/attributes" )
125
- for picsItem in serverAttributesNode :
126
- itemNumberElement = picsItem .find ('itemNumber' )
138
+ if serverAttributesNode is not None :
139
+ for picsItem in serverAttributesNode :
140
+ itemNumberElement = picsItem .find ('itemNumber' )
127
141
128
- console .print (f"Searching for { itemNumberElement .text } " )
142
+ console .print (f"Searching for { itemNumberElement .text } " )
129
143
130
- if f"{ itemNumberElement .text } " in attributePicsList :
131
- console .print ("Found attribute PICS value in XML template ✅" )
132
- supportElement = picsItem .find ('support' )
133
- supportElement .text = "true"
144
+ if f"{ itemNumberElement .text } " in attributePicsList :
145
+ console .print ("Found attribute PICS value in XML template ✅" )
146
+ supportElement = picsItem .find ('support' )
147
+ supportElement .text = "true"
134
148
135
149
# AcceptedCommandList PICS
136
150
# TODO: Only check if list is not empty
137
151
# console.print(acceptedCommandPicsList)
138
152
serverCommandsReceivedNode = root .find ("./clusterSide[@type='Server']/commandsReceived" )
139
- for picsItem in serverCommandsReceivedNode :
140
- itemNumberElement = picsItem .find ('itemNumber' )
153
+ if serverCommandsReceivedNode is not None :
154
+ for picsItem in serverCommandsReceivedNode :
155
+ itemNumberElement = picsItem .find ('itemNumber' )
141
156
142
- console .print (f"Searching for { itemNumberElement .text } " )
157
+ console .print (f"Searching for { itemNumberElement .text } " )
143
158
144
- if f"{ itemNumberElement .text } " in acceptedCommandPicsList :
145
- console .print ("Found acceptedCommand PICS value in XML template ✅" )
146
- supportElement = picsItem .find ('support' )
147
- supportElement .text = "true"
159
+ if f"{ itemNumberElement .text } " in acceptedCommandPicsList :
160
+ console .print ("Found acceptedCommand PICS value in XML template ✅" )
161
+ supportElement = picsItem .find ('support' )
162
+ supportElement .text = "true"
148
163
149
164
# GeneratedCommandList PICS
150
165
# console.print(generatedCommandPicsList)
151
166
# TODO: Only check if list is not empty
152
167
serverCommandsGeneratedNode = root .find ("./clusterSide[@type='Server']/commandsGenerated" )
153
- for picsItem in serverCommandsGeneratedNode :
154
- itemNumberElement = picsItem .find ('itemNumber' )
168
+ if serverCommandsGeneratedNode is not None :
169
+ for picsItem in serverCommandsGeneratedNode :
170
+ itemNumberElement = picsItem .find ('itemNumber' )
155
171
156
- console .print (f"Searching for { itemNumberElement .text } " )
172
+ console .print (f"Searching for { itemNumberElement .text } " )
157
173
158
- if f"{ itemNumberElement .text } " in generatedCommandPicsList :
159
- console .print ("Found generatedCommand PICS value in XML template ✅" )
160
- supportElement = picsItem .find ('support' )
161
- supportElement .text = "true"
174
+ if f"{ itemNumberElement .text } " in generatedCommandPicsList :
175
+ console .print ("Found generatedCommand PICS value in XML template ✅" )
176
+ supportElement = picsItem .find ('support' )
177
+ supportElement .text = "true"
162
178
163
179
# Event PICS (Work in progress)
164
180
# The ability to set event PICS is fairly limited, due to EventList not being supported,
@@ -168,35 +184,36 @@ def GenerateDevicePicsXmlFiles(clusterName, clusterPicsCode, featurePicsList, at
168
184
# 1) Event is mandatody
169
185
# 2) The event is mandatory based on a feature that is supported (Cross check against feature list) (Not supported yet)
170
186
serverEventsNode = root .find ("./clusterSide[@type='Server']/events" )
171
- for picsItem in serverEventsNode :
172
- itemNumberElement = picsItem .find ('itemNumber' )
173
- statusElement = picsItem .find ('status' )
174
-
175
- try :
176
- condition = statusElement .attrib ['cond' ]
177
- console .print (f"Checking { itemNumberElement .text } with conformance { statusElement .text } and condition { condition } " )
178
- except ET .ParseError :
179
- condition = ""
180
- console .print (f"Checking { itemNumberElement .text } with conformance { statusElement .text } " )
181
-
182
- if statusElement .text == "M" :
183
-
184
- # Is event mandated by the server
185
- if condition == clusterPicsCode :
186
- console .print ("Found event mandated by server ✅" )
187
- supportElement = picsItem .find ('support' )
188
- supportElement .text = "true"
189
- continue
190
-
191
- if condition in featurePicsList :
192
- console .print ("Found event mandated by feature ✅" )
193
- supportElement = picsItem .find ('support' )
194
- supportElement .text = "true"
195
- continue
196
-
197
- if condition == "" :
198
- console .print ("Event is mandated without a condition ✅" )
199
- continue
187
+ if serverEventsNode is not None :
188
+ for picsItem in serverEventsNode :
189
+ itemNumberElement = picsItem .find ('itemNumber' )
190
+ statusElement = picsItem .find ('status' )
191
+
192
+ try :
193
+ condition = statusElement .attrib ['cond' ]
194
+ console .print (f"Checking { itemNumberElement .text } with conformance { statusElement .text } and condition { condition } " )
195
+ except ET .ParseError :
196
+ condition = ""
197
+ console .print (f"Checking { itemNumberElement .text } with conformance { statusElement .text } " )
198
+
199
+ if statusElement .text == "M" :
200
+
201
+ # Is event mandated by the server
202
+ if condition == clusterPicsCode :
203
+ console .print ("Found event mandated by server ✅" )
204
+ supportElement = picsItem .find ('support' )
205
+ supportElement .text = "true"
206
+ continue
207
+
208
+ if condition in featurePicsList :
209
+ console .print ("Found event mandated by feature ✅" )
210
+ supportElement = picsItem .find ('support' )
211
+ supportElement .text = "true"
212
+ continue
213
+
214
+ if condition == "" :
215
+ console .print ("Event is mandated without a condition ✅" )
216
+ continue
200
217
201
218
# Grabbing the header from the XML templates
202
219
inputFile = open (f"{ xmlPath } { fileName } " , "r" )
@@ -255,21 +272,28 @@ async def DeviceMapping(devCtrl, nodeID, outputPathStr):
255
272
acceptedCommandListPicsList = []
256
273
generatedCommandListPicsList = []
257
274
258
- clusterClass = getattr (Clusters , devCtrl .GetClusterHandler ().GetClusterInfoById (server )['clusterName' ])
259
275
clusterID = f"0x{ server :04x} "
260
276
261
- # Does the clusterInfoDict contain the found cluster ID?
262
- if clusterID not in clusterInfoDict :
263
- console .print (f"[red]Cluster ID ({ clusterID } ) not in list! ❌" )
277
+ if server > 0x7FFF :
278
+ console .print (f"[red]Cluster outside standard range ({ clusterID } ) not handled! ❌" )
264
279
continue
265
280
266
- clusterName = clusterInfoDict [clusterID ]['Name' ]
267
- clusterPICS = f"{ clusterInfoDict [clusterID ]['PICS_Code' ]} { serverTag } "
281
+ try :
282
+ clusterClass = getattr (Clusters , devCtrl .GetClusterHandler ().GetClusterInfoById (server )['clusterName' ])
283
+ except AttributeError :
284
+ console .print (f"[red]Cluster class not found for ({ clusterID } ) not found! ❌" )
285
+ continue
268
286
269
- console .print (f"{ clusterName } - { clusterPICS } " )
287
+ # Does the the DM XML contain the found cluster ID?
288
+ try :
289
+ clusterName = xml_clusters [server ].name
290
+ clusterPICS = f"{ xml_clusters [server ].pics } { serverTag } "
291
+
292
+ except KeyError :
293
+ console .print (f"[red]Cluster ({ clusterID } ) not found in DM XML! ❌" )
294
+ continue
270
295
271
- # Print PICS for specific server from dict
272
- # console.print(clusterInfoDict[f"0x{server:04x}"])
296
+ console .print (f"{ clusterName } - { clusterPICS } " )
273
297
274
298
# Read feature map
275
299
featureMapResponse = await devCtrl .ReadAttribute (nodeID , [(endpoint , clusterClass .Attributes .FeatureMap )])
@@ -339,8 +363,14 @@ async def DeviceMapping(devCtrl, nodeID, outputPathStr):
339
363
340
364
for client in clientList :
341
365
clusterID = f"0x{ client :04x} "
342
- clusterName = clusterInfoDict [clusterID ]['Name' ]
343
- clusterPICS = f"{ clusterInfoDict [clusterID ]['PICS_Code' ]} { clientTag } "
366
+
367
+ try :
368
+ clusterName = xml_clusters [client ].name
369
+ clusterPICS = f"{ xml_clusters [client ].pics } { clientTag } "
370
+
371
+ except KeyError :
372
+ console .print (f"[red]Cluster ({ clusterID } ) not found in DM XML! ❌" )
373
+ continue
344
374
345
375
console .print (f"{ clusterName } - { clusterPICS } " )
346
376
@@ -357,21 +387,18 @@ def cleanDirectory(pathToClean):
357
387
358
388
359
389
parser = argparse .ArgumentParser ()
360
- parser .add_argument ('--cluster-data' , required = True )
361
390
parser .add_argument ('--pics-template' , required = True )
362
391
parser .add_argument ('--pics-output' , required = True )
363
392
args , unknown = parser .parse_known_args ()
364
393
365
- basePath = os .path .dirname (__file__ )
366
- clusterInfoInputPathStr = args .cluster_data
367
-
368
394
xmlTemplatePathStr = args .pics_template
369
395
if not xmlTemplatePathStr .endswith ('/' ):
370
396
xmlTemplatePathStr += '/'
371
397
372
398
baseOutputPathStr = args .pics_output
373
399
if not baseOutputPathStr .endswith ('/' ):
374
400
baseOutputPathStr += '/'
401
+ outputPathStr = baseOutputPathStr + "GeneratedPICS/"
375
402
376
403
serverTag = ".S"
377
404
clientTag = ".C"
@@ -391,43 +418,20 @@ def cleanDirectory(pathToClean):
391
418
# Endpoint define
392
419
rootNodeEndpointID = 0
393
420
394
- # Load cluster info
395
- inputJson = {}
396
- clusterInfoDict = {}
397
-
398
- print ("Generating cluster data dict from JSON input" )
399
-
400
- with open (clusterInfoInputPathStr , 'rb' ) as clusterInfoInputFile :
401
- clusterInfoJson = json .load (clusterInfoInputFile )
402
-
403
- for cluster in clusterInfoJson :
404
- clusterData = clusterInfoJson [f"{ cluster } " ]["Data created by Script" ]
405
-
406
- try :
407
- # Check if cluster id is a value hex value
408
- clusterIdValid = int (clusterData ["Id" ].lower (), 16 )
409
-
410
- # Add cluster data to dict
411
- clusterInfoDict [clusterData ["Id" ].lower ()] = {
412
- "Name" : clusterData ["Cluster Name" ],
413
- "PICS_Code" : clusterData ["PICS Code" ],
414
- }
415
-
416
- except ValueError :
417
- print (f"Ignore ClusterID: { clusterData ['Id' ]} - { clusterData ['Cluster Name' ]} " )
418
-
419
421
# Load PICS XML templates
420
422
print ("Capture list of PICS XML templates" )
421
423
xmlFileList = os .listdir (xmlTemplatePathStr )
422
424
423
425
# Setup output path
424
- baseOutputPath = pathlib .Path (baseOutputPathStr )
425
- if not baseOutputPath .exists ():
426
+ print (outputPathStr )
427
+
428
+ outputPath = pathlib .Path (outputPathStr )
429
+ if not outputPath .exists ():
426
430
print ("Create output folder" )
427
- baseOutputPath .mkdir ()
431
+ outputPath .mkdir ()
428
432
else :
429
433
print ("Clean output folder" )
430
- cleanDirectory (baseOutputPath )
434
+ cleanDirectory (outputPath )
431
435
432
436
433
437
class DeviceMappingTest (MatterBaseTest ):
@@ -438,8 +442,11 @@ async def test_device_mapping(self):
438
442
global console
439
443
console = Console ()
440
444
445
+ global xml_clusters
446
+ xml_clusters , problems = build_xml_clusters ()
447
+
441
448
# Run device mapping function
442
- await DeviceMapping (self .default_controller , self .dut_node_id , baseOutputPathStr )
449
+ await DeviceMapping (self .default_controller , self .dut_node_id , outputPathStr )
443
450
444
451
445
452
if __name__ == "__main__" :
0 commit comments