Skip to content

Commit a86f73c

Browse files
Merge branch 'master' into YAML-Updates-2-23-2024
2 parents ad6518c + e48ed00 commit a86f73c

File tree

3 files changed

+133
-133
lines changed

3 files changed

+133
-133
lines changed

src/controller/java/BUILD.gn

+1-5
Original file line numberDiff line numberDiff line change
@@ -365,11 +365,7 @@ kotlin_library("kotlin_matter_controller") {
365365

366366
output_name = "KotlinMatterController.jar"
367367

368-
deps = [
369-
":java",
370-
":tlv",
371-
"${chip_root}/third_party/java_deps:annotation",
372-
]
368+
deps = [ ":java" ]
373369

374370
sources = [
375371
"src/matter/controller/CompletionListenerAdapter.kt",

src/tools/PICS-generator/PICSGenerator.py

+124-117
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616
#
1717

1818
import argparse
19-
import json
2019
import os
2120
import pathlib
2221
import sys
@@ -28,37 +27,50 @@
2827
# Add the path to python_testing folder, in order to be able to import from matter_testing_support
2928
sys.path.append(os.path.abspath(sys.path[0] + "/../../python_testing"))
3029
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
3131

3232
console = None
33+
xml_clusters = None
3334

3435

3536
def GenerateDevicePicsXmlFiles(clusterName, clusterPicsCode, featurePicsList, attributePicsList, acceptedCommandPicsList, generatedCommandPicsList, outputPathStr):
3637

3738
xmlPath = xmlTemplatePathStr
3839
fileName = ""
3940

40-
print(f"Handling PICS for {clusterName}")
41+
console.print(f"Handling PICS for {clusterName}")
4142

4243
# 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:
5248
clusterName = "OTA Software Update"
5349

54-
elif onOffCluster == clusterName:
50+
elif "On/Off" == clusterName:
5551
clusterName = clusterName.replace("/", "-")
5652

57-
elif groupKeyManagementCluster == clusterName:
53+
elif "Group Key Management" == clusterName:
5854
clusterName = "Group Communication"
5955

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"
6274

6375
# Determine if file has already been handled and use this file
6476
for outputFolderFileName in os.listdir(outputPathStr):
@@ -108,57 +120,61 @@ def GenerateDevicePicsXmlFiles(clusterName, clusterPicsCode, featurePicsList, at
108120
# Feature PICS
109121
# console.print(featurePicsList)
110122
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')
113126

114-
console.print(f"Searching for {itemNumberElement.text}")
127+
console.print(f"Searching for {itemNumberElement.text}")
115128

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"
120133

121134
# Attributes PICS
122135
# TODO: Only check if list is not empty
123136
# console.print(attributePicsList)
124137
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')
127141

128-
console.print(f"Searching for {itemNumberElement.text}")
142+
console.print(f"Searching for {itemNumberElement.text}")
129143

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"
134148

135149
# AcceptedCommandList PICS
136150
# TODO: Only check if list is not empty
137151
# console.print(acceptedCommandPicsList)
138152
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')
141156

142-
console.print(f"Searching for {itemNumberElement.text}")
157+
console.print(f"Searching for {itemNumberElement.text}")
143158

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"
148163

149164
# GeneratedCommandList PICS
150165
# console.print(generatedCommandPicsList)
151166
# TODO: Only check if list is not empty
152167
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')
155171

156-
console.print(f"Searching for {itemNumberElement.text}")
172+
console.print(f"Searching for {itemNumberElement.text}")
157173

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"
162178

163179
# Event PICS (Work in progress)
164180
# 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
168184
# 1) Event is mandatody
169185
# 2) The event is mandatory based on a feature that is supported (Cross check against feature list) (Not supported yet)
170186
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
200217

201218
# Grabbing the header from the XML templates
202219
inputFile = open(f"{xmlPath}{fileName}", "r")
@@ -255,21 +272,28 @@ async def DeviceMapping(devCtrl, nodeID, outputPathStr):
255272
acceptedCommandListPicsList = []
256273
generatedCommandListPicsList = []
257274

258-
clusterClass = getattr(Clusters, devCtrl.GetClusterHandler().GetClusterInfoById(server)['clusterName'])
259275
clusterID = f"0x{server:04x}"
260276

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! ❌")
264279
continue
265280

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
268286

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
270295

271-
# Print PICS for specific server from dict
272-
# console.print(clusterInfoDict[f"0x{server:04x}"])
296+
console.print(f"{clusterName} - {clusterPICS}")
273297

274298
# Read feature map
275299
featureMapResponse = await devCtrl.ReadAttribute(nodeID, [(endpoint, clusterClass.Attributes.FeatureMap)])
@@ -339,8 +363,14 @@ async def DeviceMapping(devCtrl, nodeID, outputPathStr):
339363

340364
for client in clientList:
341365
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
344374

345375
console.print(f"{clusterName} - {clusterPICS}")
346376

@@ -357,21 +387,18 @@ def cleanDirectory(pathToClean):
357387

358388

359389
parser = argparse.ArgumentParser()
360-
parser.add_argument('--cluster-data', required=True)
361390
parser.add_argument('--pics-template', required=True)
362391
parser.add_argument('--pics-output', required=True)
363392
args, unknown = parser.parse_known_args()
364393

365-
basePath = os.path.dirname(__file__)
366-
clusterInfoInputPathStr = args.cluster_data
367-
368394
xmlTemplatePathStr = args.pics_template
369395
if not xmlTemplatePathStr.endswith('/'):
370396
xmlTemplatePathStr += '/'
371397

372398
baseOutputPathStr = args.pics_output
373399
if not baseOutputPathStr.endswith('/'):
374400
baseOutputPathStr += '/'
401+
outputPathStr = baseOutputPathStr + "GeneratedPICS/"
375402

376403
serverTag = ".S"
377404
clientTag = ".C"
@@ -391,43 +418,20 @@ def cleanDirectory(pathToClean):
391418
# Endpoint define
392419
rootNodeEndpointID = 0
393420

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-
419421
# Load PICS XML templates
420422
print("Capture list of PICS XML templates")
421423
xmlFileList = os.listdir(xmlTemplatePathStr)
422424

423425
# 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():
426430
print("Create output folder")
427-
baseOutputPath.mkdir()
431+
outputPath.mkdir()
428432
else:
429433
print("Clean output folder")
430-
cleanDirectory(baseOutputPath)
434+
cleanDirectory(outputPath)
431435

432436

433437
class DeviceMappingTest(MatterBaseTest):
@@ -438,8 +442,11 @@ async def test_device_mapping(self):
438442
global console
439443
console = Console()
440444

445+
global xml_clusters
446+
xml_clusters, problems = build_xml_clusters()
447+
441448
# 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)
443450

444451

445452
if __name__ == "__main__":

0 commit comments

Comments
 (0)