From 5c4a9c812afe60440723d15326a5fe64f5b37083 Mon Sep 17 00:00:00 2001 From: Andrei Litvin Date: Tue, 7 Nov 2023 11:25:30 -0500 Subject: [PATCH 1/4] Move `Fan Control Cluster` to spec (#30182) * Fan control to spec * Add to darwin backwards compatibility and zap regen * Fix Darwin availability annotations. * minor change to kick CI * Remove read/write of fan mode sequence, as the spec says it is read only * zap regen --------- Co-authored-by: Andrei Litvin Co-authored-by: Boris Zbarsky --- .../air-purifier-app.matter | 6 +- .../all-clusters-app.matter | 6 +- .../all-clusters-minimal-app.matter | 6 +- ...umiditysensor_thermostat_56de3d5f45.matter | 6 +- .../devices/rootnode_fan_7N2TobIlOX.matter | 6 +- ...tnode_heatingcoolingunit_ncdGai1E5a.matter | 6 +- ...tnode_roomairconditioner_9cf3607804.matter | 6 +- .../rootnode_thermostat_bm3fb8dhYi.matter | 6 +- .../resource-monitoring-app.matter | 6 +- .../app-templates/endpoint_config.h | 54 +++--- src/app/common/templates/config-data.yaml | 1 + src/app/tests/suites/TestFanControl.yaml | 12 -- .../data-model/chip/fan-control-cluster.xml | 7 +- .../data_model/controller-clusters.matter | 6 +- .../chip/devicecontroller/ChipClusters.java | 10 - .../devicecontroller/ClusterWriteMapping.java | 22 --- .../cluster/clusters/FanControlCluster.kt | 8 - .../zap-generated/CHIPClustersWrite-JNI.cpp | 52 ----- .../python/chip/clusters/CHIPClusters.py | 1 - .../python/chip/clusters/Objects.py | 4 +- .../CHIP/templates/availability.yaml | 22 +++ .../CHIP/zap-generated/MTRBaseClusters.h | 14 +- .../zap-generated/cluster-enums-check.h | 4 +- .../app-common/zap-generated/cluster-enums.h | 4 +- .../zap-generated/cluster/Commands.h | 3 +- .../zap-generated/cluster/Commands.h | 42 ---- .../zap-generated/test/Commands.h | 180 ++++++------------ 27 files changed, 161 insertions(+), 339 deletions(-) diff --git a/examples/air-purifier-app/air-purifier-common/air-purifier-app.matter b/examples/air-purifier-app/air-purifier-common/air-purifier-app.matter index 4607a5f5f21274..138e828cab9564 100644 --- a/examples/air-purifier-app/air-purifier-common/air-purifier-app.matter +++ b/examples/air-purifier-app/air-purifier-common/air-purifier-app.matter @@ -1127,8 +1127,8 @@ provisional server cluster FanControl = 514 { kOffLowHigh = 1; kOffLowMedHighAuto = 2; kOffLowHighAuto = 3; - kOffOnAuto = 4; - kOffOn = 5; + kOffHighAuto = 4; + kOffHigh = 5; } enum StepDirectionEnum : enum8 { @@ -1157,7 +1157,7 @@ provisional server cluster FanControl = 514 { } attribute FanModeEnum fanMode = 0; - attribute FanModeSequenceEnum fanModeSequence = 1; + readonly attribute FanModeSequenceEnum fanModeSequence = 1; attribute nullable percent percentSetting = 2; readonly attribute percent percentCurrent = 3; readonly attribute int8u speedMax = 4; diff --git a/examples/all-clusters-app/all-clusters-common/all-clusters-app.matter b/examples/all-clusters-app/all-clusters-common/all-clusters-app.matter index 7437c22e34ea5a..191a87a0088dc2 100644 --- a/examples/all-clusters-app/all-clusters-common/all-clusters-app.matter +++ b/examples/all-clusters-app/all-clusters-common/all-clusters-app.matter @@ -3705,8 +3705,8 @@ provisional server cluster FanControl = 514 { kOffLowHigh = 1; kOffLowMedHighAuto = 2; kOffLowHighAuto = 3; - kOffOnAuto = 4; - kOffOn = 5; + kOffHighAuto = 4; + kOffHigh = 5; } enum StepDirectionEnum : enum8 { @@ -3735,7 +3735,7 @@ provisional server cluster FanControl = 514 { } attribute FanModeEnum fanMode = 0; - attribute FanModeSequenceEnum fanModeSequence = 1; + readonly attribute FanModeSequenceEnum fanModeSequence = 1; attribute nullable percent percentSetting = 2; readonly attribute percent percentCurrent = 3; readonly attribute int8u speedMax = 4; diff --git a/examples/all-clusters-minimal-app/all-clusters-common/all-clusters-minimal-app.matter b/examples/all-clusters-minimal-app/all-clusters-common/all-clusters-minimal-app.matter index 910b0f8ad577af..d4c6725bd0f594 100644 --- a/examples/all-clusters-minimal-app/all-clusters-common/all-clusters-minimal-app.matter +++ b/examples/all-clusters-minimal-app/all-clusters-common/all-clusters-minimal-app.matter @@ -2864,8 +2864,8 @@ provisional server cluster FanControl = 514 { kOffLowHigh = 1; kOffLowMedHighAuto = 2; kOffLowHighAuto = 3; - kOffOnAuto = 4; - kOffOn = 5; + kOffHighAuto = 4; + kOffHigh = 5; } enum StepDirectionEnum : enum8 { @@ -2894,7 +2894,7 @@ provisional server cluster FanControl = 514 { } attribute FanModeEnum fanMode = 0; - attribute FanModeSequenceEnum fanModeSequence = 1; + readonly attribute FanModeSequenceEnum fanModeSequence = 1; attribute nullable percent percentSetting = 2; readonly attribute percent percentCurrent = 3; readonly attribute command_id generatedCommandList[] = 65528; diff --git a/examples/chef/devices/rootnode_airpurifier_airqualitysensor_temperaturesensor_humiditysensor_thermostat_56de3d5f45.matter b/examples/chef/devices/rootnode_airpurifier_airqualitysensor_temperaturesensor_humiditysensor_thermostat_56de3d5f45.matter index a44002cc3ca5e6..64dfad6fc4efa2 100644 --- a/examples/chef/devices/rootnode_airpurifier_airqualitysensor_temperaturesensor_humiditysensor_thermostat_56de3d5f45.matter +++ b/examples/chef/devices/rootnode_airpurifier_airqualitysensor_temperaturesensor_humiditysensor_thermostat_56de3d5f45.matter @@ -1127,8 +1127,8 @@ provisional server cluster FanControl = 514 { kOffLowHigh = 1; kOffLowMedHighAuto = 2; kOffLowHighAuto = 3; - kOffOnAuto = 4; - kOffOn = 5; + kOffHighAuto = 4; + kOffHigh = 5; } enum StepDirectionEnum : enum8 { @@ -1157,7 +1157,7 @@ provisional server cluster FanControl = 514 { } attribute FanModeEnum fanMode = 0; - attribute FanModeSequenceEnum fanModeSequence = 1; + readonly attribute FanModeSequenceEnum fanModeSequence = 1; attribute nullable percent percentSetting = 2; readonly attribute percent percentCurrent = 3; readonly attribute int8u speedMax = 4; diff --git a/examples/chef/devices/rootnode_fan_7N2TobIlOX.matter b/examples/chef/devices/rootnode_fan_7N2TobIlOX.matter index d28225d0a51408..131960ba6c3e09 100644 --- a/examples/chef/devices/rootnode_fan_7N2TobIlOX.matter +++ b/examples/chef/devices/rootnode_fan_7N2TobIlOX.matter @@ -1178,8 +1178,8 @@ provisional server cluster FanControl = 514 { kOffLowHigh = 1; kOffLowMedHighAuto = 2; kOffLowHighAuto = 3; - kOffOnAuto = 4; - kOffOn = 5; + kOffHighAuto = 4; + kOffHigh = 5; } enum StepDirectionEnum : enum8 { @@ -1208,7 +1208,7 @@ provisional server cluster FanControl = 514 { } attribute FanModeEnum fanMode = 0; - attribute FanModeSequenceEnum fanModeSequence = 1; + readonly attribute FanModeSequenceEnum fanModeSequence = 1; attribute nullable percent percentSetting = 2; readonly attribute percent percentCurrent = 3; readonly attribute int8u speedMax = 4; diff --git a/examples/chef/devices/rootnode_heatingcoolingunit_ncdGai1E5a.matter b/examples/chef/devices/rootnode_heatingcoolingunit_ncdGai1E5a.matter index 054b0988bac2bc..ed6f00e760d666 100644 --- a/examples/chef/devices/rootnode_heatingcoolingunit_ncdGai1E5a.matter +++ b/examples/chef/devices/rootnode_heatingcoolingunit_ncdGai1E5a.matter @@ -1493,8 +1493,8 @@ provisional server cluster FanControl = 514 { kOffLowHigh = 1; kOffLowMedHighAuto = 2; kOffLowHighAuto = 3; - kOffOnAuto = 4; - kOffOn = 5; + kOffHighAuto = 4; + kOffHigh = 5; } enum StepDirectionEnum : enum8 { @@ -1523,7 +1523,7 @@ provisional server cluster FanControl = 514 { } attribute FanModeEnum fanMode = 0; - attribute FanModeSequenceEnum fanModeSequence = 1; + readonly attribute FanModeSequenceEnum fanModeSequence = 1; attribute nullable percent percentSetting = 2; readonly attribute percent percentCurrent = 3; readonly attribute int8u speedMax = 4; diff --git a/examples/chef/devices/rootnode_roomairconditioner_9cf3607804.matter b/examples/chef/devices/rootnode_roomairconditioner_9cf3607804.matter index c46fb0d0f25c15..f4e280c1938122 100644 --- a/examples/chef/devices/rootnode_roomairconditioner_9cf3607804.matter +++ b/examples/chef/devices/rootnode_roomairconditioner_9cf3607804.matter @@ -1059,8 +1059,8 @@ provisional server cluster FanControl = 514 { kOffLowHigh = 1; kOffLowMedHighAuto = 2; kOffLowHighAuto = 3; - kOffOnAuto = 4; - kOffOn = 5; + kOffHighAuto = 4; + kOffHigh = 5; } enum StepDirectionEnum : enum8 { @@ -1089,7 +1089,7 @@ provisional server cluster FanControl = 514 { } attribute FanModeEnum fanMode = 0; - attribute FanModeSequenceEnum fanModeSequence = 1; + readonly attribute FanModeSequenceEnum fanModeSequence = 1; attribute nullable percent percentSetting = 2; readonly attribute percent percentCurrent = 3; readonly attribute command_id generatedCommandList[] = 65528; diff --git a/examples/chef/devices/rootnode_thermostat_bm3fb8dhYi.matter b/examples/chef/devices/rootnode_thermostat_bm3fb8dhYi.matter index 0b17bf5ad17a8d..8888d71c315223 100644 --- a/examples/chef/devices/rootnode_thermostat_bm3fb8dhYi.matter +++ b/examples/chef/devices/rootnode_thermostat_bm3fb8dhYi.matter @@ -1300,8 +1300,8 @@ provisional client cluster FanControl = 514 { kOffLowHigh = 1; kOffLowMedHighAuto = 2; kOffLowHighAuto = 3; - kOffOnAuto = 4; - kOffOn = 5; + kOffHighAuto = 4; + kOffHigh = 5; } enum StepDirectionEnum : enum8 { @@ -1330,7 +1330,7 @@ provisional client cluster FanControl = 514 { } attribute FanModeEnum fanMode = 0; - attribute FanModeSequenceEnum fanModeSequence = 1; + readonly attribute FanModeSequenceEnum fanModeSequence = 1; attribute nullable percent percentSetting = 2; readonly attribute percent percentCurrent = 3; readonly attribute optional int8u speedMax = 4; diff --git a/examples/resource-monitoring-app/resource-monitoring-common/resource-monitoring-app.matter b/examples/resource-monitoring-app/resource-monitoring-common/resource-monitoring-app.matter index aae55a1f554bbf..c60a06bc035d09 100644 --- a/examples/resource-monitoring-app/resource-monitoring-common/resource-monitoring-app.matter +++ b/examples/resource-monitoring-app/resource-monitoring-common/resource-monitoring-app.matter @@ -1618,8 +1618,8 @@ provisional server cluster FanControl = 514 { kOffLowHigh = 1; kOffLowMedHighAuto = 2; kOffLowHighAuto = 3; - kOffOnAuto = 4; - kOffOn = 5; + kOffHighAuto = 4; + kOffHigh = 5; } enum StepDirectionEnum : enum8 { @@ -1648,7 +1648,7 @@ provisional server cluster FanControl = 514 { } attribute FanModeEnum fanMode = 0; - attribute FanModeSequenceEnum fanModeSequence = 1; + readonly attribute FanModeSequenceEnum fanModeSequence = 1; attribute nullable percent percentSetting = 2; readonly attribute percent percentCurrent = 3; readonly attribute command_id generatedCommandList[] = 65528; diff --git a/scripts/tools/zap/tests/outputs/all-clusters-app/app-templates/endpoint_config.h b/scripts/tools/zap/tests/outputs/all-clusters-app/app-templates/endpoint_config.h index 9e9cc203615f23..cc5ff6c06f8d17 100644 --- a/scripts/tools/zap/tests/outputs/all-clusters-app/app-templates/endpoint_config.h +++ b/scripts/tools/zap/tests/outputs/all-clusters-app/app-templates/endpoint_config.h @@ -269,7 +269,7 @@ #define GENERATED_DEFAULTS_COUNT (32) // This is an array of EmberAfAttributeMinMaxValue structures. -#define GENERATED_MIN_MAX_DEFAULT_COUNT 47 +#define GENERATED_MIN_MAX_DEFAULT_COUNT 46 #define GENERATED_MIN_MAX_DEFAULTS \ { \ \ @@ -317,7 +317,6 @@ \ /* Endpoint: 1, Cluster: Fan Control (server) */ \ { (uint16_t) 0x0, (uint16_t) 0x0, (uint16_t) 0x6 }, /* FanMode */ \ - { (uint16_t) 0x2, (uint16_t) 0x0, (uint16_t) 0x5 }, /* FanModeSequence */ \ { (uint16_t) 0x0, (uint16_t) 0x0, (uint16_t) 0x64 }, /* PercentSetting */ \ { (uint16_t) 0x0, (uint16_t) 0x0, (uint16_t) 0x64 }, /* SpeedSetting */ \ \ @@ -1037,14 +1036,13 @@ \ /* Endpoint: 1, Cluster: Fan Control (server) */ \ { ZAP_MIN_MAX_DEFAULTS_INDEX(22), 0x00000000, 1, ZAP_TYPE(ENUM8), \ - ZAP_ATTRIBUTE_MASK(MIN_MAX) | ZAP_ATTRIBUTE_MASK(WRITABLE) }, /* FanMode */ \ - { ZAP_MIN_MAX_DEFAULTS_INDEX(23), 0x00000001, 1, ZAP_TYPE(ENUM8), \ - ZAP_ATTRIBUTE_MASK(MIN_MAX) | ZAP_ATTRIBUTE_MASK(WRITABLE) }, /* FanModeSequence */ \ - { ZAP_MIN_MAX_DEFAULTS_INDEX(24), 0x00000002, 1, ZAP_TYPE(PERCENT), \ + ZAP_ATTRIBUTE_MASK(MIN_MAX) | ZAP_ATTRIBUTE_MASK(WRITABLE) }, /* FanMode */ \ + { ZAP_SIMPLE_DEFAULT(0x02), 0x00000001, 1, ZAP_TYPE(ENUM8), 0 }, /* FanModeSequence */ \ + { ZAP_MIN_MAX_DEFAULTS_INDEX(23), 0x00000002, 1, ZAP_TYPE(PERCENT), \ ZAP_ATTRIBUTE_MASK(MIN_MAX) | ZAP_ATTRIBUTE_MASK(WRITABLE) | ZAP_ATTRIBUTE_MASK(NULLABLE) }, /* PercentSetting */ \ { ZAP_SIMPLE_DEFAULT(0x00), 0x00000003, 1, ZAP_TYPE(PERCENT), 0 }, /* PercentCurrent */ \ { ZAP_SIMPLE_DEFAULT(100), 0x00000004, 1, ZAP_TYPE(INT8U), 0 }, /* SpeedMax */ \ - { ZAP_MIN_MAX_DEFAULTS_INDEX(25), 0x00000005, 1, ZAP_TYPE(INT8U), \ + { ZAP_MIN_MAX_DEFAULTS_INDEX(24), 0x00000005, 1, ZAP_TYPE(INT8U), \ ZAP_ATTRIBUTE_MASK(MIN_MAX) | ZAP_ATTRIBUTE_MASK(WRITABLE) | ZAP_ATTRIBUTE_MASK(NULLABLE) }, /* SpeedSetting */ \ { ZAP_SIMPLE_DEFAULT(0x00), 0x00000006, 1, ZAP_TYPE(INT8U), 0 }, /* SpeedCurrent */ \ { ZAP_SIMPLE_DEFAULT(0x00), 0x00000007, 1, ZAP_TYPE(BITMAP8), 0 }, /* RockSupport */ \ @@ -1055,11 +1053,11 @@ { ZAP_SIMPLE_DEFAULT(2), 0x0000FFFD, 2, ZAP_TYPE(INT16U), 0 }, /* ClusterRevision */ \ \ /* Endpoint: 1, Cluster: Thermostat User Interface Configuration (server) */ \ - { ZAP_MIN_MAX_DEFAULTS_INDEX(26), 0x00000000, 1, ZAP_TYPE(ENUM8), \ + { ZAP_MIN_MAX_DEFAULTS_INDEX(25), 0x00000000, 1, ZAP_TYPE(ENUM8), \ ZAP_ATTRIBUTE_MASK(MIN_MAX) | ZAP_ATTRIBUTE_MASK(WRITABLE) }, /* TemperatureDisplayMode */ \ - { ZAP_MIN_MAX_DEFAULTS_INDEX(27), 0x00000001, 1, ZAP_TYPE(ENUM8), \ + { ZAP_MIN_MAX_DEFAULTS_INDEX(26), 0x00000001, 1, ZAP_TYPE(ENUM8), \ ZAP_ATTRIBUTE_MASK(MIN_MAX) | ZAP_ATTRIBUTE_MASK(WRITABLE) }, /* KeypadLockout */ \ - { ZAP_MIN_MAX_DEFAULTS_INDEX(28), 0x00000002, 1, ZAP_TYPE(ENUM8), \ + { ZAP_MIN_MAX_DEFAULTS_INDEX(27), 0x00000002, 1, ZAP_TYPE(ENUM8), \ ZAP_ATTRIBUTE_MASK(MIN_MAX) | ZAP_ATTRIBUTE_MASK(WRITABLE) }, /* ScheduleProgrammingVisibility */ \ { ZAP_SIMPLE_DEFAULT(0), 0x0000FFFC, 4, ZAP_TYPE(BITMAP32), 0 }, /* FeatureMap */ \ { ZAP_SIMPLE_DEFAULT(2), 0x0000FFFD, 2, ZAP_TYPE(INT16U), 0 }, /* ClusterRevision */ \ @@ -1094,25 +1092,25 @@ { ZAP_EMPTY_DEFAULT(), 0x00000028, 2, ZAP_TYPE(INT16U), 0 }, /* Primary6X */ \ { ZAP_EMPTY_DEFAULT(), 0x00000029, 2, ZAP_TYPE(INT16U), 0 }, /* Primary6Y */ \ { ZAP_EMPTY_DEFAULT(), 0x0000002A, 1, ZAP_TYPE(INT8U), ZAP_ATTRIBUTE_MASK(NULLABLE) }, /* Primary6Intensity */ \ - { ZAP_MIN_MAX_DEFAULTS_INDEX(29), 0x00000030, 2, ZAP_TYPE(INT16U), \ + { ZAP_MIN_MAX_DEFAULTS_INDEX(28), 0x00000030, 2, ZAP_TYPE(INT16U), \ ZAP_ATTRIBUTE_MASK(MIN_MAX) | ZAP_ATTRIBUTE_MASK(WRITABLE) }, /* WhitePointX */ \ - { ZAP_MIN_MAX_DEFAULTS_INDEX(30), 0x00000031, 2, ZAP_TYPE(INT16U), \ + { ZAP_MIN_MAX_DEFAULTS_INDEX(29), 0x00000031, 2, ZAP_TYPE(INT16U), \ ZAP_ATTRIBUTE_MASK(MIN_MAX) | ZAP_ATTRIBUTE_MASK(WRITABLE) }, /* WhitePointY */ \ - { ZAP_MIN_MAX_DEFAULTS_INDEX(31), 0x00000032, 2, ZAP_TYPE(INT16U), \ + { ZAP_MIN_MAX_DEFAULTS_INDEX(30), 0x00000032, 2, ZAP_TYPE(INT16U), \ ZAP_ATTRIBUTE_MASK(MIN_MAX) | ZAP_ATTRIBUTE_MASK(WRITABLE) }, /* ColorPointRX */ \ - { ZAP_MIN_MAX_DEFAULTS_INDEX(32), 0x00000033, 2, ZAP_TYPE(INT16U), \ + { ZAP_MIN_MAX_DEFAULTS_INDEX(31), 0x00000033, 2, ZAP_TYPE(INT16U), \ ZAP_ATTRIBUTE_MASK(MIN_MAX) | ZAP_ATTRIBUTE_MASK(WRITABLE) }, /* ColorPointRY */ \ { ZAP_EMPTY_DEFAULT(), 0x00000034, 1, ZAP_TYPE(INT8U), \ ZAP_ATTRIBUTE_MASK(WRITABLE) | ZAP_ATTRIBUTE_MASK(NULLABLE) }, /* ColorPointRIntensity */ \ - { ZAP_MIN_MAX_DEFAULTS_INDEX(33), 0x00000036, 2, ZAP_TYPE(INT16U), \ + { ZAP_MIN_MAX_DEFAULTS_INDEX(32), 0x00000036, 2, ZAP_TYPE(INT16U), \ ZAP_ATTRIBUTE_MASK(MIN_MAX) | ZAP_ATTRIBUTE_MASK(WRITABLE) }, /* ColorPointGX */ \ - { ZAP_MIN_MAX_DEFAULTS_INDEX(34), 0x00000037, 2, ZAP_TYPE(INT16U), \ + { ZAP_MIN_MAX_DEFAULTS_INDEX(33), 0x00000037, 2, ZAP_TYPE(INT16U), \ ZAP_ATTRIBUTE_MASK(MIN_MAX) | ZAP_ATTRIBUTE_MASK(WRITABLE) }, /* ColorPointGY */ \ { ZAP_EMPTY_DEFAULT(), 0x00000038, 1, ZAP_TYPE(INT8U), \ ZAP_ATTRIBUTE_MASK(WRITABLE) | ZAP_ATTRIBUTE_MASK(NULLABLE) }, /* ColorPointGIntensity */ \ - { ZAP_MIN_MAX_DEFAULTS_INDEX(35), 0x0000003A, 2, ZAP_TYPE(INT16U), \ + { ZAP_MIN_MAX_DEFAULTS_INDEX(34), 0x0000003A, 2, ZAP_TYPE(INT16U), \ ZAP_ATTRIBUTE_MASK(MIN_MAX) | ZAP_ATTRIBUTE_MASK(WRITABLE) }, /* ColorPointBX */ \ - { ZAP_MIN_MAX_DEFAULTS_INDEX(36), 0x0000003B, 2, ZAP_TYPE(INT16U), \ + { ZAP_MIN_MAX_DEFAULTS_INDEX(35), 0x0000003B, 2, ZAP_TYPE(INT16U), \ ZAP_ATTRIBUTE_MASK(MIN_MAX) | ZAP_ATTRIBUTE_MASK(WRITABLE) }, /* ColorPointBY */ \ { ZAP_EMPTY_DEFAULT(), 0x0000003C, 1, ZAP_TYPE(INT8U), \ ZAP_ATTRIBUTE_MASK(WRITABLE) | ZAP_ATTRIBUTE_MASK(NULLABLE) }, /* ColorPointBIntensity */ \ @@ -1127,7 +1125,7 @@ { ZAP_SIMPLE_DEFAULT(0x0000), 0x0000400B, 2, ZAP_TYPE(INT16U), 0 }, /* ColorTempPhysicalMinMireds */ \ { ZAP_SIMPLE_DEFAULT(0xFEFF), 0x0000400C, 2, ZAP_TYPE(INT16U), 0 }, /* ColorTempPhysicalMaxMireds */ \ { ZAP_EMPTY_DEFAULT(), 0x0000400D, 2, ZAP_TYPE(INT16U), 0 }, /* CoupleColorTempToLevelMinMireds */ \ - { ZAP_MIN_MAX_DEFAULTS_INDEX(37), 0x00004010, 2, ZAP_TYPE(INT16U), \ + { ZAP_MIN_MAX_DEFAULTS_INDEX(36), 0x00004010, 2, ZAP_TYPE(INT16U), \ ZAP_ATTRIBUTE_MASK(MIN_MAX) | ZAP_ATTRIBUTE_MASK(WRITABLE) | \ ZAP_ATTRIBUTE_MASK(NULLABLE) }, /* StartUpColorTemperatureMireds */ \ { ZAP_SIMPLE_DEFAULT(0x1F), 0x0000FFFC, 4, ZAP_TYPE(BITMAP32), 0 }, /* FeatureMap */ \ @@ -1317,13 +1315,13 @@ { ZAP_EMPTY_DEFAULT(), 0x00000024, 1, ZAP_TYPE(ENUM8), ZAP_ATTRIBUTE_MASK(WRITABLE) }, /* enum_attr */ \ { ZAP_EMPTY_DEFAULT(), 0x00000025, 0, ZAP_TYPE(STRUCT), \ ZAP_ATTRIBUTE_MASK(EXTERNAL_STORAGE) | ZAP_ATTRIBUTE_MASK(WRITABLE) }, /* struct_attr */ \ - { ZAP_MIN_MAX_DEFAULTS_INDEX(38), 0x00000026, 1, ZAP_TYPE(INT8U), \ + { ZAP_MIN_MAX_DEFAULTS_INDEX(37), 0x00000026, 1, ZAP_TYPE(INT8U), \ ZAP_ATTRIBUTE_MASK(MIN_MAX) | ZAP_ATTRIBUTE_MASK(WRITABLE) }, /* range_restricted_int8u */ \ - { ZAP_MIN_MAX_DEFAULTS_INDEX(39), 0x00000027, 1, ZAP_TYPE(INT8S), \ + { ZAP_MIN_MAX_DEFAULTS_INDEX(38), 0x00000027, 1, ZAP_TYPE(INT8S), \ ZAP_ATTRIBUTE_MASK(MIN_MAX) | ZAP_ATTRIBUTE_MASK(WRITABLE) }, /* range_restricted_int8s */ \ - { ZAP_MIN_MAX_DEFAULTS_INDEX(40), 0x00000028, 2, ZAP_TYPE(INT16U), \ + { ZAP_MIN_MAX_DEFAULTS_INDEX(39), 0x00000028, 2, ZAP_TYPE(INT16U), \ ZAP_ATTRIBUTE_MASK(MIN_MAX) | ZAP_ATTRIBUTE_MASK(WRITABLE) }, /* range_restricted_int16u */ \ - { ZAP_MIN_MAX_DEFAULTS_INDEX(41), 0x00000029, 2, ZAP_TYPE(INT16S), \ + { ZAP_MIN_MAX_DEFAULTS_INDEX(40), 0x00000029, 2, ZAP_TYPE(INT16S), \ ZAP_ATTRIBUTE_MASK(MIN_MAX) | ZAP_ATTRIBUTE_MASK(WRITABLE) }, /* range_restricted_int16s */ \ { ZAP_EMPTY_DEFAULT(), 0x0000002A, 0, ZAP_TYPE(ARRAY), \ ZAP_ATTRIBUTE_MASK(EXTERNAL_STORAGE) | ZAP_ATTRIBUTE_MASK(WRITABLE) }, /* list_long_octet_string */ \ @@ -1394,16 +1392,16 @@ { ZAP_EMPTY_DEFAULT(), 0x00004025, 0, ZAP_TYPE(STRUCT), \ ZAP_ATTRIBUTE_MASK(EXTERNAL_STORAGE) | ZAP_ATTRIBUTE_MASK(WRITABLE) | \ ZAP_ATTRIBUTE_MASK(NULLABLE) }, /* nullable_struct */ \ - { ZAP_MIN_MAX_DEFAULTS_INDEX(42), 0x00004026, 1, ZAP_TYPE(INT8U), \ + { ZAP_MIN_MAX_DEFAULTS_INDEX(41), 0x00004026, 1, ZAP_TYPE(INT8U), \ ZAP_ATTRIBUTE_MASK(MIN_MAX) | ZAP_ATTRIBUTE_MASK(WRITABLE) | \ ZAP_ATTRIBUTE_MASK(NULLABLE) }, /* nullable_range_restricted_int8u */ \ - { ZAP_MIN_MAX_DEFAULTS_INDEX(43), 0x00004027, 1, ZAP_TYPE(INT8S), \ + { ZAP_MIN_MAX_DEFAULTS_INDEX(42), 0x00004027, 1, ZAP_TYPE(INT8S), \ ZAP_ATTRIBUTE_MASK(MIN_MAX) | ZAP_ATTRIBUTE_MASK(WRITABLE) | \ ZAP_ATTRIBUTE_MASK(NULLABLE) }, /* nullable_range_restricted_int8s */ \ - { ZAP_MIN_MAX_DEFAULTS_INDEX(44), 0x00004028, 2, ZAP_TYPE(INT16U), \ + { ZAP_MIN_MAX_DEFAULTS_INDEX(43), 0x00004028, 2, ZAP_TYPE(INT16U), \ ZAP_ATTRIBUTE_MASK(MIN_MAX) | ZAP_ATTRIBUTE_MASK(WRITABLE) | \ ZAP_ATTRIBUTE_MASK(NULLABLE) }, /* nullable_range_restricted_int16u */ \ - { ZAP_MIN_MAX_DEFAULTS_INDEX(45), 0x00004029, 2, ZAP_TYPE(INT16S), \ + { ZAP_MIN_MAX_DEFAULTS_INDEX(44), 0x00004029, 2, ZAP_TYPE(INT16S), \ ZAP_ATTRIBUTE_MASK(MIN_MAX) | ZAP_ATTRIBUTE_MASK(WRITABLE) | \ ZAP_ATTRIBUTE_MASK(NULLABLE) }, /* nullable_range_restricted_int16s */ \ { ZAP_EMPTY_DEFAULT(), 0x0000402A, 1, ZAP_TYPE(INT8U), \ @@ -1438,7 +1436,7 @@ { ZAP_SIMPLE_DEFAULT(1), 0x00004000, 1, ZAP_TYPE(BOOLEAN), 0 }, /* GlobalSceneControl */ \ { ZAP_SIMPLE_DEFAULT(0), 0x00004001, 2, ZAP_TYPE(INT16U), ZAP_ATTRIBUTE_MASK(WRITABLE) }, /* OnTime */ \ { ZAP_SIMPLE_DEFAULT(0), 0x00004002, 2, ZAP_TYPE(INT16U), ZAP_ATTRIBUTE_MASK(WRITABLE) }, /* OffWaitTime */ \ - { ZAP_MIN_MAX_DEFAULTS_INDEX(46), 0x00004003, 1, ZAP_TYPE(ENUM8), \ + { ZAP_MIN_MAX_DEFAULTS_INDEX(45), 0x00004003, 1, ZAP_TYPE(ENUM8), \ ZAP_ATTRIBUTE_MASK(MIN_MAX) | ZAP_ATTRIBUTE_MASK(WRITABLE) | ZAP_ATTRIBUTE_MASK(NULLABLE) }, /* StartUpOnOff */ \ { ZAP_SIMPLE_DEFAULT(0x0000), 0x0000FFFC, 4, ZAP_TYPE(BITMAP32), 0 }, /* FeatureMap */ \ { ZAP_SIMPLE_DEFAULT(5), 0x0000FFFD, 2, ZAP_TYPE(INT16U), 0 }, /* ClusterRevision */ \ diff --git a/src/app/common/templates/config-data.yaml b/src/app/common/templates/config-data.yaml index 60fc765d26f403..1665fdbbfbee06 100644 --- a/src/app/common/templates/config-data.yaml +++ b/src/app/common/templates/config-data.yaml @@ -2,6 +2,7 @@ DarwinForceWritable: # Work-around for not allowing changes from writable to read-only # happened in https://github.com/project-chip/connectedhomeip/pull/30134 - ApplicationLauncher::CurrentApp + - FanControl::FanModeSequence WeakEnums: # Allow-list of enums that we generate as enums, not enum classes. diff --git a/src/app/tests/suites/TestFanControl.yaml b/src/app/tests/suites/TestFanControl.yaml index b27fa4d143e546..92fca4f2a6e253 100644 --- a/src/app/tests/suites/TestFanControl.yaml +++ b/src/app/tests/suites/TestFanControl.yaml @@ -40,18 +40,6 @@ tests: response: value: 3 - - label: "Write fan mode sequence" - command: "writeAttribute" - attribute: "FanModeSequence" - arguments: - value: 5 - - - label: "Read back fan mode sequence" - command: "readAttribute" - attribute: "FanModeSequence" - response: - value: 5 - - label: "Write percent setting" command: "writeAttribute" attribute: "PercentSetting" diff --git a/src/app/zap-templates/zcl/data-model/chip/fan-control-cluster.xml b/src/app/zap-templates/zcl/data-model/chip/fan-control-cluster.xml index 3c30d960f18fe7..ad6279b2ef65e2 100644 --- a/src/app/zap-templates/zcl/data-model/chip/fan-control-cluster.xml +++ b/src/app/zap-templates/zcl/data-model/chip/fan-control-cluster.xml @@ -44,8 +44,8 @@ limitations under the License. - - + + @@ -86,7 +86,7 @@ limitations under the License. FanMode - FanModeSequence + FanModeSequence PercentSetting PercentCurrent SpeedMax @@ -104,6 +104,5 @@ limitations under the License. - diff --git a/src/controller/data_model/controller-clusters.matter b/src/controller/data_model/controller-clusters.matter index 68fd1dfab60d30..c1e182aec384aa 100644 --- a/src/controller/data_model/controller-clusters.matter +++ b/src/controller/data_model/controller-clusters.matter @@ -4761,8 +4761,8 @@ provisional client cluster FanControl = 514 { kOffLowHigh = 1; kOffLowMedHighAuto = 2; kOffLowHighAuto = 3; - kOffOnAuto = 4; - kOffOn = 5; + kOffHighAuto = 4; + kOffHigh = 5; } enum StepDirectionEnum : enum8 { @@ -4791,7 +4791,7 @@ provisional client cluster FanControl = 514 { } attribute FanModeEnum fanMode = 0; - attribute FanModeSequenceEnum fanModeSequence = 1; + readonly attribute FanModeSequenceEnum fanModeSequence = 1; attribute nullable percent percentSetting = 2; readonly attribute percent percentCurrent = 3; readonly attribute optional int8u speedMax = 4; diff --git a/src/controller/java/generated/java/chip/devicecontroller/ChipClusters.java b/src/controller/java/generated/java/chip/devicecontroller/ChipClusters.java index f328b90d5462ff..04f8ae801534e4 100644 --- a/src/controller/java/generated/java/chip/devicecontroller/ChipClusters.java +++ b/src/controller/java/generated/java/chip/devicecontroller/ChipClusters.java @@ -18802,14 +18802,6 @@ public void readFanModeSequenceAttribute( readFanModeSequenceAttribute(chipClusterPtr, callback); } - public void writeFanModeSequenceAttribute(DefaultClusterCallback callback, Integer value) { - writeFanModeSequenceAttribute(chipClusterPtr, callback, value, null); - } - - public void writeFanModeSequenceAttribute(DefaultClusterCallback callback, Integer value, int timedWriteTimeoutMs) { - writeFanModeSequenceAttribute(chipClusterPtr, callback, value, timedWriteTimeoutMs); - } - public void subscribeFanModeSequenceAttribute( IntegerAttributeCallback callback, int minInterval, int maxInterval) { subscribeFanModeSequenceAttribute(chipClusterPtr, callback, minInterval, maxInterval); @@ -19023,8 +19015,6 @@ public void subscribeClusterRevisionAttribute( private native void readFanModeSequenceAttribute(long chipClusterPtr, IntegerAttributeCallback callback); - private native void writeFanModeSequenceAttribute(long chipClusterPtr, DefaultClusterCallback callback, Integer value, @Nullable Integer timedWriteTimeoutMs); - private native void subscribeFanModeSequenceAttribute(long chipClusterPtr, IntegerAttributeCallback callback, int minInterval, int maxInterval); private native void readPercentSettingAttribute(long chipClusterPtr, PercentSettingAttributeCallback callback); diff --git a/src/controller/java/generated/java/chip/devicecontroller/ClusterWriteMapping.java b/src/controller/java/generated/java/chip/devicecontroller/ClusterWriteMapping.java index d5c91e3844ec35..1e52b8f08c49a0 100644 --- a/src/controller/java/generated/java/chip/devicecontroller/ClusterWriteMapping.java +++ b/src/controller/java/generated/java/chip/devicecontroller/ClusterWriteMapping.java @@ -2355,28 +2355,6 @@ public Map> getWriteAttributeMap() { writeFanControlFanModeCommandParams ); writeFanControlInteractionInfo.put("writeFanModeAttribute", writeFanControlFanModeAttributeInteractionInfo); - Map writeFanControlFanModeSequenceCommandParams = new LinkedHashMap(); - CommandParameterInfo fanControlfanModeSequenceCommandParameterInfo = - new CommandParameterInfo( - "value", - Integer.class, - Integer.class - ); - writeFanControlFanModeSequenceCommandParams.put( - "value", - fanControlfanModeSequenceCommandParameterInfo - ); - InteractionInfo writeFanControlFanModeSequenceAttributeInteractionInfo = new InteractionInfo( - (cluster, callback, commandArguments) -> { - ((ChipClusters.FanControlCluster) cluster).writeFanModeSequenceAttribute( - (DefaultClusterCallback) callback, - (Integer) commandArguments.get("value") - ); - }, - () -> new ClusterInfoMapping.DelegatedDefaultClusterCallback(), - writeFanControlFanModeSequenceCommandParams - ); - writeFanControlInteractionInfo.put("writeFanModeSequenceAttribute", writeFanControlFanModeSequenceAttributeInteractionInfo); Map writeFanControlPercentSettingCommandParams = new LinkedHashMap(); CommandParameterInfo fanControlpercentSettingCommandParameterInfo = new CommandParameterInfo( diff --git a/src/controller/java/generated/java/matter/devicecontroller/cluster/clusters/FanControlCluster.kt b/src/controller/java/generated/java/matter/devicecontroller/cluster/clusters/FanControlCluster.kt index 4c33486d894df4..178dde9600faad 100644 --- a/src/controller/java/generated/java/matter/devicecontroller/cluster/clusters/FanControlCluster.kt +++ b/src/controller/java/generated/java/matter/devicecontroller/cluster/clusters/FanControlCluster.kt @@ -68,14 +68,6 @@ class FanControlCluster(private val controller: MatterController, private val en // Implementation needs to be added here } - suspend fun writeFanModeSequenceAttribute(value: UInt, timedWriteTimeoutMs: Int? = null) { - if (timedWriteTimeoutMs != null) { - // Do the action with timedWriteTimeoutMs - } else { - // Do the action without timedWriteTimeoutMs - } - } - suspend fun subscribeFanModeSequenceAttribute(minInterval: Int, maxInterval: Int): UByte { // Implementation needs to be added here } diff --git a/src/controller/java/zap-generated/CHIPClustersWrite-JNI.cpp b/src/controller/java/zap-generated/CHIPClustersWrite-JNI.cpp index 00009ac07695a1..77703a5afb7059 100644 --- a/src/controller/java/zap-generated/CHIPClustersWrite-JNI.cpp +++ b/src/controller/java/zap-generated/CHIPClustersWrite-JNI.cpp @@ -6108,58 +6108,6 @@ JNI_METHOD(void, FanControlCluster, writeFanModeAttribute) onFailure.release(); } -JNI_METHOD(void, FanControlCluster, writeFanModeSequenceAttribute) -(JNIEnv * env, jobject self, jlong clusterPtr, jobject callback, jobject value, jobject timedWriteTimeoutMs) -{ - chip::DeviceLayer::StackLock lock; - ListFreer listFreer; - using TypeInfo = chip::app::Clusters::FanControl::Attributes::FanModeSequence::TypeInfo; - TypeInfo::Type cppValue; - - std::vector> cleanupByteArrays; - std::vector> cleanupStrings; - - cppValue = - static_cast>(chip::JniReferences::GetInstance().IntegerToPrimitive(value)); - - std::unique_ptr onSuccess( - Platform::New(callback), Platform::Delete); - VerifyOrReturn(onSuccess.get() != nullptr, - chip::AndroidClusterExceptions::GetInstance().ReturnIllegalStateException( - env, callback, "Error creating native success callback", CHIP_ERROR_NO_MEMORY)); - - std::unique_ptr onFailure( - Platform::New(callback), Platform::Delete); - VerifyOrReturn(onFailure.get() != nullptr, - chip::AndroidClusterExceptions::GetInstance().ReturnIllegalStateException( - env, callback, "Error creating native failure callback", CHIP_ERROR_NO_MEMORY)); - - CHIP_ERROR err = CHIP_NO_ERROR; - FanControlCluster * cppCluster = reinterpret_cast(clusterPtr); - VerifyOrReturn(cppCluster != nullptr, - chip::AndroidClusterExceptions::GetInstance().ReturnIllegalStateException( - env, callback, "Could not get native cluster", CHIP_ERROR_INCORRECT_STATE)); - - auto successFn = chip::Callback::Callback::FromCancelable(onSuccess->Cancel()); - auto failureFn = chip::Callback::Callback::FromCancelable(onFailure->Cancel()); - - if (timedWriteTimeoutMs == nullptr) - { - err = cppCluster->WriteAttribute(cppValue, onSuccess->mContext, successFn->mCall, failureFn->mCall); - } - else - { - err = cppCluster->WriteAttribute(cppValue, onSuccess->mContext, successFn->mCall, failureFn->mCall, - chip::JniReferences::GetInstance().IntegerToPrimitive(timedWriteTimeoutMs)); - } - VerifyOrReturn( - err == CHIP_NO_ERROR, - chip::AndroidClusterExceptions::GetInstance().ReturnIllegalStateException(env, callback, "Error writing attribute", err)); - - onSuccess.release(); - onFailure.release(); -} - JNI_METHOD(void, FanControlCluster, writePercentSettingAttribute) (JNIEnv * env, jobject self, jlong clusterPtr, jobject callback, jobject value, jobject timedWriteTimeoutMs) { diff --git a/src/controller/python/chip/clusters/CHIPClusters.py b/src/controller/python/chip/clusters/CHIPClusters.py index 81fc792cf066f5..ae930bb6cad987 100644 --- a/src/controller/python/chip/clusters/CHIPClusters.py +++ b/src/controller/python/chip/clusters/CHIPClusters.py @@ -7180,7 +7180,6 @@ class ChipClusters: "attributeId": 0x00000001, "type": "int", "reportable": True, - "writable": True, }, 0x00000002: { "attributeName": "PercentSetting", diff --git a/src/controller/python/chip/clusters/Objects.py b/src/controller/python/chip/clusters/Objects.py index eb73af290d3ac2..0eaff0e245e66e 100644 --- a/src/controller/python/chip/clusters/Objects.py +++ b/src/controller/python/chip/clusters/Objects.py @@ -25298,8 +25298,8 @@ class FanModeSequenceEnum(MatterIntEnum): kOffLowHigh = 0x01 kOffLowMedHighAuto = 0x02 kOffLowHighAuto = 0x03 - kOffOnAuto = 0x04 - kOffOn = 0x05 + kOffHighAuto = 0x04 + kOffHigh = 0x05 # All received enum values that are not listed above will be mapped # to kUnknownEnumValue. This is a helper enum value that should only # be used by code to process how it handles receiving and unknown diff --git a/src/darwin/Framework/CHIP/templates/availability.yaml b/src/darwin/Framework/CHIP/templates/availability.yaml index 60cd3ac3dae78f..1603541e5de222 100644 --- a/src/darwin/Framework/CHIP/templates/availability.yaml +++ b/src/darwin/Framework/CHIP/templates/availability.yaml @@ -7751,6 +7751,11 @@ WiFiNetworkDiagnostics: AssociationFailure: - associationFailureCause + enum values: + FanControl: + FanModeSequenceEnum: + - OffHighAuto + - OffHigh bitmaps: Scenes: - CopyModeBitmap @@ -7777,6 +7782,11 @@ WiFiNetworkDiagnostics: AssociationFailure: - associationFailure + enum values: + FanControl: + FanModeSequenceEnum: + - OffOnAuto + - OffOn bitmaps: Scenes: - ScenesCopyMode @@ -7817,6 +7827,18 @@ WiFiNetworkDiagnostics: AssociationFailure: associationFailureCause: associationFailure + enum values: + FanControl: + FanModeSequenceEnum: + OffHighAuto: OffOnAuto + OffHigh: OffOn + # FanModeSequenceType is the old name of + # FanModeSequenceEnum; we need this rename annotation + # here so we don't lose the old values under that old + # name. + FanModeSequenceType: + OffHighAuto: OffOnAuto + OffHigh: OffOn bitmaps: Scenes: CopyModeBitmap: ScenesCopyMode diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.h b/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.h index 22dcdd51f5c80c..8a7f4e880dec13 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.h +++ b/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.h @@ -15839,8 +15839,14 @@ typedef NS_ENUM(uint8_t, MTRFanControlFanModeSequence) { MTRFanControlFanModeSequenceOffLowHigh MTR_AVAILABLE(ios(17.0), macos(14.0), watchos(10.0), tvos(17.0)) = 0x01, MTRFanControlFanModeSequenceOffLowMedHighAuto MTR_AVAILABLE(ios(17.0), macos(14.0), watchos(10.0), tvos(17.0)) = 0x02, MTRFanControlFanModeSequenceOffLowHighAuto MTR_AVAILABLE(ios(17.0), macos(14.0), watchos(10.0), tvos(17.0)) = 0x03, - MTRFanControlFanModeSequenceOffOnAuto MTR_AVAILABLE(ios(17.0), macos(14.0), watchos(10.0), tvos(17.0)) = 0x04, - MTRFanControlFanModeSequenceOffOn MTR_AVAILABLE(ios(17.0), macos(14.0), watchos(10.0), tvos(17.0)) = 0x05, + MTRFanControlFanModeSequenceOffHighAuto MTR_NEWLY_AVAILABLE = 0x04, + MTRFanControlFanModeSequenceOffOnAuto MTR_AVAILABLE(ios(17.0), macos(14.0), watchos(10.0), tvos(17.0)) + MTR_NEWLY_DEPRECATED("Please use MTRFanControlFanModeSequenceOffHighAuto") + = 0x04, + MTRFanControlFanModeSequenceOffHigh MTR_NEWLY_AVAILABLE = 0x05, + MTRFanControlFanModeSequenceOffOn MTR_AVAILABLE(ios(17.0), macos(14.0), watchos(10.0), tvos(17.0)) + MTR_NEWLY_DEPRECATED("Please use MTRFanControlFanModeSequenceOffHigh") + = 0x05, } MTR_AVAILABLE(ios(17.0), macos(14.0), watchos(10.0), tvos(17.0)); typedef NS_ENUM(uint8_t, MTRFanControlFanModeSequenceType) { @@ -15848,8 +15854,8 @@ typedef NS_ENUM(uint8_t, MTRFanControlFanModeSequenceType) { MTRFanControlFanModeSequenceTypeOffLowHigh MTR_DEPRECATED("Please use MTRFanControlFanModeSequenceOffLowHigh", ios(16.1, 17.0), macos(13.0, 14.0), watchos(9.1, 10.0), tvos(16.1, 17.0)) = 0x01, MTRFanControlFanModeSequenceTypeOffLowMedHighAuto MTR_DEPRECATED("Please use MTRFanControlFanModeSequenceOffLowMedHighAuto", ios(16.1, 17.0), macos(13.0, 14.0), watchos(9.1, 10.0), tvos(16.1, 17.0)) = 0x02, MTRFanControlFanModeSequenceTypeOffLowHighAuto MTR_DEPRECATED("Please use MTRFanControlFanModeSequenceOffLowHighAuto", ios(16.1, 17.0), macos(13.0, 14.0), watchos(9.1, 10.0), tvos(16.1, 17.0)) = 0x03, - MTRFanControlFanModeSequenceTypeOffOnAuto MTR_DEPRECATED("Please use MTRFanControlFanModeSequenceOffOnAuto", ios(16.1, 17.0), macos(13.0, 14.0), watchos(9.1, 10.0), tvos(16.1, 17.0)) = 0x04, - MTRFanControlFanModeSequenceTypeOffOn MTR_DEPRECATED("Please use MTRFanControlFanModeSequenceOffOn", ios(16.1, 17.0), macos(13.0, 14.0), watchos(9.1, 10.0), tvos(16.1, 17.0)) = 0x05, + MTRFanControlFanModeSequenceTypeOffOnAuto MTR_DEPRECATED("Please use MTRFanControlFanModeSequenceOffHighAuto", ios(16.1, 17.0), macos(13.0, 14.0), watchos(9.1, 10.0), tvos(16.1, 17.0)) = 0x04, + MTRFanControlFanModeSequenceTypeOffOn MTR_DEPRECATED("Please use MTRFanControlFanModeSequenceOffHigh", ios(16.1, 17.0), macos(13.0, 14.0), watchos(9.1, 10.0), tvos(16.1, 17.0)) = 0x05, } MTR_DEPRECATED("Please use MTRFanControlFanModeSequence", ios(16.1, 17.0), macos(13.0, 14.0), watchos(9.1, 10.0), tvos(16.1, 17.0)); typedef NS_ENUM(uint8_t, MTRFanControlStepDirection) { diff --git a/zzz_generated/app-common/app-common/zap-generated/cluster-enums-check.h b/zzz_generated/app-common/app-common/zap-generated/cluster-enums-check.h index efe20ce7a401a7..4e3c6d09cef847 100644 --- a/zzz_generated/app-common/app-common/zap-generated/cluster-enums-check.h +++ b/zzz_generated/app-common/app-common/zap-generated/cluster-enums-check.h @@ -1979,8 +1979,8 @@ static auto __attribute__((unused)) EnsureKnownEnumValue(FanControl::FanModeSequ case EnumType::kOffLowHigh: case EnumType::kOffLowMedHighAuto: case EnumType::kOffLowHighAuto: - case EnumType::kOffOnAuto: - case EnumType::kOffOn: + case EnumType::kOffHighAuto: + case EnumType::kOffHigh: return val; default: return static_cast(6); diff --git a/zzz_generated/app-common/app-common/zap-generated/cluster-enums.h b/zzz_generated/app-common/app-common/zap-generated/cluster-enums.h index 559a735f499971..28cff087bcc9f1 100644 --- a/zzz_generated/app-common/app-common/zap-generated/cluster-enums.h +++ b/zzz_generated/app-common/app-common/zap-generated/cluster-enums.h @@ -2879,8 +2879,8 @@ enum class FanModeSequenceEnum : uint8_t kOffLowHigh = 0x01, kOffLowMedHighAuto = 0x02, kOffLowHighAuto = 0x03, - kOffOnAuto = 0x04, - kOffOn = 0x05, + kOffHighAuto = 0x04, + kOffHigh = 0x05, // All received enum values that are not listed above will be mapped // to kUnknownEnumValue. This is a helper enum value that should only // be used by code to process how it handles receiving and unknown diff --git a/zzz_generated/chip-tool/zap-generated/cluster/Commands.h b/zzz_generated/chip-tool/zap-generated/cluster/Commands.h index 530b36936233da..50731135213eb3 100644 --- a/zzz_generated/chip-tool/zap-generated/cluster/Commands.h +++ b/zzz_generated/chip-tool/zap-generated/cluster/Commands.h @@ -17663,7 +17663,8 @@ void registerClusterFanControl(Commands & commands, CredentialIssuerCommands * c make_unique>( Id, "fan-mode", 0, UINT8_MAX, Attributes::FanMode::Id, WriteCommandType::kWrite, credsIssuerConfig), // make_unique>( - Id, "fan-mode-sequence", 0, UINT8_MAX, Attributes::FanModeSequence::Id, WriteCommandType::kWrite, credsIssuerConfig), // + Id, "fan-mode-sequence", 0, UINT8_MAX, Attributes::FanModeSequence::Id, WriteCommandType::kForceWrite, + credsIssuerConfig), // make_unique>>( Id, "percent-setting", 0, UINT8_MAX, Attributes::PercentSetting::Id, WriteCommandType::kWrite, credsIssuerConfig), // make_unique>(Id, "percent-current", 0, UINT8_MAX, Attributes::PercentCurrent::Id, diff --git a/zzz_generated/darwin-framework-tool/zap-generated/cluster/Commands.h b/zzz_generated/darwin-framework-tool/zap-generated/cluster/Commands.h index 960635d511d42a..ffabd5c6ba9a12 100644 --- a/zzz_generated/darwin-framework-tool/zap-generated/cluster/Commands.h +++ b/zzz_generated/darwin-framework-tool/zap-generated/cluster/Commands.h @@ -87490,47 +87490,6 @@ class ReadFanControlFanModeSequence : public ReadAttribute { } }; -class WriteFanControlFanModeSequence : public WriteAttribute { -public: - WriteFanControlFanModeSequence() - : WriteAttribute("fan-mode-sequence") - { - AddArgument("attr-name", "fan-mode-sequence"); - AddArgument("attr-value", 0, UINT8_MAX, &mValue); - WriteAttribute::AddArguments(); - } - - ~WriteFanControlFanModeSequence() - { - } - - CHIP_ERROR SendCommand(MTRBaseDevice * device, chip::EndpointId endpointId) override - { - constexpr chip::ClusterId clusterId = chip::app::Clusters::FanControl::Id; - constexpr chip::AttributeId attributeId = chip::app::Clusters::FanControl::Attributes::FanModeSequence::Id; - - ChipLogProgress(chipTool, "Sending cluster (0x%08" PRIX32 ") WriteAttribute (0x%08" PRIX32 ") on endpoint %u", clusterId, attributeId, endpointId); - dispatch_queue_t callbackQueue = dispatch_queue_create("com.chip.command", DISPATCH_QUEUE_SERIAL); - __auto_type * cluster = [[MTRBaseClusterFanControl alloc] initWithDevice:device endpointID:@(endpointId) queue:callbackQueue]; - __auto_type * params = [[MTRWriteParams alloc] init]; - params.timedWriteTimeout = mTimedInteractionTimeoutMs.HasValue() ? [NSNumber numberWithUnsignedShort:mTimedInteractionTimeoutMs.Value()] : nil; - params.dataVersion = mDataVersion.HasValue() ? [NSNumber numberWithUnsignedInt:mDataVersion.Value()] : nil; - NSNumber * _Nonnull value = [NSNumber numberWithUnsignedChar:mValue]; - - [cluster writeAttributeFanModeSequenceWithValue:value params:params completion:^(NSError * _Nullable error) { - if (error != nil) { - LogNSError("FanControl FanModeSequence write Error", error); - RemoteDataModelLogger::LogAttributeErrorAsJSON(@(endpointId), @(clusterId), @(attributeId), error); - } - SetCommandExitStatus(error); - }]; - return CHIP_NO_ERROR; - } - -private: - uint8_t mValue; -}; - class SubscribeAttributeFanControlFanModeSequence : public SubscribeAttribute { public: SubscribeAttributeFanControlFanModeSequence() @@ -158831,7 +158790,6 @@ void registerClusterFanControl(Commands & commands) make_unique(), // make_unique(), // make_unique(), // - make_unique(), // make_unique(), // make_unique(), // make_unique(), // diff --git a/zzz_generated/darwin-framework-tool/zap-generated/test/Commands.h b/zzz_generated/darwin-framework-tool/zap-generated/test/Commands.h index 71266e224a1a6a..8613471b1d7068 100644 --- a/zzz_generated/darwin-framework-tool/zap-generated/test/Commands.h +++ b/zzz_generated/darwin-framework-tool/zap-generated/test/Commands.h @@ -142225,92 +142225,84 @@ class TestFanControl : public TestCommandBridge { err = TestReadBackFanMode_2(); break; case 3: - ChipLogProgress(chipTool, " ***** Test Step 3 : Write fan mode sequence\n"); - err = TestWriteFanModeSequence_3(); + ChipLogProgress(chipTool, " ***** Test Step 3 : Write percent setting\n"); + err = TestWritePercentSetting_3(); break; case 4: - ChipLogProgress(chipTool, " ***** Test Step 4 : Read back fan mode sequence\n"); - err = TestReadBackFanModeSequence_4(); + ChipLogProgress(chipTool, " ***** Test Step 4 : Read back percent setting\n"); + err = TestReadBackPercentSetting_4(); break; case 5: - ChipLogProgress(chipTool, " ***** Test Step 5 : Write percent setting\n"); - err = TestWritePercentSetting_5(); + ChipLogProgress(chipTool, " ***** Test Step 5 : Read back speed setting\n"); + err = TestReadBackSpeedSetting_5(); break; case 6: - ChipLogProgress(chipTool, " ***** Test Step 6 : Read back percent setting\n"); - err = TestReadBackPercentSetting_6(); + ChipLogProgress(chipTool, " ***** Test Step 6 : Read back speed current\n"); + err = TestReadBackSpeedCurrent_6(); break; case 7: - ChipLogProgress(chipTool, " ***** Test Step 7 : Read back speed setting\n"); - err = TestReadBackSpeedSetting_7(); + ChipLogProgress(chipTool, " ***** Test Step 7 : Write percent setting\n"); + err = TestWritePercentSetting_7(); break; case 8: - ChipLogProgress(chipTool, " ***** Test Step 8 : Read back speed current\n"); - err = TestReadBackSpeedCurrent_8(); + ChipLogProgress(chipTool, " ***** Test Step 8 : Read back percent setting\n"); + err = TestReadBackPercentSetting_8(); break; case 9: - ChipLogProgress(chipTool, " ***** Test Step 9 : Write percent setting\n"); - err = TestWritePercentSetting_9(); + ChipLogProgress(chipTool, " ***** Test Step 9 : Write speed setting\n"); + err = TestWriteSpeedSetting_9(); break; case 10: - ChipLogProgress(chipTool, " ***** Test Step 10 : Read back percent setting\n"); - err = TestReadBackPercentSetting_10(); + ChipLogProgress(chipTool, " ***** Test Step 10 : Read back speed setting\n"); + err = TestReadBackSpeedSetting_10(); break; case 11: - ChipLogProgress(chipTool, " ***** Test Step 11 : Write speed setting\n"); - err = TestWriteSpeedSetting_11(); + ChipLogProgress(chipTool, " ***** Test Step 11 : Read back percent setting\n"); + err = TestReadBackPercentSetting_11(); break; case 12: - ChipLogProgress(chipTool, " ***** Test Step 12 : Read back speed setting\n"); - err = TestReadBackSpeedSetting_12(); + ChipLogProgress(chipTool, " ***** Test Step 12 : Read back percent current\n"); + err = TestReadBackPercentCurrent_12(); break; case 13: - ChipLogProgress(chipTool, " ***** Test Step 13 : Read back percent setting\n"); - err = TestReadBackPercentSetting_13(); + ChipLogProgress(chipTool, " ***** Test Step 13 : Write speed setting\n"); + err = TestWriteSpeedSetting_13(); break; case 14: - ChipLogProgress(chipTool, " ***** Test Step 14 : Read back percent current\n"); - err = TestReadBackPercentCurrent_14(); + ChipLogProgress(chipTool, " ***** Test Step 14 : Read back speed setting\n"); + err = TestReadBackSpeedSetting_14(); break; case 15: - ChipLogProgress(chipTool, " ***** Test Step 15 : Write speed setting\n"); - err = TestWriteSpeedSetting_15(); + ChipLogProgress(chipTool, " ***** Test Step 15 : Write fan mode\n"); + err = TestWriteFanMode_15(); break; case 16: - ChipLogProgress(chipTool, " ***** Test Step 16 : Read back speed setting\n"); - err = TestReadBackSpeedSetting_16(); + ChipLogProgress(chipTool, " ***** Test Step 16 : Read back percent setting\n"); + err = TestReadBackPercentSetting_16(); break; case 17: - ChipLogProgress(chipTool, " ***** Test Step 17 : Write fan mode\n"); - err = TestWriteFanMode_17(); + ChipLogProgress(chipTool, " ***** Test Step 17 : Read back percent current\n"); + err = TestReadBackPercentCurrent_17(); break; case 18: - ChipLogProgress(chipTool, " ***** Test Step 18 : Read back percent setting\n"); - err = TestReadBackPercentSetting_18(); + ChipLogProgress(chipTool, " ***** Test Step 18 : Read back speed setting\n"); + err = TestReadBackSpeedSetting_18(); break; case 19: - ChipLogProgress(chipTool, " ***** Test Step 19 : Read back percent current\n"); - err = TestReadBackPercentCurrent_19(); + ChipLogProgress(chipTool, " ***** Test Step 19 : Read back speed current\n"); + err = TestReadBackSpeedCurrent_19(); break; case 20: - ChipLogProgress(chipTool, " ***** Test Step 20 : Read back speed setting\n"); - err = TestReadBackSpeedSetting_20(); + ChipLogProgress(chipTool, " ***** Test Step 20 : Write fan mode\n"); + err = TestWriteFanMode_20(); break; case 21: - ChipLogProgress(chipTool, " ***** Test Step 21 : Read back speed current\n"); - err = TestReadBackSpeedCurrent_21(); + ChipLogProgress(chipTool, " ***** Test Step 21 : Read back percent setting\n"); + err = TestReadBackPercentSetting_21(); break; case 22: - ChipLogProgress(chipTool, " ***** Test Step 22 : Write fan mode\n"); - err = TestWriteFanMode_22(); - break; - case 23: - ChipLogProgress(chipTool, " ***** Test Step 23 : Read back percent setting\n"); - err = TestReadBackPercentSetting_23(); - break; - case 24: - ChipLogProgress(chipTool, " ***** Test Step 24 : Read back speed setting\n"); - err = TestReadBackSpeedSetting_24(); + ChipLogProgress(chipTool, " ***** Test Step 22 : Read back speed setting\n"); + err = TestReadBackSpeedSetting_22(); break; } @@ -142392,12 +142384,6 @@ class TestFanControl : public TestCommandBridge { case 22: VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); break; - case 23: - VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); - break; - case 24: - VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0)); - break; } // Go on to the next test. @@ -142408,7 +142394,7 @@ class TestFanControl : public TestCommandBridge { private: std::atomic_uint16_t mTestIndex; - const uint16_t mTestCount = 25; + const uint16_t mTestCount = 23; chip::Optional mNodeId; chip::Optional mCluster; @@ -142467,51 +142453,7 @@ class TestFanControl : public TestCommandBridge { return CHIP_NO_ERROR; } - CHIP_ERROR TestWriteFanModeSequence_3() - { - - MTRBaseDevice * device = GetDevice("alpha"); - __auto_type * cluster = [[MTRBaseClusterFanControl alloc] initWithDevice:device endpointID:@(1) queue:mCallbackQueue]; - VerifyOrReturnError(cluster != nil, CHIP_ERROR_INCORRECT_STATE); - - id fanModeSequenceArgument; - fanModeSequenceArgument = - [NSNumber numberWithUnsignedChar:5U]; - [cluster writeAttributeFanModeSequenceWithValue:fanModeSequenceArgument completion:^(NSError * _Nullable err) { - NSLog(@"Write fan mode sequence Error: %@", err); - - VerifyOrReturn(CheckValue("status", err ? err.code : 0, 0)); - - NextTest(); - }]; - - return CHIP_NO_ERROR; - } - - CHIP_ERROR TestReadBackFanModeSequence_4() - { - - MTRBaseDevice * device = GetDevice("alpha"); - __auto_type * cluster = [[MTRBaseClusterFanControl alloc] initWithDevice:device endpointID:@(1) queue:mCallbackQueue]; - VerifyOrReturnError(cluster != nil, CHIP_ERROR_INCORRECT_STATE); - - [cluster readAttributeFanModeSequenceWithCompletion:^(NSNumber * _Nullable value, NSError * _Nullable err) { - NSLog(@"Read back fan mode sequence Error: %@", err); - - VerifyOrReturn(CheckValue("status", err ? err.code : 0, 0)); - - { - id actualValue = value; - VerifyOrReturn(CheckValue("FanModeSequence", actualValue, 5U)); - } - - NextTest(); - }]; - - return CHIP_NO_ERROR; - } - - CHIP_ERROR TestWritePercentSetting_5() + CHIP_ERROR TestWritePercentSetting_3() { MTRBaseDevice * device = GetDevice("alpha"); @@ -142532,7 +142474,7 @@ class TestFanControl : public TestCommandBridge { return CHIP_NO_ERROR; } - CHIP_ERROR TestReadBackPercentSetting_6() + CHIP_ERROR TestReadBackPercentSetting_4() { MTRBaseDevice * device = GetDevice("alpha"); @@ -142556,7 +142498,7 @@ class TestFanControl : public TestCommandBridge { return CHIP_NO_ERROR; } - CHIP_ERROR TestReadBackSpeedSetting_7() + CHIP_ERROR TestReadBackSpeedSetting_5() { MTRBaseDevice * device = GetDevice("alpha"); @@ -142580,7 +142522,7 @@ class TestFanControl : public TestCommandBridge { return CHIP_NO_ERROR; } - CHIP_ERROR TestReadBackSpeedCurrent_8() + CHIP_ERROR TestReadBackSpeedCurrent_6() { MTRBaseDevice * device = GetDevice("alpha"); @@ -142603,7 +142545,7 @@ class TestFanControl : public TestCommandBridge { return CHIP_NO_ERROR; } - CHIP_ERROR TestWritePercentSetting_9() + CHIP_ERROR TestWritePercentSetting_7() { MTRBaseDevice * device = GetDevice("alpha"); @@ -142623,7 +142565,7 @@ class TestFanControl : public TestCommandBridge { return CHIP_NO_ERROR; } - CHIP_ERROR TestReadBackPercentSetting_10() + CHIP_ERROR TestReadBackPercentSetting_8() { MTRBaseDevice * device = GetDevice("alpha"); @@ -142647,7 +142589,7 @@ class TestFanControl : public TestCommandBridge { return CHIP_NO_ERROR; } - CHIP_ERROR TestWriteSpeedSetting_11() + CHIP_ERROR TestWriteSpeedSetting_9() { MTRBaseDevice * device = GetDevice("alpha"); @@ -142668,7 +142610,7 @@ class TestFanControl : public TestCommandBridge { return CHIP_NO_ERROR; } - CHIP_ERROR TestReadBackSpeedSetting_12() + CHIP_ERROR TestReadBackSpeedSetting_10() { MTRBaseDevice * device = GetDevice("alpha"); @@ -142692,7 +142634,7 @@ class TestFanControl : public TestCommandBridge { return CHIP_NO_ERROR; } - CHIP_ERROR TestReadBackPercentSetting_13() + CHIP_ERROR TestReadBackPercentSetting_11() { MTRBaseDevice * device = GetDevice("alpha"); @@ -142716,7 +142658,7 @@ class TestFanControl : public TestCommandBridge { return CHIP_NO_ERROR; } - CHIP_ERROR TestReadBackPercentCurrent_14() + CHIP_ERROR TestReadBackPercentCurrent_12() { MTRBaseDevice * device = GetDevice("alpha"); @@ -142739,7 +142681,7 @@ class TestFanControl : public TestCommandBridge { return CHIP_NO_ERROR; } - CHIP_ERROR TestWriteSpeedSetting_15() + CHIP_ERROR TestWriteSpeedSetting_13() { MTRBaseDevice * device = GetDevice("alpha"); @@ -142759,7 +142701,7 @@ class TestFanControl : public TestCommandBridge { return CHIP_NO_ERROR; } - CHIP_ERROR TestReadBackSpeedSetting_16() + CHIP_ERROR TestReadBackSpeedSetting_14() { MTRBaseDevice * device = GetDevice("alpha"); @@ -142783,7 +142725,7 @@ class TestFanControl : public TestCommandBridge { return CHIP_NO_ERROR; } - CHIP_ERROR TestWriteFanMode_17() + CHIP_ERROR TestWriteFanMode_15() { MTRBaseDevice * device = GetDevice("alpha"); @@ -142804,7 +142746,7 @@ class TestFanControl : public TestCommandBridge { return CHIP_NO_ERROR; } - CHIP_ERROR TestReadBackPercentSetting_18() + CHIP_ERROR TestReadBackPercentSetting_16() { MTRBaseDevice * device = GetDevice("alpha"); @@ -142828,7 +142770,7 @@ class TestFanControl : public TestCommandBridge { return CHIP_NO_ERROR; } - CHIP_ERROR TestReadBackPercentCurrent_19() + CHIP_ERROR TestReadBackPercentCurrent_17() { MTRBaseDevice * device = GetDevice("alpha"); @@ -142851,7 +142793,7 @@ class TestFanControl : public TestCommandBridge { return CHIP_NO_ERROR; } - CHIP_ERROR TestReadBackSpeedSetting_20() + CHIP_ERROR TestReadBackSpeedSetting_18() { MTRBaseDevice * device = GetDevice("alpha"); @@ -142875,7 +142817,7 @@ class TestFanControl : public TestCommandBridge { return CHIP_NO_ERROR; } - CHIP_ERROR TestReadBackSpeedCurrent_21() + CHIP_ERROR TestReadBackSpeedCurrent_19() { MTRBaseDevice * device = GetDevice("alpha"); @@ -142898,7 +142840,7 @@ class TestFanControl : public TestCommandBridge { return CHIP_NO_ERROR; } - CHIP_ERROR TestWriteFanMode_22() + CHIP_ERROR TestWriteFanMode_20() { MTRBaseDevice * device = GetDevice("alpha"); @@ -142919,7 +142861,7 @@ class TestFanControl : public TestCommandBridge { return CHIP_NO_ERROR; } - CHIP_ERROR TestReadBackPercentSetting_23() + CHIP_ERROR TestReadBackPercentSetting_21() { MTRBaseDevice * device = GetDevice("alpha"); @@ -142942,7 +142884,7 @@ class TestFanControl : public TestCommandBridge { return CHIP_NO_ERROR; } - CHIP_ERROR TestReadBackSpeedSetting_24() + CHIP_ERROR TestReadBackSpeedSetting_22() { MTRBaseDevice * device = GetDevice("alpha"); From 3cb6fcd649a8c6c0d6077bb99e37adf9841dfb17 Mon Sep 17 00:00:00 2001 From: Andrei Litvin Date: Tue, 7 Nov 2023 12:04:06 -0500 Subject: [PATCH 2/4] Make TestAddressResolve_DefaultImpl.cpp work on thread devices (#30249) * Update AddressResolve test to not need IPv4. EFR32 unit tests were failing occassionally and I believe it is due to an IPv4 usage in a thread device. Changes: - only use IPV6 in the test - Add logs in case IP address parse fails - Add validation assertions that low/medium/high addresses are ordered as the test expects. * Restyle --- .../tests/TestAddressResolve_DefaultImpl.cpp | 40 ++++++++++++++----- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/src/lib/address_resolve/tests/TestAddressResolve_DefaultImpl.cpp b/src/lib/address_resolve/tests/TestAddressResolve_DefaultImpl.cpp index 05d2491475ecef..f926fc227ea294 100644 --- a/src/lib/address_resolve/tests/TestAddressResolve_DefaultImpl.cpp +++ b/src/lib/address_resolve/tests/TestAddressResolve_DefaultImpl.cpp @@ -1,5 +1,4 @@ /* - * * Copyright (c) 2021 Project CHIP Authors * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -25,33 +24,45 @@ using namespace chip::AddressResolve; namespace { +using chip::Dnssd::IPAddressSorter::IpScore; +using chip::Dnssd::IPAddressSorter::ScoreIpAddress; + constexpr uint8_t kNumberOfAvailableSlots = CHIP_CONFIG_MDNS_RESOLVE_LOOKUP_RESULTS; Transport::PeerAddress GetAddressWithLowScore(uint16_t port = CHIP_PORT, Inet::InterfaceId interfaceId = Inet::InterfaceId::Null()) { - // Embedded IPv4 + // Unique Local - expect score "3" Inet::IPAddress ipAddress; - Inet::IPAddress::FromString("0:0:0:0:0:0:111.22.33.44", ipAddress); - + if (!Inet::IPAddress::FromString("fdff:aabb:ccdd:1::4", ipAddress)) + { + ChipLogError(NotSpecified, "!!!!!!!! IP Parse failure"); + } return Transport::PeerAddress::UDP(ipAddress, port, interfaceId); } Transport::PeerAddress GetAddressWithMediumScore(uint16_t port = CHIP_PORT, Inet::InterfaceId interfaceId = Inet::InterfaceId::Null()) { - // Unique Local - Inet::IPAddress ipAddress; - Inet::IPAddress::FromString("fdff:aabb:ccdd:1::4", ipAddress); + // Global Unicast - expect score '4' + Inet::IPAddress ipAddress; + if (!Inet::IPAddress::FromString("2001::aabb:ccdd:2233:4455", ipAddress)) + { + ChipLogError(NotSpecified, "!!!!!!!! IP Parse failure"); + } return Transport::PeerAddress::UDP(ipAddress, port, interfaceId); } Transport::PeerAddress GetAddressWithHighScore(uint16_t port = CHIP_PORT, Inet::InterfaceId interfaceId = Inet::InterfaceId::Null()) { - // Global Unicast + // LinkLocal - expect score '7' + // Likely that the interfaceId is wrong (link local needs it), + // however we do not expect sorter to care Inet::IPAddress ipAddress; - Inet::IPAddress::FromString("2001::aabb:ccdd:2233:4455", ipAddress); - + if (!Inet::IPAddress::FromString("fe80::aabb:ccdd:2233:4455", ipAddress)) + { + ChipLogError(NotSpecified, "!!!!!!!! IP Parse failure"); + } return Transport::PeerAddress::UDP(ipAddress, port, interfaceId); } @@ -66,6 +77,15 @@ void TestLookupResult(nlTestSuite * inSuite, void * inContext) ResolveResult highResult; highResult.address = GetAddressWithHighScore(); + // Ensure test expectations regarding ordering is matched + + IpScore lowScore = ScoreIpAddress(lowResult.address.GetIPAddress(), Inet::InterfaceId::Null()); + IpScore mediumScore = ScoreIpAddress(mediumResult.address.GetIPAddress(), Inet::InterfaceId::Null()); + IpScore highScore = ScoreIpAddress(highResult.address.GetIPAddress(), Inet::InterfaceId::Null()); + + NL_TEST_ASSERT(inSuite, to_underlying(lowScore) < to_underlying(mediumScore)); + NL_TEST_ASSERT(inSuite, to_underlying(mediumScore) < to_underlying(highScore)); + ResolveResult outResult; AddressResolve::NodeLookupHandle handle; From f4bf696acbf388bc1567edb8e25b75ebc1233cc4 Mon Sep 17 00:00:00 2001 From: C Freeman Date: Tue, 7 Nov 2023 12:26:32 -0500 Subject: [PATCH 3/4] Python testing: Move code out of main file (#30207) * Python testing: Move code out of main file This file is becoming large, so I moved out some of the code that is logically similar. I also abstraceted the setup into a separate function. The reason for this: Right now, all these tests are run in the CI against all clusters. All cluster is a special case and it is not clear that it is ever going to be spec conformant. I would like to split that test out, enable the error and start running it against individual example apps as they get corrected. There are no code changes in this PR, just moves and adjustments of the imports. * move attribute ids to enum --- .../TC_DeviceBasicComposition.py | 376 ++---------------- .../TestMatterTestingSupport.py | 6 +- .../basic_composition_support.py | 163 ++++++++ src/python_testing/global_attribute_ids.py | 28 ++ .../taglist_and_topology_test_support.py | 191 +++++++++ 5 files changed, 426 insertions(+), 338 deletions(-) create mode 100644 src/python_testing/basic_composition_support.py create mode 100644 src/python_testing/global_attribute_ids.py create mode 100644 src/python_testing/taglist_and_topology_test_support.py diff --git a/src/python_testing/TC_DeviceBasicComposition.py b/src/python_testing/TC_DeviceBasicComposition.py index 2288c7c5a4b596..bb85b045923d06 100644 --- a/src/python_testing/TC_DeviceBasicComposition.py +++ b/src/python_testing/TC_DeviceBasicComposition.py @@ -15,108 +15,25 @@ # limitations under the License. # -import base64 -import copy -import functools -import json import logging -import pathlib -import sys -from collections import defaultdict -from dataclasses import dataclass, field -from pprint import pprint -from typing import Any, Callable, Optional +from dataclasses import dataclass +from typing import Any, Callable import chip.clusters as Clusters import chip.clusters.ClusterObjects import chip.tlv +from basic_composition_support import BasicCompositionTests from chip.clusters.Attribute import ValueDecodeFailure from chip.tlv import uint from conformance_support import ConformanceDecision, conformance_allowed +from global_attribute_ids import GlobalAttributeIds from matter_testing_support import (AttributePathLocation, ClusterPathLocation, CommandPathLocation, MatterBaseTest, async_test_body, default_matter_test_main) from mobly import asserts from spec_parsing_support import CommandType, build_xml_clusters - -ATTRIBUTE_LIST_ID = 0xFFFB -ACCEPTED_COMMAND_LIST_ID = 0xFFF9 -GENERATED_COMMAND_LIST_ID = 0xFFF8 -FEATURE_MAP_ID = 0xFFFC -CLUSTER_REVISION_ID = 0xFFFD - - -def MatterTlvToJson(tlv_data: dict[int, Any]) -> dict[str, Any]: - """Given TLV data for a specific cluster instance, convert to the Matter JSON format.""" - - matter_json_dict = {} - - key_type_mappings = { - chip.tlv.uint: "UINT", - int: "INT", - bool: "BOOL", - list: "ARRAY", - dict: "STRUCT", - chip.tlv.float32: "FLOAT", - float: "DOUBLE", - bytes: "BYTES", - str: "STRING", - ValueDecodeFailure: "ERROR", - type(None): "NULL", - } - - def ConvertValue(value) -> Any: - if isinstance(value, ValueDecodeFailure): - raise ValueError(f"Bad Value: {str(value)}") - - if isinstance(value, bytes): - return base64.b64encode(value).decode("UTF-8") - elif isinstance(value, list): - value = [ConvertValue(item) for item in value] - elif isinstance(value, dict): - value = MatterTlvToJson(value) - - return value - - for key in tlv_data: - value_type = type(tlv_data[key]) - value = copy.deepcopy(tlv_data[key]) - - element_type: str = key_type_mappings[value_type] - sub_element_type = "" - - try: - new_value = ConvertValue(value) - except ValueError as e: - new_value = str(e) - - if element_type: - if element_type == "ARRAY": - if len(new_value): - sub_element_type = key_type_mappings[type(tlv_data[key][0])] - else: - sub_element_type = "?" - - new_key = "" - if element_type: - if sub_element_type: - new_key = f"{str(key)}:{element_type}-{sub_element_type}" - else: - new_key = f"{str(key)}:{element_type}" - else: - new_key = str(key) - - matter_json_dict[new_key] = new_value - - return matter_json_dict - - -@dataclass -class TagProblem: - root: int - missing_attribute: bool - missing_feature: bool - duplicates: set[int] - same_tag: set[int] = field(default_factory=set) +from taglist_and_topology_test_support import (create_device_type_list_for_root, create_device_type_lists, find_tag_list_problems, + find_tree_roots, get_all_children, get_direct_children_of_root, parts_list_cycles, + separate_endpoint_types) def check_int_in_range(min_value: int, max_value: int, allow_null: bool = False) -> Callable: @@ -186,232 +103,11 @@ def check_no_duplicates(obj: Any) -> None: raise ValueError(f"Value {str(obj)} contains duplicate values") -def separate_endpoint_types(endpoint_dict: dict[int, Any]) -> tuple[list[int], list[int]]: - """Returns a tuple containing the list of flat endpoints and a list of tree endpoints""" - flat = [] - tree = [] - for endpoint_id, endpoint in endpoint_dict.items(): - if endpoint_id == 0: - continue - aggregator_id = 0x000e - content_app_id = 0x0024 - device_types = [d.deviceType for d in endpoint[Clusters.Descriptor][Clusters.Descriptor.Attributes.DeviceTypeList]] - if aggregator_id in device_types: - flat.append(endpoint_id) - else: - if content_app_id in device_types: - continue - tree.append(endpoint_id) - return (flat, tree) - - -def get_all_children(endpoint_id, endpoint_dict: dict[int, Any]) -> set[int]: - """Returns all the children (include subchildren) of the given endpoint - This assumes we've already checked that there are no cycles, so we can do the dumb things and just trace the tree - """ - children = set() - - def add_children(endpoint_id, children): - immediate_children = endpoint_dict[endpoint_id][Clusters.Descriptor][Clusters.Descriptor.Attributes.PartsList] - if not immediate_children: - return - children.update(set(immediate_children)) - for child in immediate_children: - add_children(child, children) - - add_children(endpoint_id, children) - return children - - -def find_tree_roots(tree_endpoints: list[int], endpoint_dict: dict[int, Any]) -> set[int]: - """Returns a set of all the endpoints in tree_endpoints that are roots for a tree (not include singletons)""" - tree_roots = set() - - def find_tree_root(current_id): - for endpoint_id, endpoint in endpoint_dict.items(): - if endpoint_id not in tree_endpoints: - continue - if current_id in endpoint[Clusters.Descriptor][Clusters.Descriptor.Attributes.PartsList]: - # this is not the root, move up - return find_tree_root(endpoint_id) - return current_id - - for endpoint_id in tree_endpoints: - root = find_tree_root(endpoint_id) - if root != endpoint_id: - tree_roots.add(root) - return tree_roots - - -def parts_list_cycles(tree_endpoints: list[int], endpoint_dict: dict[int, Any]) -> list[int]: - """Returns a list of all the endpoints in the tree_endpoints list that contain cycles""" - def parts_list_cycle_detect(visited: set, current_id: int) -> bool: - if current_id in visited: - return True - visited.add(current_id) - for child in endpoint_dict[current_id][Clusters.Descriptor][Clusters.Descriptor.Attributes.PartsList]: - child_has_cycles = parts_list_cycle_detect(visited, child) - if child_has_cycles: - return True - return False - - cycles = [] - # This is quick enough that we can do all the endpoints wihtout searching for the roots - for endpoint_id in tree_endpoints: - visited = set() - if parts_list_cycle_detect(visited, endpoint_id): - cycles.append(endpoint_id) - return cycles - - -def create_device_type_lists(roots: list[int], endpoint_dict: dict[int, Any]) -> dict[int, dict[int, set[int]]]: - """Returns a list of endpoints per device type for each root in the list""" - device_types = {} - for root in roots: - tree_device_types = defaultdict(set) - eps = get_all_children(root, endpoint_dict) - eps.add(root) - for ep in eps: - for d in endpoint_dict[ep][Clusters.Descriptor][Clusters.Descriptor.Attributes.DeviceTypeList]: - tree_device_types[d.deviceType].add(ep) - device_types[root] = tree_device_types - - return device_types - - -def get_direct_children_of_root(endpoint_dict: dict[int, Any]) -> set[int]: - root_children = set(endpoint_dict[0][Clusters.Descriptor][Clusters.Descriptor.Attributes.PartsList]) - direct_children = root_children - for ep in root_children: - ep_children = set(endpoint_dict[ep][Clusters.Descriptor][Clusters.Descriptor.Attributes.PartsList]) - direct_children = direct_children - ep_children - return direct_children - - -def create_device_type_list_for_root(direct_children, endpoint_dict: dict[int, Any]) -> dict[int, set[int]]: - device_types = defaultdict(set) - for ep in direct_children: - for d in endpoint_dict[ep][Clusters.Descriptor][Clusters.Descriptor.Attributes.DeviceTypeList]: - device_types[d.deviceType].add(ep) - return device_types - - -def cmp_tag_list(a: Clusters.Descriptor.Structs.SemanticTagStruct, b: Clusters.Descriptor.Structs.SemanticTagStruct): - if a.mfgCode != b.mfgCode: - return -1 if a.mfgCode < b.mfgCode else 1 - if a.namespaceID != b.namespaceID: - return -1 if a.namespaceID < b.namespaceID else 1 - if a.tag != b.tag: - return -1 if a.tag < b.tag else 1 - if a.label != b.label: - return -1 if a.label < b.label else 1 - return 0 - - -def find_tag_list_problems(roots: list[int], device_types: dict[int, dict[int, set[int]]], endpoint_dict: dict[int, Any]) -> dict[int, TagProblem]: - """Checks for non-spec compliant tag lists""" - tag_problems = {} - for root in roots: - for _, endpoints in device_types[root].items(): - if len(endpoints) < 2: - continue - for endpoint in endpoints: - missing_feature = not bool(endpoint_dict[endpoint][Clusters.Descriptor] - [Clusters.Descriptor.Attributes.FeatureMap] & Clusters.Descriptor.Bitmaps.Feature.kTagList) - if Clusters.Descriptor.Attributes.TagList not in endpoint_dict[endpoint][Clusters.Descriptor] or endpoint_dict[endpoint][Clusters.Descriptor][Clusters.Descriptor.Attributes.TagList] == []: - tag_problems[endpoint] = TagProblem(root=root, missing_attribute=True, - missing_feature=missing_feature, duplicates=endpoints) - continue - # Check that this tag isn't the same as the other tags in the endpoint list - duplicate_tags = set() - for other in endpoints: - if other == endpoint: - continue - # The OTHER endpoint is missing a tag list attribute - ignore this here, we'll catch that when we assess this endpoint as the primary - if Clusters.Descriptor.Attributes.TagList not in endpoint_dict[other][Clusters.Descriptor]: - continue - - if sorted(endpoint_dict[endpoint][Clusters.Descriptor][Clusters.Descriptor.Attributes.TagList], key=functools.cmp_to_key(cmp_tag_list)) == sorted(endpoint_dict[other][Clusters.Descriptor][Clusters.Descriptor.Attributes.TagList], key=functools.cmp_to_key(cmp_tag_list)): - duplicate_tags.add(other) - if len(duplicate_tags) != 0: - duplicate_tags.add(endpoint) - tag_problems[endpoint] = TagProblem(root=root, missing_attribute=False, missing_feature=missing_feature, - duplicates=endpoints, same_tag=duplicate_tags) - continue - if missing_feature: - tag_problems[endpoint] = TagProblem(root=root, missing_attribute=False, - missing_feature=missing_feature, duplicates=endpoints) - - return tag_problems - - -class TC_DeviceBasicComposition(MatterBaseTest): +class TC_DeviceBasicComposition(MatterBaseTest, BasicCompositionTests): @async_test_body async def setup_class(self): super().setup_class() - dev_ctrl = self.default_controller - self.problems = [] - - do_test_over_pase = self.user_params.get("use_pase_only", True) - dump_device_composition_path: Optional[str] = self.user_params.get("dump_device_composition_path", None) - - if do_test_over_pase: - info = self.get_setup_payload_info() - - commissionable_nodes = dev_ctrl.DiscoverCommissionableNodes( - info.filter_type, info.filter_value, stopOnFirst=True, timeoutSecond=15) - logging.info(f"Commissionable nodes: {commissionable_nodes}") - # TODO: Support BLE - if commissionable_nodes is not None and len(commissionable_nodes) > 0: - commissionable_node = commissionable_nodes[0] - instance_name = f"{commissionable_node.instanceName}._matterc._udp.local" - vid = f"{commissionable_node.vendorId}" - pid = f"{commissionable_node.productId}" - address = f"{commissionable_node.addresses[0]}" - logging.info(f"Found instance {instance_name}, VID={vid}, PID={pid}, Address={address}") - - node_id = 1 - dev_ctrl.EstablishPASESessionIP(address, info.passcode, node_id) - else: - asserts.fail("Failed to find the DUT according to command line arguments.") - else: - # Using the already commissioned node - node_id = self.dut_node_id - - wildcard_read = (await dev_ctrl.Read(node_id, [()])) - endpoints_tlv = wildcard_read.tlvAttributes - - node_dump_dict = {endpoint_id: MatterTlvToJson(endpoints_tlv[endpoint_id]) for endpoint_id in endpoints_tlv} - logging.debug(f"Raw TLV contents of Node: {json.dumps(node_dump_dict, indent=2)}") - - if dump_device_composition_path is not None: - with open(pathlib.Path(dump_device_composition_path).with_suffix(".json"), "wt+") as outfile: - json.dump(node_dump_dict, outfile, indent=2) - with open(pathlib.Path(dump_device_composition_path).with_suffix(".txt"), "wt+") as outfile: - pprint(wildcard_read.attributes, outfile, indent=1, width=200, compact=True) - - logging.info("###########################################################") - logging.info("Start of actual tests") - logging.info("###########################################################") - - # ======= State kept for use by all tests ======= - - # All endpoints in "full object" indexing format - self.endpoints = wildcard_read.attributes - - # All endpoints in raw TLV format - self.endpoints_tlv = wildcard_read.tlvAttributes - - def get_test_name(self) -> str: - """Return the function name of the caller. Used to create logging entries.""" - return sys._getframe().f_back.f_code.co_name - - def fail_current_test(self, msg: Optional[str] = None): - if not msg: - # Without a message, just log the last problem seen - asserts.fail(msg=self.problems[-1].problem) - else: - asserts.fail(msg) + await self.setup_class_helper() # ======= START OF ACTUAL TESTS ======= def test_TC_SM_1_1(self): @@ -482,15 +178,17 @@ class RequiredMandatoryAttribute: validators: list[Callable] ATTRIBUTES_TO_CHECK = [ - RequiredMandatoryAttribute(id=CLUSTER_REVISION_ID, name="ClusterRevision", validators=[check_int_in_range(1, 0xFFFF)]), - RequiredMandatoryAttribute(id=FEATURE_MAP_ID, name="FeatureMap", validators=[check_int_in_range(0, 0xFFFF_FFFF)]), - RequiredMandatoryAttribute(id=ATTRIBUTE_LIST_ID, name="AttributeList", + RequiredMandatoryAttribute(id=GlobalAttributeIds.CLUSTER_REVISION_ID, name="ClusterRevision", + validators=[check_int_in_range(1, 0xFFFF)]), + RequiredMandatoryAttribute(id=GlobalAttributeIds.FEATURE_MAP_ID, name="FeatureMap", + validators=[check_int_in_range(0, 0xFFFF_FFFF)]), + RequiredMandatoryAttribute(id=GlobalAttributeIds.ATTRIBUTE_LIST_ID, name="AttributeList", validators=[check_non_empty_list_of_ints_in_range(0, 0xFFFF_FFFF), check_no_duplicates]), # TODO: Check for EventList # RequiredMandatoryAttribute(id=0xFFFA, name="EventList", validator=check_list_of_ints_in_range(0, 0xFFFF_FFFF)), - RequiredMandatoryAttribute(id=ACCEPTED_COMMAND_LIST_ID, name="AcceptedCommandList", + RequiredMandatoryAttribute(id=GlobalAttributeIds.ACCEPTED_COMMAND_LIST_ID, name="AcceptedCommandList", validators=[check_list_of_ints_in_range(0, 0xFFFF_FFFF), check_no_duplicates]), - RequiredMandatoryAttribute(id=GENERATED_COMMAND_LIST_ID, name="GeneratedCommandList", + RequiredMandatoryAttribute(id=GlobalAttributeIds.GENERATED_COMMAND_LIST_ID, name="GeneratedCommandList", validators=[check_list_of_ints_in_range(0, 0xFFFF_FFFF), check_no_duplicates]), ] @@ -532,7 +230,7 @@ class RequiredMandatoryAttribute: if success: for endpoint_id, endpoint in self.endpoints_tlv.items(): for cluster_id, cluster in endpoint.items(): - attribute_list = cluster[ATTRIBUTE_LIST_ID] + attribute_list = cluster[GlobalAttributeIds.ATTRIBUTE_LIST_ID] for attribute_id in attribute_list: location = AttributePathLocation(endpoint_id, cluster_id, attribute_id) has_attribute = attribute_id in cluster @@ -579,7 +277,7 @@ class RequiredMandatoryAttribute: mei_range_min = 0x0001_0000 for endpoint_id, endpoint in self.endpoints_tlv.items(): for cluster_id, cluster in endpoint.items(): - globals = [a for a in cluster[ATTRIBUTE_LIST_ID] if a >= global_range_min and a < mei_range_min] + globals = [a for a in cluster[GlobalAttributeIds.ATTRIBUTE_LIST_ID] if a >= global_range_min and a < mei_range_min] unexpected_globals = sorted(list(set(globals) - set(allowed_globals))) for unexpected in unexpected_globals: location = AttributePathLocation(endpoint_id=endpoint_id, cluster_id=cluster_id, attribute_id=unexpected) @@ -593,7 +291,8 @@ class RequiredMandatoryAttribute: if cluster_id not in chip.clusters.ClusterObjects.ALL_ATTRIBUTES: # Skip clusters that are not part of the standard generated corpus (e.g. MS clusters) continue - standard_attributes = [a for a in cluster[ATTRIBUTE_LIST_ID] if a <= attribute_standard_range_max] + standard_attributes = [a for a in cluster[GlobalAttributeIds.ATTRIBUTE_LIST_ID] + if a <= attribute_standard_range_max] allowed_standard_attributes = chip.clusters.ClusterObjects.ALL_ATTRIBUTES[cluster_id] unexpected_standard_attributes = sorted(list(set(standard_attributes) - set(allowed_standard_attributes))) for unexpected in unexpected_standard_attributes: @@ -606,7 +305,7 @@ class RequiredMandatoryAttribute: # This is de-facto already covered in the check above, assuming the spec hasn't defined any values in this range, but we should make sure for endpoint_id, endpoint in self.endpoints_tlv.items(): for cluster_id, cluster in endpoint.items(): - bad_range_values = [a for a in cluster[ATTRIBUTE_LIST_ID] if a > + bad_range_values = [a for a in cluster[GlobalAttributeIds.ATTRIBUTE_LIST_ID] if a > attribute_standard_range_max and a < global_range_min] for bad in bad_range_values: location = AttributePathLocation(endpoint_id=endpoint_id, cluster_id=cluster_id, attribute_id=bad) @@ -620,8 +319,10 @@ class RequiredMandatoryAttribute: for cluster_id, cluster in endpoint.items(): if cluster_id not in chip.clusters.ClusterObjects.ALL_CLUSTERS: continue - standard_accepted_commands = [a for a in cluster[ACCEPTED_COMMAND_LIST_ID] if a <= command_standard_range_max] - standard_generated_commands = [a for a in cluster[GENERATED_COMMAND_LIST_ID] if a <= command_standard_range_max] + standard_accepted_commands = [ + a for a in cluster[GlobalAttributeIds.ACCEPTED_COMMAND_LIST_ID] if a <= command_standard_range_max] + standard_generated_commands = [ + a for a in cluster[GlobalAttributeIds.GENERATED_COMMAND_LIST_ID] if a <= command_standard_range_max] if cluster_id in chip.clusters.ClusterObjects.ALL_ACCEPTED_COMMANDS: allowed_accepted_commands = [a for a in chip.clusters.ClusterObjects.ALL_ACCEPTED_COMMANDS[cluster_id]] else: @@ -658,8 +359,9 @@ class RequiredMandatoryAttribute: bad_prefix_min = 0xFFF1_0000 for endpoint_id, endpoint in self.endpoints_tlv.items(): for cluster_id, cluster in endpoint.items(): - attr_prefixes = [a & 0xFFFF_0000 for a in cluster[ATTRIBUTE_LIST_ID]] - cmd_values = cluster[ACCEPTED_COMMAND_LIST_ID] + cluster[GENERATED_COMMAND_LIST_ID] + attr_prefixes = [a & 0xFFFF_0000 for a in cluster[GlobalAttributeIds.ATTRIBUTE_LIST_ID]] + cmd_values = cluster[GlobalAttributeIds.ACCEPTED_COMMAND_LIST_ID] + \ + cluster[GlobalAttributeIds.GENERATED_COMMAND_LIST_ID] cmd_prefixes = [a & 0xFFFF_0000 for a in cmd_values] bad_attrs = [a for a in attr_prefixes if a >= bad_prefix_min] bad_cmds = [a for a in cmd_prefixes if a >= bad_prefix_min] @@ -679,7 +381,7 @@ class RequiredMandatoryAttribute: suffix_mask = 0x0000_FFFF for endpoint_id, endpoint in self.endpoints_tlv.items(): for cluster_id, cluster in endpoint.items(): - manufacturer_range_values = [a for a in cluster[ATTRIBUTE_LIST_ID] if a > mei_range_min] + manufacturer_range_values = [a for a in cluster[GlobalAttributeIds.ATTRIBUTE_LIST_ID] if a > mei_range_min] for manufacturer_value in manufacturer_range_values: suffix = manufacturer_value & suffix_mask location = AttributePathLocation(endpoint_id=endpoint_id, cluster_id=cluster_id, @@ -697,8 +399,10 @@ class RequiredMandatoryAttribute: for endpoint_id, endpoint in self.endpoints_tlv.items(): for cluster_id, cluster in endpoint.items(): - accepted_manufacturer_range_values = [a for a in cluster[ACCEPTED_COMMAND_LIST_ID] if a > mei_range_min] - generated_manufacturer_range_values = [a for a in cluster[GENERATED_COMMAND_LIST_ID] if a > mei_range_min] + accepted_manufacturer_range_values = [ + a for a in cluster[GlobalAttributeIds.ACCEPTED_COMMAND_LIST_ID] if a > mei_range_min] + generated_manufacturer_range_values = [ + a for a in cluster[GlobalAttributeIds.GENERATED_COMMAND_LIST_ID] if a > mei_range_min] all_command_manufacturer_range_values = accepted_manufacturer_range_values + generated_manufacturer_range_values for manufacturer_value in all_command_manufacturer_range_values: suffix = manufacturer_value & suffix_mask @@ -743,7 +447,7 @@ class RequiredMandatoryAttribute: for cluster_id, cluster in endpoint.items(): if cluster_id not in chip.clusters.ClusterObjects.ALL_CLUSTERS: continue - feature_map = cluster[FEATURE_MAP_ID] + feature_map = cluster[GlobalAttributeIds.FEATURE_MAP_ID] feature_mask = 0 try: feature_map_enum = chip.clusters.ClusterObjects.ALL_CLUSTERS[cluster_id].Bitmaps.Feature @@ -1045,14 +749,16 @@ def conformance_str(conformance: Callable, feature_map: uint, feature_dict: dict problem='Standard cluster found on device, but is not present in spec data') continue - feature_map = cluster[FEATURE_MAP_ID] - attribute_list = cluster[ATTRIBUTE_LIST_ID] - all_command_list = cluster[ACCEPTED_COMMAND_LIST_ID] + cluster[GENERATED_COMMAND_LIST_ID] + feature_map = cluster[GlobalAttributeIds.FEATURE_MAP_ID] + attribute_list = cluster[GlobalAttributeIds.ATTRIBUTE_LIST_ID] + all_command_list = cluster[GlobalAttributeIds.ACCEPTED_COMMAND_LIST_ID] + \ + cluster[GlobalAttributeIds.GENERATED_COMMAND_LIST_ID] # Feature conformance checking feature_masks = [1 << i for i in range(32) if feature_map & (1 << i)] for f in feature_masks: - location = AttributePathLocation(endpoint_id=endpoint_id, cluster_id=cluster_id, attribute_id=FEATURE_MAP_ID) + location = AttributePathLocation(endpoint_id=endpoint_id, cluster_id=cluster_id, + attribute_id=GlobalAttributeIds.FEATURE_MAP_ID) if f not in clusters[cluster_id].features.keys(): self.record_error(self.get_test_name(), location=location, problem=f'Unknown feature with mask 0x{f:02x}') success = False @@ -1102,7 +808,7 @@ def conformance_str(conformance: Callable, feature_map: uint, feature_dict: dict def check_spec_conformance_for_commands(command_type: CommandType) -> bool: success = True - global_attribute_id = ACCEPTED_COMMAND_LIST_ID if command_type == CommandType.ACCEPTED else GENERATED_COMMAND_LIST_ID + global_attribute_id = GlobalAttributeIds.ACCEPTED_COMMAND_LIST_ID if command_type == CommandType.ACCEPTED else GlobalAttributeIds.GENERATED_COMMAND_LIST_ID xml_commands_dict = clusters[cluster_id].accepted_commands if command_type == CommandType.ACCEPTED else clusters[cluster_id].generated_commands command_list = cluster[global_attribute_id] for command_id in command_list: diff --git a/src/python_testing/TestMatterTestingSupport.py b/src/python_testing/TestMatterTestingSupport.py index f69182ad6b5350..e713f4f0e71a61 100644 --- a/src/python_testing/TestMatterTestingSupport.py +++ b/src/python_testing/TestMatterTestingSupport.py @@ -25,9 +25,9 @@ from matter_testing_support import (MatterBaseTest, async_test_body, compare_time, default_matter_test_main, get_wait_seconds_from_set_time, parse_pics, type_matches, utc_time_in_matter_epoch) from mobly import asserts, signals -from TC_DeviceBasicComposition import (TagProblem, create_device_type_list_for_root, create_device_type_lists, - find_tag_list_problems, find_tree_roots, get_all_children, get_direct_children_of_root, - parts_list_cycles, separate_endpoint_types) +from taglist_and_topology_test_support import (TagProblem, create_device_type_list_for_root, create_device_type_lists, + find_tag_list_problems, find_tree_roots, get_all_children, + get_direct_children_of_root, parts_list_cycles, separate_endpoint_types) def get_raw_type_list(): diff --git a/src/python_testing/basic_composition_support.py b/src/python_testing/basic_composition_support.py new file mode 100644 index 00000000000000..523c41c223875d --- /dev/null +++ b/src/python_testing/basic_composition_support.py @@ -0,0 +1,163 @@ +# +# Copyright (c) 2023 Project CHIP Authors +# All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + + +import base64 +import copy +import json +import logging +import pathlib +import sys +from pprint import pprint +from typing import Any, Optional + +import chip.clusters.ClusterObjects +import chip.tlv +from chip.clusters.Attribute import ValueDecodeFailure +from mobly import asserts + + +def MatterTlvToJson(tlv_data: dict[int, Any]) -> dict[str, Any]: + """Given TLV data for a specific cluster instance, convert to the Matter JSON format.""" + + matter_json_dict = {} + + key_type_mappings = { + chip.tlv.uint: "UINT", + int: "INT", + bool: "BOOL", + list: "ARRAY", + dict: "STRUCT", + chip.tlv.float32: "FLOAT", + float: "DOUBLE", + bytes: "BYTES", + str: "STRING", + ValueDecodeFailure: "ERROR", + type(None): "NULL", + } + + def ConvertValue(value) -> Any: + if isinstance(value, ValueDecodeFailure): + raise ValueError(f"Bad Value: {str(value)}") + + if isinstance(value, bytes): + return base64.b64encode(value).decode("UTF-8") + elif isinstance(value, list): + value = [ConvertValue(item) for item in value] + elif isinstance(value, dict): + value = MatterTlvToJson(value) + + return value + + for key in tlv_data: + value_type = type(tlv_data[key]) + value = copy.deepcopy(tlv_data[key]) + + element_type: str = key_type_mappings[value_type] + sub_element_type = "" + + try: + new_value = ConvertValue(value) + except ValueError as e: + new_value = str(e) + + if element_type: + if element_type == "ARRAY": + if len(new_value): + sub_element_type = key_type_mappings[type(tlv_data[key][0])] + else: + sub_element_type = "?" + + new_key = "" + if element_type: + if sub_element_type: + new_key = f"{str(key)}:{element_type}-{sub_element_type}" + else: + new_key = f"{str(key)}:{element_type}" + else: + new_key = str(key) + + matter_json_dict[new_key] = new_value + + return matter_json_dict + + +class BasicCompositionTests: + async def setup_class_helper(self): + dev_ctrl = self.default_controller + self.problems = [] + + do_test_over_pase = self.user_params.get("use_pase_only", True) + dump_device_composition_path: Optional[str] = self.user_params.get("dump_device_composition_path", None) + + if do_test_over_pase: + info = self.get_setup_payload_info() + + commissionable_nodes = dev_ctrl.DiscoverCommissionableNodes( + info.filter_type, info.filter_value, stopOnFirst=True, timeoutSecond=15) + logging.info(f"Commissionable nodes: {commissionable_nodes}") + # TODO: Support BLE + if commissionable_nodes is not None and len(commissionable_nodes) > 0: + commissionable_node = commissionable_nodes[0] + instance_name = f"{commissionable_node.instanceName}._matterc._udp.local" + vid = f"{commissionable_node.vendorId}" + pid = f"{commissionable_node.productId}" + address = f"{commissionable_node.addresses[0]}" + logging.info(f"Found instance {instance_name}, VID={vid}, PID={pid}, Address={address}") + + node_id = 1 + dev_ctrl.EstablishPASESessionIP(address, info.passcode, node_id) + else: + asserts.fail("Failed to find the DUT according to command line arguments.") + else: + # Using the already commissioned node + node_id = self.dut_node_id + + wildcard_read = (await dev_ctrl.Read(node_id, [()])) + endpoints_tlv = wildcard_read.tlvAttributes + + node_dump_dict = {endpoint_id: MatterTlvToJson(endpoints_tlv[endpoint_id]) for endpoint_id in endpoints_tlv} + logging.debug(f"Raw TLV contents of Node: {json.dumps(node_dump_dict, indent=2)}") + + if dump_device_composition_path is not None: + with open(pathlib.Path(dump_device_composition_path).with_suffix(".json"), "wt+") as outfile: + json.dump(node_dump_dict, outfile, indent=2) + with open(pathlib.Path(dump_device_composition_path).with_suffix(".txt"), "wt+") as outfile: + pprint(wildcard_read.attributes, outfile, indent=1, width=200, compact=True) + + logging.info("###########################################################") + logging.info("Start of actual tests") + logging.info("###########################################################") + + # ======= State kept for use by all tests ======= + + # All endpoints in "full object" indexing format + self.endpoints = wildcard_read.attributes + + # All endpoints in raw TLV format + self.endpoints_tlv = wildcard_read.tlvAttributes + + def get_test_name(self) -> str: + """Return the function name of the caller. Used to create logging entries.""" + return sys._getframe().f_back.f_code.co_name + + def fail_current_test(self, msg: Optional[str] = None): + if not msg: + # Without a message, just log the last problem seen + asserts.fail(msg=self.problems[-1].problem) + else: + asserts.fail(msg) diff --git a/src/python_testing/global_attribute_ids.py b/src/python_testing/global_attribute_ids.py new file mode 100644 index 00000000000000..63d37952a00e2c --- /dev/null +++ b/src/python_testing/global_attribute_ids.py @@ -0,0 +1,28 @@ +# +# Copyright (c) 2023 Project CHIP Authors +# All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# This file should be removed once we have a good way to get this from the codegen or XML + +from enum import IntEnum + + +class GlobalAttributeIds(IntEnum): + ATTRIBUTE_LIST_ID = 0xFFFB + ACCEPTED_COMMAND_LIST_ID = 0xFFF9 + GENERATED_COMMAND_LIST_ID = 0xFFF8 + FEATURE_MAP_ID = 0xFFFC + CLUSTER_REVISION_ID = 0xFFFD diff --git a/src/python_testing/taglist_and_topology_test_support.py b/src/python_testing/taglist_and_topology_test_support.py new file mode 100644 index 00000000000000..af3bb05bea21b6 --- /dev/null +++ b/src/python_testing/taglist_and_topology_test_support.py @@ -0,0 +1,191 @@ +# +# Copyright (c) 2023 Project CHIP Authors +# All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +import functools +from collections import defaultdict +from dataclasses import dataclass, field +from typing import Any + +import chip.clusters as Clusters + + +@dataclass +class TagProblem: + root: int + missing_attribute: bool + missing_feature: bool + duplicates: set[int] + same_tag: set[int] = field(default_factory=set) + + +def separate_endpoint_types(endpoint_dict: dict[int, Any]) -> tuple[list[int], list[int]]: + """Returns a tuple containing the list of flat endpoints and a list of tree endpoints""" + flat = [] + tree = [] + for endpoint_id, endpoint in endpoint_dict.items(): + if endpoint_id == 0: + continue + aggregator_id = 0x000e + content_app_id = 0x0024 + device_types = [d.deviceType for d in endpoint[Clusters.Descriptor][Clusters.Descriptor.Attributes.DeviceTypeList]] + if aggregator_id in device_types: + flat.append(endpoint_id) + else: + if content_app_id in device_types: + continue + tree.append(endpoint_id) + return (flat, tree) + + +def get_all_children(endpoint_id, endpoint_dict: dict[int, Any]) -> set[int]: + """Returns all the children (include subchildren) of the given endpoint + This assumes we've already checked that there are no cycles, so we can do the dumb things and just trace the tree + """ + children = set() + + def add_children(endpoint_id, children): + immediate_children = endpoint_dict[endpoint_id][Clusters.Descriptor][Clusters.Descriptor.Attributes.PartsList] + if not immediate_children: + return + children.update(set(immediate_children)) + for child in immediate_children: + add_children(child, children) + + add_children(endpoint_id, children) + return children + + +def find_tree_roots(tree_endpoints: list[int], endpoint_dict: dict[int, Any]) -> set[int]: + """Returns a set of all the endpoints in tree_endpoints that are roots for a tree (not include singletons)""" + tree_roots = set() + + def find_tree_root(current_id): + for endpoint_id, endpoint in endpoint_dict.items(): + if endpoint_id not in tree_endpoints: + continue + if current_id in endpoint[Clusters.Descriptor][Clusters.Descriptor.Attributes.PartsList]: + # this is not the root, move up + return find_tree_root(endpoint_id) + return current_id + + for endpoint_id in tree_endpoints: + root = find_tree_root(endpoint_id) + if root != endpoint_id: + tree_roots.add(root) + return tree_roots + + +def parts_list_cycles(tree_endpoints: list[int], endpoint_dict: dict[int, Any]) -> list[int]: + """Returns a list of all the endpoints in the tree_endpoints list that contain cycles""" + def parts_list_cycle_detect(visited: set, current_id: int) -> bool: + if current_id in visited: + return True + visited.add(current_id) + for child in endpoint_dict[current_id][Clusters.Descriptor][Clusters.Descriptor.Attributes.PartsList]: + child_has_cycles = parts_list_cycle_detect(visited, child) + if child_has_cycles: + return True + return False + + cycles = [] + # This is quick enough that we can do all the endpoints without searching for the roots + for endpoint_id in tree_endpoints: + visited = set() + if parts_list_cycle_detect(visited, endpoint_id): + cycles.append(endpoint_id) + return cycles + + +def create_device_type_lists(roots: list[int], endpoint_dict: dict[int, Any]) -> dict[int, dict[int, set[int]]]: + """Returns a list of endpoints per device type for each root in the list""" + device_types = {} + for root in roots: + tree_device_types = defaultdict(set) + eps = get_all_children(root, endpoint_dict) + eps.add(root) + for ep in eps: + for d in endpoint_dict[ep][Clusters.Descriptor][Clusters.Descriptor.Attributes.DeviceTypeList]: + tree_device_types[d.deviceType].add(ep) + device_types[root] = tree_device_types + + return device_types + + +def get_direct_children_of_root(endpoint_dict: dict[int, Any]) -> set[int]: + root_children = set(endpoint_dict[0][Clusters.Descriptor][Clusters.Descriptor.Attributes.PartsList]) + direct_children = root_children + for ep in root_children: + ep_children = set(endpoint_dict[ep][Clusters.Descriptor][Clusters.Descriptor.Attributes.PartsList]) + direct_children = direct_children - ep_children + return direct_children + + +def create_device_type_list_for_root(direct_children, endpoint_dict: dict[int, Any]) -> dict[int, set[int]]: + device_types = defaultdict(set) + for ep in direct_children: + for d in endpoint_dict[ep][Clusters.Descriptor][Clusters.Descriptor.Attributes.DeviceTypeList]: + device_types[d.deviceType].add(ep) + return device_types + + +def cmp_tag_list(a: Clusters.Descriptor.Structs.SemanticTagStruct, b: Clusters.Descriptor.Structs.SemanticTagStruct): + if a.mfgCode != b.mfgCode: + return -1 if a.mfgCode < b.mfgCode else 1 + if a.namespaceID != b.namespaceID: + return -1 if a.namespaceID < b.namespaceID else 1 + if a.tag != b.tag: + return -1 if a.tag < b.tag else 1 + if a.label != b.label: + return -1 if a.label < b.label else 1 + return 0 + + +def find_tag_list_problems(roots: list[int], device_types: dict[int, dict[int, set[int]]], endpoint_dict: dict[int, Any]) -> dict[int, TagProblem]: + """Checks for non-spec compliant tag lists""" + tag_problems = {} + for root in roots: + for _, endpoints in device_types[root].items(): + if len(endpoints) < 2: + continue + for endpoint in endpoints: + missing_feature = not bool(endpoint_dict[endpoint][Clusters.Descriptor] + [Clusters.Descriptor.Attributes.FeatureMap] & Clusters.Descriptor.Bitmaps.Feature.kTagList) + if Clusters.Descriptor.Attributes.TagList not in endpoint_dict[endpoint][Clusters.Descriptor] or endpoint_dict[endpoint][Clusters.Descriptor][Clusters.Descriptor.Attributes.TagList] == []: + tag_problems[endpoint] = TagProblem(root=root, missing_attribute=True, + missing_feature=missing_feature, duplicates=endpoints) + continue + # Check that this tag isn't the same as the other tags in the endpoint list + duplicate_tags = set() + for other in endpoints: + if other == endpoint: + continue + # The OTHER endpoint is missing a tag list attribute - ignore this here, we'll catch that when we assess this endpoint as the primary + if Clusters.Descriptor.Attributes.TagList not in endpoint_dict[other][Clusters.Descriptor]: + continue + + if sorted(endpoint_dict[endpoint][Clusters.Descriptor][Clusters.Descriptor.Attributes.TagList], key=functools.cmp_to_key(cmp_tag_list)) == sorted(endpoint_dict[other][Clusters.Descriptor][Clusters.Descriptor.Attributes.TagList], key=functools.cmp_to_key(cmp_tag_list)): + duplicate_tags.add(other) + if len(duplicate_tags) != 0: + duplicate_tags.add(endpoint) + tag_problems[endpoint] = TagProblem(root=root, missing_attribute=False, missing_feature=missing_feature, + duplicates=endpoints, same_tag=duplicate_tags) + continue + if missing_feature: + tag_problems[endpoint] = TagProblem(root=root, missing_attribute=False, + missing_feature=missing_feature, duplicates=endpoints) + + return tag_problems From c44e241d305ae0c419d3dd82eabd6da375611ffc Mon Sep 17 00:00:00 2001 From: C Freeman Date: Tue, 7 Nov 2023 12:28:09 -0500 Subject: [PATCH 4/4] TC-1DM-10.3: Add (Cluster revision checks) (#30211) --- .../TC_DeviceBasicComposition.py | 28 +++++++++++++++++++ src/python_testing/spec_parsing_support.py | 6 +++- 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/src/python_testing/TC_DeviceBasicComposition.py b/src/python_testing/TC_DeviceBasicComposition.py index bb85b045923d06..87e55c1ace52f0 100644 --- a/src/python_testing/TC_DeviceBasicComposition.py +++ b/src/python_testing/TC_DeviceBasicComposition.py @@ -851,6 +851,34 @@ def check_spec_conformance_for_commands(command_type: CommandType) -> bool: # self.fail_current_test("Problems with conformance") logging.error("Problems found with conformance, this should turn into a test failure once #29812 is resolved") + def test_IDM_10_3(self): + # TODO: move to class setup + success = True + clusters, problems = build_xml_clusters() + self.problems = self.problems + problems + for endpoint_id, endpoint in self.endpoints_tlv.items(): + for cluster_id, cluster in endpoint.items(): + if cluster_id not in clusters.keys(): + if (cluster_id & 0xFFFF_0000) != 0: + # manufacturer cluster + continue + location = ClusterPathLocation(endpoint_id=endpoint_id, cluster_id=cluster_id) + # TODO: update this from a warning once we have all the data + self.record_warning(self.get_test_name(), location=location, + problem='Standard cluster found on device, but is not present in spec data') + continue + if int(clusters[cluster_id].revision) != cluster[CLUSTER_REVISION_ID]: + location = AttributePathLocation(endpoint_id=endpoint_id, cluster_id=cluster_id, + attribute_id=CLUSTER_REVISION_ID) + self.record_error(self.get_test_name( + ), location=location, problem=f'Revision found on cluster ({cluster[CLUSTER_REVISION_ID]}) does not match revision listed in the spec ({clusters[cluster_id].revision})') + success = False + if not success: + # TODO: Right now, we have failures in all-cluster, so we can't fail this test and keep it in CI. For now, just log. + # Issue tracking: #30210 + # self.fail_current_test("Problems with cluster revision on at least one cluster") + logging.error('Problems with cluster revision on at least one cluster') + if __name__ == "__main__": default_matter_test_main() diff --git a/src/python_testing/spec_parsing_support.py b/src/python_testing/spec_parsing_support.py index b59ef8379e9e63..9cf3cfa86a7307 100644 --- a/src/python_testing/spec_parsing_support.py +++ b/src/python_testing/spec_parsing_support.py @@ -246,7 +246,11 @@ def parse_events(self) -> dict[uint, XmlAttribute]: return events def create_cluster(self) -> XmlCluster: - return XmlCluster(revision=self._cluster.attrib['revision'], derived=self._derived, + try: + revision = int(self._cluster.attrib['revision'], 0) + except ValueError: + revision = 0 + return XmlCluster(revision=revision, derived=self._derived, name=self._name, feature_map=self.params.feature_map, attribute_map=self.params.attribute_map, command_map=self.params.command_map, features=self.parse_features(),