diff --git a/scripts/py_matter_idl/matter_idl/generators/types.py b/scripts/py_matter_idl/matter_idl/generators/types.py index 393c444ae46060..dd9ed047584012 100644 --- a/scripts/py_matter_idl/matter_idl/generators/types.py +++ b/scripts/py_matter_idl/matter_idl/generators/types.py @@ -412,3 +412,29 @@ def ParseDataType(data_type: DataType, lookup: TypeLookupContext) -> Union[Basic "Data type %s is NOT known, but treating it as a generic IDL type." % data_type) return result + + +def IsSignedDataType(data_type: DataType) -> bool: + """ + Returns if the data type is a signed type. + Returns if the data type is a signed data type of False if the data type can not be found. + """ + lowercase_name = data_type.name.lower() + sized_type = __CHIP_SIZED_TYPES__.get(lowercase_name, None) + if sized_type is None: + return False + + return sized_type.is_signed + + +def GetDataTypeSizeInBits(data_type: DataType) -> int: + """ + Returns the size in bits for a given data type or None if the data type can not be found. + """ + + lowercase_name = data_type.name.lower() + sized_type = __CHIP_SIZED_TYPES__.get(lowercase_name, None) + if sized_type is None: + return None + + return sized_type.power_of_two_bits diff --git a/scripts/py_matter_idl/matter_idl/matter_idl_types.py b/scripts/py_matter_idl/matter_idl/matter_idl_types.py index 9e3b4beb53ed79..eb86e3ec4b99fc 100644 --- a/scripts/py_matter_idl/matter_idl/matter_idl_types.py +++ b/scripts/py_matter_idl/matter_idl/matter_idl_types.py @@ -99,8 +99,13 @@ class DataType: name: str # Applies for strings (char or binary) + min_length: Optional[int] = None max_length: Optional[int] = None + # Applies for numbers + min_value: Optional[int] = None + max_value: Optional[int] = None + @dataclass class Field: diff --git a/scripts/py_matter_idl/matter_idl/test_xml_parser.py b/scripts/py_matter_idl/matter_idl/test_xml_parser.py index 7828c4219694fd..d8c7bb0a6c5dc1 100755 --- a/scripts/py_matter_idl/matter_idl/test_xml_parser.py +++ b/scripts/py_matter_idl/matter_idl/test_xml_parser.py @@ -59,6 +59,9 @@ def testCluster(self): 0x1234 Test + SomeCharStringAttribute + SomeIntAttribute @@ -93,7 +96,17 @@ def testCluster(self): description="Test", attributes=[ Attribute(definition=Field( - data_type=DataType(name='INT32U'), + data_type=DataType( + name='CHAR_STRING', min_length=2, max_length=10), + code=10, + name='SomeCharStringAttribute', + qualities=FieldQuality.NULLABLE), + qualities=AttributeQuality.READABLE, + readacl=AccessPrivilege.VIEW, writeacl=AccessPrivilege.OPERATE), + + Attribute(definition=Field( + data_type=DataType( + name='INT32U', min_value=0, max_value=2), code=11, name='SomeIntAttribute', qualities=FieldQuality.NULLABLE), @@ -101,7 +114,8 @@ def testCluster(self): readacl=AccessPrivilege.VIEW, writeacl=AccessPrivilege.OPERATE), Attribute(definition=Field( - data_type=DataType(name='INT8U'), + data_type=DataType( + name='INT8U', min_value=0, max_value=10), code=22, name='AttributeWithAccess', qualities=FieldQuality.OPTIONAL), qualities=AttributeQuality.READABLE | AttributeQuality.WRITABLE, @@ -214,7 +228,10 @@ def testFabricScopedAndSensitive(self): name='Field3', qualities=FieldQuality.FABRIC_SENSITIVE), Field(data_type=DataType(name='int32u', - max_length=None), + min_length=None, + max_length=None, + min_value=None, + max_value=None), code=10, name='Field10')], qualities=StructQuality.FABRIC_SCOPED)], @@ -369,7 +386,7 @@ def testSkipsNotProcessedFields(self): Attribute( definition=Field( data_type=DataType( - name='Type'), + name='Type', min_value=0, max_value=9), code=0, name='Type', ), diff --git a/scripts/py_matter_idl/matter_idl/zapxml/handlers/parsing.py b/scripts/py_matter_idl/matter_idl/zapxml/handlers/parsing.py index 09243a627fea5e..c6f057b992f611 100644 --- a/scripts/py_matter_idl/matter_idl/zapxml/handlers/parsing.py +++ b/scripts/py_matter_idl/matter_idl/zapxml/handlers/parsing.py @@ -12,16 +12,23 @@ # See the License for the specific language governing permissions and # limitations under the License. +from matter_idl.generators.types import GetDataTypeSizeInBits, IsSignedDataType from matter_idl.matter_idl_types import AccessPrivilege, Attribute, AttributeQuality, DataType, Field, FieldQuality -def ParseInt(value: str) -> int: - """Convert a string that is a known integer into an actual number. +def ParseInt(value: str, data_type: DataType = None) -> int: + """ + Convert a string that is a known integer into an actual number. - Supports decimal or hex values prefixed with '0x' + Supports decimal or hex values prefixed with '0x' """ if value.startswith('0x'): - return int(value[2:], 16) + value = int(value[2:], 16) + if data_type and IsSignedDataType(data_type): + bits = GetDataTypeSizeInBits(data_type) + if value & (1 << (bits - 1)): + value -= 1 << bits + return value else: return int(value) @@ -60,9 +67,18 @@ def AttrsToAttribute(attrs) -> Attribute: else: data_type = DataType(name=attrs['type']) + if 'minLength' in attrs: + data_type.min_length = ParseInt(attrs['minLength']) + if 'length' in attrs: data_type.max_length = ParseInt(attrs['length']) + if 'min' in attrs: + data_type.min_value = ParseInt(attrs['min'], data_type) + + if 'max' in attrs: + data_type.max_value = ParseInt(attrs['max'], data_type) + field = Field( data_type=data_type, code=ParseInt(attrs['code']),