diff --git a/config/telink/chip-module/Kconfig b/config/telink/chip-module/Kconfig index 1148af804eee0b..b76e3962d2efbe 100644 --- a/config/telink/chip-module/Kconfig +++ b/config/telink/chip-module/Kconfig @@ -216,6 +216,10 @@ config CHIP_ENABLE_POWER_ON_FACTORY_RESET first 5 seconds after power on and this sequence repeated 5 times - factory reset will be involved. +config CHIP_TASK_STACK_SIZE + int + default 8192 + config CHIP_USE_MARS_SENSOR bool "Use Mars board sensor" depends on SOC_SERIES_RISCV_TELINK_B9X && (BOARD_TLSR9518ADK80D || BOARD_TLSR9518ADK80D_RETENTION) diff --git a/config/telink/chip-module/Kconfig.defaults b/config/telink/chip-module/Kconfig.defaults index c4ccd625b9cda7..0a71d5a53feaba 100644 --- a/config/telink/chip-module/Kconfig.defaults +++ b/config/telink/chip-module/Kconfig.defaults @@ -211,7 +211,7 @@ config SETTINGS_NVS_SECTOR_SIZE_MULT # Set sector counter of NVS config SETTINGS_NVS_SECTOR_COUNT - default 10 + default 12 # Enable OpenThread @@ -329,4 +329,7 @@ config PWM_SHELL config OPENTHREAD_SHELL default n +config CHIP_TASK_STACK_SIZE + default 4864 if PM + endif diff --git a/examples/air-purifier-app/air-purifier-common/README.md b/examples/air-purifier-app/air-purifier-common/README.md new file mode 100644 index 00000000000000..2ed26cacf9a229 --- /dev/null +++ b/examples/air-purifier-app/air-purifier-common/README.md @@ -0,0 +1,353 @@ +# CHIP Air Purifier Example + +This example implements the following PICS: + +``` +# Fan Control +FAN.S=1 +FAN.C=0 +FAN.S.F00=1 +FAN.S.F01=1 +FAN.S.F02=1 +FAN.S.F03=1 +FAN.S.F04=1 +FAN.S.F05=1 +FAN.S.A0000=1 +FAN.S.A0001=1 +FAN.S.A0002=1 +FAN.S.A0003=1 +FAN.S.A0004=1 +FAN.S.A0005=1 +FAN.S.A0006=1 +FAN.S.A0007=1 +FAN.S.A0008=1 +FAN.S.A0009=1 +FAN.S.A000A=1 +FAN.S.A000B=1 +FAN.S.C00.Rsp=1 + +# HEPA Filter Monitoring Cluster +HEPAFREMON.S=1 +HEPAFREMON.C=0 +HEPAFREMON.S.F00=1 +HEPAFREMON.S.F01=1 +HEPAFREMON.S.F02=1 +HEPAFREMON.S.A0000=1 +HEPAFREMON.S.A0001=1 +HEPAFREMON.S.A0002=1 +HEPAFREMON.S.A0003=1 +HEPAFREMON.S.A0004=1 +HEPAFREMON.S.A0005=1 +HEPAFREMON.S.C00.Rsp=1 + +# Activated Carbon Filter Monitoring Cluster +ACFREMON.S=1 +ACFREMON.C=0 +ACFREMON.S.F00=1 +ACFREMON.S.F01=1 +ACFREMON.S.F02=1 +ACFREMON.S.A0000=1 +ACFREMON.S.A0001=1 +ACFREMON.S.A0002=1 +ACFREMON.S.A0003=1 +ACFREMON.S.A0004=1 +ACFREMON.S.A0005=1 +ACFREMON.S.C00.Rsp=1 + +# Air Quality Cluster +AIRQUAL.C=0 +AIRQUAL.S=1 +AIRQUAL.S.F00=1 +AIRQUAL.S.F01=1 +AIRQUAL.S.F02=1 +AIRQUAL.S.F03=1 +AIRQUAL.S.A0000=1 +AIRQUAL.M.AirQualityChange=0 + +# Concentration Measurement CLusters +CDOCONC.C=0 +CDOCONC.S=1 +CDOCONC.S.F00=1 +CDOCONC.S.F01=1 +CDOCONC.S.F02=1 +CDOCONC.S.F03=1 +CDOCONC.S.F04=1 +CDOCONC.S.F05=1 +CDOCONC.S.A0000=1 +CDOCONC.S.A0001=1 +CDOCONC.S.A0002=1 +CDOCONC.S.A0003=1 +CDOCONC.S.A0004=1 +CDOCONC.S.A0005=1 +CDOCONC.S.A0006=1 +CDOCONC.S.A0007=1 +CDOCONC.S.A0008=1 +CDOCONC.S.A0009=1 +CDOCONC.S.A000a=1 + +CMOCONC.C=0 +CMOCONC.S=1 +CMOCONC.S.F00=1 +CMOCONC.S.F01=1 +CMOCONC.S.F02=1 +CMOCONC.S.F03=1 +CMOCONC.S.F04=1 +CMOCONC.S.F05=1 +CMOCONC.S.A0000=1 +CMOCONC.S.A0001=1 +CMOCONC.S.A0002=1 +CMOCONC.S.A0003=1 +CMOCONC.S.A0004=1 +CMOCONC.S.A0005=1 +CMOCONC.S.A0006=1 +CMOCONC.S.A0007=1 +CMOCONC.S.A0008=1 +CMOCONC.S.A0009=1 +CMOCONC.S.A000a=1 + +NDOCONC.C=0 +NDOCONC.S=1 +NDOCONC.S.F00=1 +NDOCONC.S.F01=1 +NDOCONC.S.F02=1 +NDOCONC.S.F03=1 +NDOCONC.S.F04=1 +NDOCONC.S.F05=1 +NDOCONC.S.A0000=1 +NDOCONC.S.A0001=1 +NDOCONC.S.A0002=1 +NDOCONC.S.A0003=1 +NDOCONC.S.A0004=1 +NDOCONC.S.A0005=1 +NDOCONC.S.A0006=1 +NDOCONC.S.A0007=1 +NDOCONC.S.A0008=1 +NDOCONC.S.A0009=1 +NDOCONC.S.A000a=1 + +OZCONC.C=0 +OZCONC.S=1 +OZCONC.S.F00=1 +OZCONC.S.F01=1 +OZCONC.S.F02=1 +OZCONC.S.F03=1 +OZCONC.S.F04=1 +OZCONC.S.F05=1 +OZCONC.S.A0000=1 +OZCONC.S.A0001=1 +OZCONC.S.A0002=1 +OZCONC.S.A0003=1 +OZCONC.S.A0004=1 +OZCONC.S.A0005=1 +OZCONC.S.A0006=1 +OZCONC.S.A0007=1 +OZCONC.S.A0008=1 +OZCONC.S.A0009=1 +OZCONC.S.A000a=1 + +PMICONC.C=0 +PMICONC.S=1 +PMICONC.S.F00=1 +PMICONC.S.F01=1 +PMICONC.S.F02=1 +PMICONC.S.F03=1 +PMICONC.S.F04=1 +PMICONC.S.F05=1 +PMICONC.S.A0000=1 +PMICONC.S.A0001=1 +PMICONC.S.A0002=1 +PMICONC.S.A0003=1 +PMICONC.S.A0004=1 +PMICONC.S.A0005=1 +PMICONC.S.A0006=1 +PMICONC.S.A0007=1 +PMICONC.S.A0008=1 +PMICONC.S.A0009=1 +PMICONC.S.A000a=1 + +FLDCONC.C=0 +FLDCONC.S=1 +FLDCONC.S.F00=1 +FLDCONC.S.F01=1 +FLDCONC.S.F02=1 +FLDCONC.S.F03=1 +FLDCONC.S.F04=1 +FLDCONC.S.F05=1 +FLDCONC.S.A0000=1 +FLDCONC.S.A0001=1 +FLDCONC.S.A0002=1 +FLDCONC.S.A0003=1 +FLDCONC.S.A0004=1 +FLDCONC.S.A0005=1 +FLDCONC.S.A0006=1 +FLDCONC.S.A0007=1 +FLDCONC.S.A0008=1 +FLDCONC.S.A0009=1 +FLDCONC.S.A000a=1 + +PMHCONC.C=0 +PMHCONC.S=1 +PMHCONC.S.F00=1 +PMHCONC.S.F01=1 +PMHCONC.S.F02=1 +PMHCONC.S.F03=1 +PMHCONC.S.F04=1 +PMHCONC.S.F05=1 +PMHCONC.S.A0000=1 +PMHCONC.S.A0001=1 +PMHCONC.S.A0002=1 +PMHCONC.S.A0003=1 +PMHCONC.S.A0004=1 +PMHCONC.S.A0005=1 +PMHCONC.S.A0006=1 +PMHCONC.S.A0007=1 +PMHCONC.S.A0008=1 +PMHCONC.S.A0009=1 +PMHCONC.S.A000a=1 + +PMKCONC.C=0 +PMKCONC.S=1 +PMKCONC.S.F00=1 +PMKCONC.S.F01=1 +PMKCONC.S.F02=1 +PMKCONC.S.F03=1 +PMKCONC.S.F04=1 +PMKCONC.S.F05=1 +PMKCONC.S.A0000=1 +PMKCONC.S.A0001=1 +PMKCONC.S.A0002=1 +PMKCONC.S.A0003=1 +PMKCONC.S.A0004=1 +PMKCONC.S.A0005=1 +PMKCONC.S.A0006=1 +PMKCONC.S.A0007=1 +PMKCONC.S.A0008=1 +PMKCONC.S.A0009=1 +PMKCONC.S.A000a=1 + +TVOCCONC.C=0 +TVOCCONC.S=1 +TVOCCONC.S.F00=1 +TVOCCONC.S.F01=1 +TVOCCONC.S.F02=1 +TVOCCONC.S.F03=1 +TVOCCONC.S.F04=1 +TVOCCONC.S.F05=1 +TVOCCONC.S.A0000=1 +TVOCCONC.S.A0001=1 +TVOCCONC.S.A0002=1 +TVOCCONC.S.A0003=1 +TVOCCONC.S.A0004=1 +TVOCCONC.S.A0005=1 +TVOCCONC.S.A0006=1 +TVOCCONC.S.A0007=1 +TVOCCONC.S.A0008=1 +TVOCCONC.S.A0009=1 +TVOCCONC.S.A000a=1 + +RNCONC.C=0 +RNCONC.S=1 +RNCONC.S.F00=1 +RNCONC.S.F01=1 +RNCONC.S.F02=1 +RNCONC.S.F03=1 +RNCONC.S.F04=1 +RNCONC.S.F05=1 +RNCONC.S.A0000=1 +RNCONC.S.A0001=1 +RNCONC.S.A0002=1 +RNCONC.S.A0003=1 +RNCONC.S.A0004=1 +RNCONC.S.A0005=1 +RNCONC.S.A0006=1 +RNCONC.S.A0007=1 +RNCONC.S.A0008=1 +RNCONC.S.A0009=1 +RNCONC.S.A000a=1 + +# Temperature Measurement Cluster +TMP.S=1 +TMP.S.A0000=1 +TMP.S.A0001=1 +TMP.S.A0002=1 +TMP.S.A0003=1 +TMP.M.ManuallyControlled=0 + +# Relative Humidity Cluster +RH.S=1 +RH.S.A0000=1 +RH.S.A0001=1 +RH.S.A0002=1 +RH.S.A0003=1 +RH.M.ManuallyControlled=0 + +# Thermostat Cluster +TSTAT.S = 1 +TSTAT.S.F00 = 1 +TSTAT.S.F01 = 0 +TSTAT.S.F02 = 0 +TSTAT.S.F03 = 0 +TSTAT.S.F04 = 0 +TSTAT.S.F05 = 0 +TSTAT.S.F06 = 0 + +TSTAT.S.A0000 = 1 +TSTAT.S.A0001 = 0 +TSTAT.S.A0002 = 0 +TSTAT.S.A0003 = 1 +TSTAT.S.A0004 = 1 +TSTAT.S.A0005 = 0 +TSTAT.S.A0006 = 0 +TSTAT.S.A0007 = 0 +TSTAT.S.A0008 = 0 +TSTAT.S.A0009 = 0 +TSTAT.S.A0010 = 0 +TSTAT.S.A0011 = 0 +TSTAT.S.A0012 = 1 +TSTAT.S.A0013 = 0 +TSTAT.S.A0014 = 0 +TSTAT.S.A0015 = 0 +TSTAT.S.A0016 = 0 +TSTAT.S.A0017 = 0 +TSTAT.S.A0018 = 0 +TSTAT.S.A0019 = 0 +TSTAT.S.A001a = 0 +TSTAT.S.A001b = 1 +TSTAT.S.A001c = 1 +TSTAT.S.A001d = 0 +TSTAT.S.A001e = 0 +TSTAT.S.A0020 = 0 +TSTAT.S.A0021 = 0 +TSTAT.S.A0022 = 0 +TSTAT.S.A0023 = 0 +TSTAT.S.A0024 = 0 +TSTAT.S.A0025 = 0 +TSTAT.S.A0029 = 1 +TSTAT.S.A0030 = 0 +TSTAT.S.A0031 = 0 +TSTAT.S.A0032 = 0 +TSTAT.S.A0034 = 0 +TSTAT.S.A0035 = 0 +TSTAT.S.A0036 = 0 +TSTAT.S.A0037 = 0 +TSTAT.S.A0038 = 0 +TSTAT.S.A0039 = 0 +TSTAT.S.A003a = 0 +TSTAT.S.A0040 = 0 +TSTAT.S.A0041 = 0 +TSTAT.S.A0042 = 0 +TSTAT.S.A0043 = 0 +TSTAT.S.A0044 = 0 +TSTAT.S.A0045 = 0 +TSTAT.S.A0046 = 0 +TSTAT.S.A0047 = 0 +TSTAT.S.M.MinSetpointDeadBandWritable = 0 +TSTAT.S.M.HVACSystemTypeConfigurationWritable = 0 + +# Server Commands +TSTAT.S.C00.Rsp = 1 +TSTAT.S.C01.Rsp = 0 +TSTAT.S.C02.Rsp = 0 +TSTAT.S.C03.Rsp = 0 +TSTAT.S.C04.Rsp = 0 +``` 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 33de78383c41fc..ac6dc5a4c04dec 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 @@ -1207,6 +1207,377 @@ cluster ActivatedCarbonFilterMonitoring = 114 { command ResetCondition(): DefaultSuccess = 0; } +/** An interface for configuring and controlling the functionality of a thermostat. */ +cluster Thermostat = 513 { + revision 6; + + enum ACCapacityFormatEnum : enum8 { + kBTUh = 0; + } + + enum ACCompressorTypeEnum : enum8 { + kUnknown = 0; + kT1 = 1; + kT2 = 2; + kT3 = 3; + } + + enum ACLouverPositionEnum : enum8 { + kClosed = 1; + kOpen = 2; + kQuarter = 3; + kHalf = 4; + kThreeQuarters = 5; + } + + enum ACRefrigerantTypeEnum : enum8 { + kUnknown = 0; + kR22 = 1; + kR410a = 2; + kR407c = 3; + } + + enum ACTypeEnum : enum8 { + kUnknown = 0; + kCoolingFixed = 1; + kHeatPumpFixed = 2; + kCoolingInverter = 3; + kHeatPumpInverter = 4; + } + + enum ControlSequenceOfOperationEnum : enum8 { + kCoolingOnly = 0; + kCoolingWithReheat = 1; + kHeatingOnly = 2; + kHeatingWithReheat = 3; + kCoolingAndHeating = 4; + kCoolingAndHeatingWithReheat = 5; + } + + enum PresetScenarioEnum : enum8 { + kUnspecified = 0; + kOccupied = 1; + kUnoccupied = 2; + kSleep = 3; + kWake = 4; + kVacation = 5; + kUserDefined = 6; + } + + enum SetpointChangeSourceEnum : enum8 { + kManual = 0; + kSchedule = 1; + kExternal = 2; + } + + enum SetpointRaiseLowerModeEnum : enum8 { + kHeat = 0; + kCool = 1; + kBoth = 2; + } + + enum StartOfWeekEnum : enum8 { + kSunday = 0; + kMonday = 1; + kTuesday = 2; + kWednesday = 3; + kThursday = 4; + kFriday = 5; + kSaturday = 6; + } + + enum SystemModeEnum : enum8 { + kOff = 0; + kAuto = 1; + kCool = 3; + kHeat = 4; + kEmergencyHeat = 5; + kPrecooling = 6; + kFanOnly = 7; + kDry = 8; + kSleep = 9; + } + + enum TemperatureSetpointHoldEnum : enum8 { + kSetpointHoldOff = 0; + kSetpointHoldOn = 1; + } + + enum ThermostatRunningModeEnum : enum8 { + kOff = 0; + kCool = 3; + kHeat = 4; + } + + bitmap ACErrorCodeBitmap : bitmap32 { + kCompressorFail = 0x1; + kRoomSensorFail = 0x2; + kOutdoorSensorFail = 0x4; + kCoilSensorFail = 0x8; + kFanFail = 0x10; + } + + bitmap Feature : bitmap32 { + kHeating = 0x1; + kCooling = 0x2; + kOccupancy = 0x4; + kScheduleConfiguration = 0x8; + kSetback = 0x10; + kAutoMode = 0x20; + kLocalTemperatureNotExposed = 0x40; + kMatterScheduleConfiguration = 0x80; + kPresets = 0x100; + kSetpoints = 0x200; + kQueuedPresetsSupported = 0x400; + } + + bitmap HVACSystemTypeBitmap : bitmap8 { + kCoolingStage = 0x3; + kHeatingStage = 0xC; + kHeatingIsHeatPump = 0x10; + kHeatingUsesFuel = 0x20; + } + + bitmap PresetTypeFeaturesBitmap : bitmap16 { + kAutomatic = 0x1; + kSupportsNames = 0x2; + } + + bitmap ProgrammingOperationModeBitmap : bitmap8 { + kScheduleActive = 0x1; + kAutoRecovery = 0x2; + kEconomy = 0x4; + } + + bitmap RelayStateBitmap : bitmap16 { + kHeat = 0x1; + kCool = 0x2; + kFan = 0x4; + kHeatStage2 = 0x8; + kCoolStage2 = 0x10; + kFanStage2 = 0x20; + kFanStage3 = 0x40; + } + + bitmap RemoteSensingBitmap : bitmap8 { + kLocalTemperature = 0x1; + kOutdoorTemperature = 0x2; + kOccupancy = 0x4; + } + + bitmap ScheduleDayOfWeekBitmap : bitmap8 { + kSunday = 0x1; + kMonday = 0x2; + kTuesday = 0x4; + kWednesday = 0x8; + kThursday = 0x10; + kFriday = 0x20; + kSaturday = 0x40; + kAway = 0x80; + } + + bitmap ScheduleModeBitmap : bitmap8 { + kHeatSetpointPresent = 0x1; + kCoolSetpointPresent = 0x2; + } + + bitmap ScheduleTypeFeaturesBitmap : bitmap16 { + kSupportsPresets = 0x1; + kSupportsSetpoints = 0x2; + kSupportsNames = 0x4; + kSupportsOff = 0x8; + } + + bitmap TemperatureSetpointHoldPolicyBitmap : bitmap8 { + kHoldDurationElapsed = 0x1; + kHoldDurationElapsedOrPresetChanged = 0x2; + } + + struct ScheduleTransitionStruct { + ScheduleDayOfWeekBitmap dayOfWeek = 0; + int16u transitionTime = 1; + optional octet_string<16> presetHandle = 2; + optional SystemModeEnum systemMode = 3; + optional temperature coolingSetpoint = 4; + optional temperature heatingSetpoint = 5; + } + + struct ScheduleStruct { + nullable octet_string<16> scheduleHandle = 0; + SystemModeEnum systemMode = 1; + optional char_string<64> name = 2; + optional octet_string<16> presetHandle = 3; + ScheduleTransitionStruct transitions[] = 4; + optional nullable boolean builtIn = 5; + } + + struct PresetStruct { + nullable octet_string<16> presetHandle = 0; + PresetScenarioEnum presetScenario = 1; + optional nullable char_string<64> name = 2; + optional temperature coolingSetpoint = 3; + optional temperature heatingSetpoint = 4; + nullable boolean builtIn = 5; + } + + struct PresetTypeStruct { + PresetScenarioEnum presetScenario = 0; + int8u numberOfPresets = 1; + PresetTypeFeaturesBitmap presetTypeFeatures = 2; + } + + struct QueuedPresetStruct { + nullable octet_string<16> presetHandle = 0; + nullable epoch_s transitionTimestamp = 1; + } + + struct ScheduleTypeStruct { + SystemModeEnum systemMode = 0; + int8u numberOfSchedules = 1; + ScheduleTypeFeaturesBitmap scheduleTypeFeatures = 2; + } + + struct WeeklyScheduleTransitionStruct { + int16u transitionTime = 0; + nullable temperature heatSetpoint = 1; + nullable temperature coolSetpoint = 2; + } + + readonly attribute nullable temperature localTemperature = 0; + readonly attribute optional nullable temperature outdoorTemperature = 1; + readonly attribute optional bitmap8 occupancy = 2; + readonly attribute optional temperature absMinHeatSetpointLimit = 3; + readonly attribute optional temperature absMaxHeatSetpointLimit = 4; + readonly attribute optional temperature absMinCoolSetpointLimit = 5; + readonly attribute optional temperature absMaxCoolSetpointLimit = 6; + readonly attribute optional int8u PICoolingDemand = 7; + readonly attribute optional int8u PIHeatingDemand = 8; + attribute access(write: manage) optional bitmap8 HVACSystemTypeConfiguration = 9; + attribute access(write: manage) optional int8s localTemperatureCalibration = 16; + attribute optional int16s occupiedCoolingSetpoint = 17; + attribute optional int16s occupiedHeatingSetpoint = 18; + attribute optional int16s unoccupiedCoolingSetpoint = 19; + attribute optional int16s unoccupiedHeatingSetpoint = 20; + attribute access(write: manage) optional int16s minHeatSetpointLimit = 21; + attribute access(write: manage) optional int16s maxHeatSetpointLimit = 22; + attribute access(write: manage) optional int16s minCoolSetpointLimit = 23; + attribute access(write: manage) optional int16s maxCoolSetpointLimit = 24; + attribute access(write: manage) optional int8s minSetpointDeadBand = 25; + attribute access(write: manage) optional RemoteSensingBitmap remoteSensing = 26; + attribute access(write: manage) ControlSequenceOfOperationEnum controlSequenceOfOperation = 27; + attribute access(write: manage) SystemModeEnum systemMode = 28; + readonly attribute optional ThermostatRunningModeEnum thermostatRunningMode = 30; + readonly attribute optional StartOfWeekEnum startOfWeek = 32; + readonly attribute optional int8u numberOfWeeklyTransitions = 33; + readonly attribute optional int8u numberOfDailyTransitions = 34; + attribute access(write: manage) optional TemperatureSetpointHoldEnum temperatureSetpointHold = 35; + attribute access(write: manage) optional nullable int16u temperatureSetpointHoldDuration = 36; + attribute access(write: manage) optional ProgrammingOperationModeBitmap thermostatProgrammingOperationMode = 37; + readonly attribute optional RelayStateBitmap thermostatRunningState = 41; + readonly attribute optional SetpointChangeSourceEnum setpointChangeSource = 48; + readonly attribute optional nullable int16s setpointChangeAmount = 49; + readonly attribute optional epoch_s setpointChangeSourceTimestamp = 50; + attribute access(write: manage) optional nullable int8u occupiedSetback = 52; + readonly attribute optional nullable int8u occupiedSetbackMin = 53; + readonly attribute optional nullable int8u occupiedSetbackMax = 54; + attribute access(write: manage) optional nullable int8u unoccupiedSetback = 55; + readonly attribute optional nullable int8u unoccupiedSetbackMin = 56; + readonly attribute optional nullable int8u unoccupiedSetbackMax = 57; + attribute access(write: manage) optional int8u emergencyHeatDelta = 58; + attribute access(write: manage) optional ACTypeEnum ACType = 64; + attribute access(write: manage) optional int16u ACCapacity = 65; + attribute access(write: manage) optional ACRefrigerantTypeEnum ACRefrigerantType = 66; + attribute access(write: manage) optional ACCompressorTypeEnum ACCompressorType = 67; + attribute access(write: manage) optional ACErrorCodeBitmap ACErrorCode = 68; + attribute access(write: manage) optional ACLouverPositionEnum ACLouverPosition = 69; + readonly attribute optional nullable temperature ACCoilTemperature = 70; + attribute access(write: manage) optional ACCapacityFormatEnum ACCapacityformat = 71; + readonly attribute optional PresetTypeStruct presetTypes[] = 72; + readonly attribute optional ScheduleTypeStruct scheduleTypes[] = 73; + readonly attribute optional int8u numberOfPresets = 74; + readonly attribute optional int8u numberOfSchedules = 75; + readonly attribute optional int8u numberOfScheduleTransitions = 76; + readonly attribute optional nullable int8u numberOfScheduleTransitionPerDay = 77; + readonly attribute optional nullable octet_string<16> activePresetHandle = 78; + readonly attribute optional nullable octet_string<16> activeScheduleHandle = 79; + attribute access(write: manage) optional PresetStruct presets[] = 80; + attribute access(write: manage) optional ScheduleStruct schedules[] = 81; + readonly attribute optional boolean presetsSchedulesEditable = 82; + readonly attribute optional TemperatureSetpointHoldPolicyBitmap temperatureSetpointHoldPolicy = 83; + readonly attribute optional nullable epoch_s setpointHoldExpiryTimestamp = 84; + readonly attribute optional nullable QueuedPresetStruct queuedPreset = 85; + readonly attribute command_id generatedCommandList[] = 65528; + readonly attribute command_id acceptedCommandList[] = 65529; + readonly attribute event_id eventList[] = 65530; + readonly attribute attrib_id attributeList[] = 65531; + readonly attribute bitmap32 featureMap = 65532; + readonly attribute int16u clusterRevision = 65533; + + request struct SetpointRaiseLowerRequest { + SetpointRaiseLowerModeEnum mode = 0; + int8s amount = 1; + } + + response struct GetWeeklyScheduleResponse = 0 { + int8u numberOfTransitionsForSequence = 0; + ScheduleDayOfWeekBitmap dayOfWeekForSequence = 1; + ScheduleModeBitmap modeForSequence = 2; + WeeklyScheduleTransitionStruct transitions[] = 3; + } + + request struct SetWeeklyScheduleRequest { + int8u numberOfTransitionsForSequence = 0; + ScheduleDayOfWeekBitmap dayOfWeekForSequence = 1; + ScheduleModeBitmap modeForSequence = 2; + WeeklyScheduleTransitionStruct transitions[] = 3; + } + + request struct GetWeeklyScheduleRequest { + ScheduleDayOfWeekBitmap daysToReturn = 0; + ScheduleModeBitmap modeToReturn = 1; + } + + request struct SetActiveScheduleRequestRequest { + octet_string<16> scheduleHandle = 0; + } + + request struct SetActivePresetRequestRequest { + octet_string<16> presetHandle = 0; + optional int16u delayMinutes = 1; + } + + request struct StartPresetsSchedulesEditRequestRequest { + int16u timeoutSeconds = 0; + } + + request struct SetTemperatureSetpointHoldPolicyRequest { + TemperatureSetpointHoldPolicyBitmap temperatureSetpointHoldPolicy = 0; + } + + /** Command description for SetpointRaiseLower */ + command SetpointRaiseLower(SetpointRaiseLowerRequest): DefaultSuccess = 0; + /** Command description for SetWeeklySchedule */ + command access(invoke: manage) SetWeeklySchedule(SetWeeklyScheduleRequest): DefaultSuccess = 1; + /** Command description for GetWeeklySchedule */ + command GetWeeklySchedule(GetWeeklyScheduleRequest): GetWeeklyScheduleResponse = 2; + /** This command is used to clear the weekly schedule. The ClearWeeklySchedule command has no payload. */ + command access(invoke: manage) ClearWeeklySchedule(): DefaultSuccess = 3; + /** This command is used to set the active schedule. */ + command SetActiveScheduleRequest(SetActiveScheduleRequestRequest): DefaultSuccess = 5; + /** This command is used to set the active preset. */ + command SetActivePresetRequest(SetActivePresetRequestRequest): DefaultSuccess = 6; + /** This command is used to start editing the presets and schedules. */ + command access(invoke: manage) StartPresetsSchedulesEditRequest(StartPresetsSchedulesEditRequestRequest): DefaultSuccess = 7; + /** This command is used to cancel editing presets and schedules. */ + command access(invoke: manage) CancelPresetsSchedulesEditRequest(): DefaultSuccess = 8; + /** This command is used to notify the server that all edits are done and should be committed. */ + command access(invoke: manage) CommitPresetsSchedulesRequest(): DefaultSuccess = 9; + /** This command is sent to cancel a queued preset. */ + command access(invoke: manage) CancelSetActivePresetRequest(): DefaultSuccess = 10; + /** This command sets the set point hold policy. */ + command SetTemperatureSetpointHoldPolicy(SetTemperatureSetpointHoldPolicyRequest): DefaultSuccess = 11; +} + /** An interface for controlling a fan in a heating/cooling system. */ provisional cluster FanControl = 514 { revision 4; @@ -2407,7 +2778,7 @@ endpoint 2 { } } endpoint 3 { - device type ma_tempsensor = 770, version 1; + device type ma_tempsensor = 770, version 2; server cluster Identify { @@ -2451,7 +2822,7 @@ endpoint 3 { } } endpoint 4 { - device type ma_humiditysensor = 775, version 1; + device type ma_humiditysensor = 775, version 2; server cluster Identify { @@ -2494,5 +2865,54 @@ endpoint 4 { ram attribute clusterRevision default = 3; } } +endpoint 5 { + device type ma_thermostat = 769, version 2; + + + server cluster Identify { + ram attribute identifyTime default = 0x0; + ram attribute identifyType default = 0x00; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute eventList; + callback attribute attributeList; + ram attribute featureMap default = 0; + ram attribute clusterRevision default = 4; + + handle command Identify; + handle command TriggerEffect; + } + + server cluster Descriptor { + callback attribute deviceTypeList; + callback attribute serverList; + callback attribute clientList; + callback attribute partsList; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute eventList; + callback attribute attributeList; + callback attribute featureMap; + callback attribute clusterRevision; + } + + server cluster Thermostat { + ram attribute localTemperature; + ram attribute absMinHeatSetpointLimit default = 1000; + ram attribute absMaxHeatSetpointLimit default = 3000; + ram attribute occupiedHeatingSetpoint default = 2000; + ram attribute controlSequenceOfOperation default = 2; + ram attribute systemMode default = 0; + ram attribute thermostatRunningState default = 0; + callback attribute generatedCommandList; + callback attribute acceptedCommandList; + callback attribute eventList; + callback attribute attributeList; + ram attribute featureMap default = 1; + ram attribute clusterRevision default = 6; + + handle command SetpointRaiseLower; + } +} diff --git a/examples/air-purifier-app/air-purifier-common/air-purifier-app.zap b/examples/air-purifier-app/air-purifier-common/air-purifier-app.zap index d71c47a6d98758..b868916264f4ba 100644 --- a/examples/air-purifier-app/air-purifier-common/air-purifier-app.zap +++ b/examples/air-purifier-app/air-purifier-common/air-purifier-app.zap @@ -6514,7 +6514,7 @@ } ], "deviceVersions": [ - 1 + 2 ], "deviceIdentifiers": [ 770 @@ -7039,7 +7039,7 @@ } ], "deviceVersions": [ - 1 + 2 ], "deviceIdentifiers": [ 775 @@ -7545,43 +7545,634 @@ ] } ] - } - ], - "endpoints": [ - { - "endpointTypeName": "MA-rootdevice", - "endpointTypeIndex": 0, - "profileId": 259, - "endpointId": 0, - "networkId": 0 - }, - { - "endpointTypeName": "Anonymous Endpoint Type", - "endpointTypeIndex": 1, - "profileId": 259, - "endpointId": 1, - "networkId": 0 - }, - { - "endpointTypeName": "Anonymous Endpoint Type", - "endpointTypeIndex": 2, - "profileId": 259, - "endpointId": 2, - "networkId": 0 - }, - { - "endpointTypeName": "Anonymous Endpoint Type", - "endpointTypeIndex": 3, - "profileId": 259, - "endpointId": 3, - "networkId": 0 }, { - "endpointTypeName": "Anonymous Endpoint Type", - "endpointTypeIndex": 4, - "profileId": 259, - "endpointId": 4, - "networkId": 0 - } - ] + "id": 6, + "name": "Anonymous Endpoint Type", + "deviceTypeRef": { + "code": 769, + "profileId": 259, + "label": "MA-thermostat", + "name": "MA-thermostat" + }, + "deviceTypes": [ + { + "code": 769, + "profileId": 259, + "label": "MA-thermostat", + "name": "MA-thermostat" + } + ], + "deviceVersions": [ + 2 + ], + "deviceIdentifiers": [ + 769 + ], + "deviceTypeName": "MA-thermostat", + "deviceTypeCode": 769, + "deviceTypeProfileId": 259, + "clusters": [ + { + "name": "Identify", + "code": 3, + "mfgCode": null, + "define": "IDENTIFY_CLUSTER", + "side": "server", + "enabled": 1, + "commands": [ + { + "name": "Identify", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + }, + { + "name": "TriggerEffect", + "code": 64, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + } + ], + "attributes": [ + { + "name": "IdentifyTime", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x0", + "reportable": 0, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "IdentifyType", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "IdentifyTypeEnum", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0x00", + "reportable": 0, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "EventList", + "code": 65530, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "4", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Descriptor", + "code": 29, + "mfgCode": null, + "define": "DESCRIPTOR_CLUSTER", + "side": "server", + "enabled": 1, + "attributes": [ + { + "name": "DeviceTypeList", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ServerList", + "code": 1, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 0, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClientList", + "code": 2, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 0, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "PartsList", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 0, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "EventList", + "code": 65530, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "2", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + }, + { + "name": "Thermostat", + "code": 513, + "mfgCode": null, + "define": "THERMOSTAT_CLUSTER", + "side": "server", + "enabled": 1, + "commands": [ + { + "name": "SetpointRaiseLower", + "code": 0, + "mfgCode": null, + "source": "client", + "isIncoming": 1, + "isEnabled": 1 + } + ], + "attributes": [ + { + "name": "LocalTemperature", + "code": 0, + "mfgCode": null, + "side": "server", + "type": "temperature", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AbsMinHeatSetpointLimit", + "code": 3, + "mfgCode": null, + "side": "server", + "type": "temperature", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1000", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AbsMaxHeatSetpointLimit", + "code": 4, + "mfgCode": null, + "side": "server", + "type": "temperature", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "3000", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "OccupiedHeatingSetpoint", + "code": 18, + "mfgCode": null, + "side": "server", + "type": "int16s", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "2000", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ControlSequenceOfOperation", + "code": 27, + "mfgCode": null, + "side": "server", + "type": "ControlSequenceOfOperationEnum", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "2", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "SystemMode", + "code": 28, + "mfgCode": null, + "side": "server", + "type": "SystemModeEnum", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ThermostatRunningState", + "code": 41, + "mfgCode": null, + "side": "server", + "type": "RelayStateBitmap", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "0", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "EventList", + "code": 65530, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AttributeList", + "code": 65531, + "mfgCode": null, + "side": "server", + "type": "array", + "included": 1, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "FeatureMap", + "code": 65532, + "mfgCode": null, + "side": "server", + "type": "bitmap32", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "1", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "ClusterRevision", + "code": 65533, + "mfgCode": null, + "side": "server", + "type": "int16u", + "included": 1, + "storageOption": "RAM", + "singleton": 0, + "bounded": 0, + "defaultValue": "6", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + } + ] + } + ] + } + ], + "endpoints": [ + { + "endpointTypeName": "MA-rootdevice", + "endpointTypeIndex": 0, + "profileId": 259, + "endpointId": 0, + "networkId": 0 + }, + { + "endpointTypeName": "Anonymous Endpoint Type", + "endpointTypeIndex": 1, + "profileId": 259, + "endpointId": 1, + "networkId": 0 + }, + { + "endpointTypeName": "Anonymous Endpoint Type", + "endpointTypeIndex": 2, + "profileId": 259, + "endpointId": 2, + "networkId": 0 + }, + { + "endpointTypeName": "Anonymous Endpoint Type", + "endpointTypeIndex": 3, + "profileId": 259, + "endpointId": 3, + "networkId": 0 + }, + { + "endpointTypeName": "Anonymous Endpoint Type", + "endpointTypeIndex": 4, + "profileId": 259, + "endpointId": 4, + "networkId": 0 + }, + { + "endpointTypeName": "Anonymous Endpoint Type", + "endpointTypeIndex": 5, + "profileId": 259, + "endpointId": 5, + "networkId": 0 + } + ], + "log": [] } \ No newline at end of file diff --git a/examples/air-purifier-app/air-purifier-common/include/air-purifier-manager.h b/examples/air-purifier-app/air-purifier-common/include/air-purifier-manager.h index 81565d532e4e7e..e50ccd09958283 100644 --- a/examples/air-purifier-app/air-purifier-common/include/air-purifier-manager.h +++ b/examples/air-purifier-app/air-purifier-common/include/air-purifier-manager.h @@ -22,6 +22,7 @@ #include #include #include +#include #pragma once @@ -52,12 +53,13 @@ class AirPurifierManager : public FanControl::Delegate, public DeviceManager::De AirPurifierManager & operator=(const AirPurifierManager &) = delete; static void InitInstance(EndpointId aEndpointId = 1, EndpointId aAirQualitySensorEndpointId = 2, - EndpointId aTemperatureSensorEndpointId = 3, EndpointId aHumiditySensorEndpointId = 4) + EndpointId aTemperatureSensorEndpointId = 3, EndpointId aHumiditySensorEndpointId = 4, + EndpointId aThermostatEndpointId = 5) { if (mInstance == nullptr) { mInstance = new AirPurifierManager(aEndpointId, aAirQualitySensorEndpointId, aTemperatureSensorEndpointId, - aHumiditySensorEndpointId); + aHumiditySensorEndpointId, aThermostatEndpointId); mInstance->Init(); } }; @@ -89,6 +91,11 @@ class AirPurifierManager : public FanControl::Delegate, public DeviceManager::De */ Protocols::InteractionModel::Status HandleStep(FanControl::StepDirectionEnum aDirection, bool aWrap, bool aLowestOff) override; + /** + * @brief Callback that thermostat manager calls when the heating state changes + */ + void HeatingCallback(); + private: inline static AirPurifierManager * mInstance; @@ -96,10 +103,13 @@ class AirPurifierManager : public FanControl::Delegate, public DeviceManager::De EndpointId mAirQualitySensorEndpointId; EndpointId mTemperatureSensorEndpointId; EndpointId mHumiditySensorEndpointId; + EndpointId mThermostatEndpointId; uint8_t percentCurrent; uint8_t speedCurrent; + bool fanWasStartedByUser = false; + // Set up for Activated Carbon Filter Monitoring ActivatedCarbonFilterMonitoringDelegate activatedCarbonFilterDelegate; ResourceMonitoring::Instance activatedCarbonFilterInstance; @@ -112,6 +122,7 @@ class AirPurifierManager : public FanControl::Delegate, public DeviceManager::De AirQualitySensorManager mAirQualitySensorManager; TemperatureSensorManager mTemperatureSensorManager; RelativeHumiditySensorManager mHumiditySensorManager; + ThermostatManager mThermostatManager; // Fan Mode Limits static constexpr int FAN_MODE_LOW_LOWER_BOUND = 1; @@ -129,7 +140,7 @@ class AirPurifierManager : public FanControl::Delegate, public DeviceManager::De * @param[in] aHumiditySensorEndpointId Endpoint that the humidity sensor is on */ AirPurifierManager(EndpointId aEndpointId, EndpointId aAirQualitySensorEndpointId, EndpointId aTemperatureSensorEndpointId, - EndpointId aHumiditySensorEndpointId) : + EndpointId aHumiditySensorEndpointId, EndpointId aThermostatEndpointId) : FanControl::Delegate(aEndpointId), mEndpointId(aEndpointId), activatedCarbonFilterInstance(&activatedCarbonFilterDelegate, mEndpointId, ActivatedCarbonFilterMonitoring::Id, @@ -139,7 +150,9 @@ class AirPurifierManager : public FanControl::Delegate, public DeviceManager::De static_cast(gHepaFilterFeatureMap.to_ulong()), ResourceMonitoring::DegradationDirectionEnum::kDown, true), mAirQualitySensorManager(aAirQualitySensorEndpointId), mTemperatureSensorManager(aTemperatureSensorEndpointId), - mHumiditySensorManager(aHumiditySensorEndpointId){}; + mHumiditySensorManager(aHumiditySensorEndpointId), + mThermostatManager(aThermostatEndpointId, [this]() { HeatingCallback(); }) + {} /** * @brief Handle attribute changes for the Fan Control Cluster @@ -155,6 +168,12 @@ class AirPurifierManager : public FanControl::Delegate, public DeviceManager::De void FanModeWriteCallback(FanControl::FanModeEnum aNewFanMode); void SetSpeedSetting(DataModel::Nullable aNewSpeedSetting); + DataModel::Nullable GetSpeedSetting(); + DataModel::Nullable GetPercentSetting(); + + void HandleThermostatAttributeChange(AttributeId attributeId, uint8_t type, uint16_t size, uint8_t * value); + void ThermostatHeatingSetpointWriteCallback(int16_t aNewHeatingSetpoint); + void ThermostatSystemModeWriteCallback(uint8_t aNewSystemMode); }; } // namespace Clusters diff --git a/examples/air-purifier-app/air-purifier-common/include/thermostat-manager.h b/examples/air-purifier-app/air-purifier-common/include/thermostat-manager.h new file mode 100644 index 00000000000000..f19e596f66991b --- /dev/null +++ b/examples/air-purifier-app/air-purifier-common/include/thermostat-manager.h @@ -0,0 +1,53 @@ +/* + * + * 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. + */ + +#pragma once + +#include +#include + +namespace chip { +namespace app { +namespace Clusters { + +class ThermostatManager +{ +public: + using HeatingCallbackType = std::function; + + ThermostatManager(EndpointId aEndpointId, const HeatingCallbackType & callback) : + mEndpointId(aEndpointId), heatingCallback(callback) + {} + + void Init(); + + void HeatingSetpointWriteCallback(int16_t newValue); + void SystemModeWriteCallback(uint8_t newValue); + void OnLocalTemperatureChangeCallback(int16_t temperature); + void SetHeatMode(bool heat); + +private: + EndpointId mEndpointId; + + void SetHeating(bool isHeating); + HeatingCallbackType heatingCallback; +}; + +} // namespace Clusters +} // namespace app +} // namespace chip diff --git a/examples/air-purifier-app/air-purifier-common/src/air-purifier-manager.cpp b/examples/air-purifier-app/air-purifier-common/src/air-purifier-manager.cpp index 93e1e37a73dd77..7ce8ac5f338fcc 100644 --- a/examples/air-purifier-app/air-purifier-common/src/air-purifier-manager.cpp +++ b/examples/air-purifier-app/air-purifier-common/src/air-purifier-manager.cpp @@ -33,37 +33,31 @@ void AirPurifierManager::Init() mAirQualitySensorManager.Init(); mTemperatureSensorManager.Init(); mHumiditySensorManager.Init(); + mThermostatManager.Init(); - DataModel::Nullable percentSetting; - EmberAfStatus status = FanControl::Attributes::PercentSetting::Get(mEndpointId, percentSetting); - if (EMBER_ZCL_STATUS_SUCCESS == status) + DataModel::Nullable percentSetting = GetPercentSetting(); + if (percentSetting.IsNull()) { - if (percentSetting.IsNull()) - { - PercentSettingWriteCallback(0); - } - else - { - PercentSettingWriteCallback(percentSetting.Value()); - } + PercentSettingWriteCallback(0); + } + else + { + PercentSettingWriteCallback(percentSetting.Value()); } - DataModel::Nullable speedSetting; - status = FanControl::Attributes::SpeedSetting::Get(mEndpointId, speedSetting); - if (EMBER_ZCL_STATUS_SUCCESS == status) + DataModel::Nullable speedSetting = GetSpeedSetting(); + if (speedSetting.IsNull()) { - if (speedSetting.IsNull()) - { - SpeedSettingWriteCallback(0); - } - else - { - SpeedSettingWriteCallback(speedSetting.Value()); - } + SpeedSettingWriteCallback(0); + } + else + { + SpeedSettingWriteCallback(speedSetting.Value()); } // Set up some sane initial values for temperature and humidity - note these are fixed values for testing purposes only mTemperatureSensorManager.OnTemperatureChangeHandler(2000); + mThermostatManager.OnLocalTemperatureChangeCallback(2000); mHumiditySensorManager.OnHumidityChangeHandler(5000); } @@ -77,6 +71,11 @@ void AirPurifierManager::PostAttributeChangeCallback(EndpointId endpoint, Cluste break; } + case Thermostat::Id: { + HandleThermostatAttributeChange(attributeId, type, size, value); + break; + } + default: break; } @@ -92,8 +91,7 @@ Status AirPurifierManager::HandleStep(FanControl::StepDirectionEnum aDirection, uint8_t speedMax; FanControl::Attributes::SpeedMax::Get(mEndpointId, &speedMax); - DataModel::Nullable speedSetting; - FanControl::Attributes::SpeedSetting::Get(mEndpointId, speedSetting); + DataModel::Nullable speedSetting = GetSpeedSetting(); uint8_t newSpeedSetting = speedSetting.IsNull() ? 0 : speedSetting.Value(); @@ -309,3 +307,68 @@ void AirPurifierManager::SetSpeedSetting(DataModel::Nullable aNewSpeedS } } } + +DataModel::Nullable AirPurifierManager::GetSpeedSetting() +{ + DataModel::Nullable speedSetting; + EmberAfStatus status = FanControl::Attributes::SpeedSetting::Get(mEndpointId, speedSetting); + + if (status != EMBER_ZCL_STATUS_SUCCESS) + { + ChipLogError(NotSpecified, "AirPurifierManager::GetSpeedSetting: failed to get SpeedSetting attribute: %d", status); + } + + return speedSetting; +} + +DataModel::Nullable AirPurifierManager::GetPercentSetting() +{ + DataModel::Nullable percentSetting; + EmberAfStatus status = FanControl::Attributes::PercentSetting::Get(mEndpointId, percentSetting); + + if (status != EMBER_ZCL_STATUS_SUCCESS) + { + ChipLogError(NotSpecified, "AirPurifierManager::GetPercentSetting: failed to get PercentSetting attribute: %d", status); + } + + return percentSetting; +} + +void AirPurifierManager::HandleThermostatAttributeChange(AttributeId attributeId, uint8_t type, uint16_t size, uint8_t * value) +{ + switch (attributeId) + { + case Thermostat::Attributes::OccupiedHeatingSetpoint::Id: { + int16_t heatingSetpoint = static_cast(chip::Encoding::LittleEndian::Get16(value)); + ThermostatHeatingSetpointWriteCallback(heatingSetpoint); + break; + } + case Thermostat::Attributes::SystemMode::Id: { + uint8_t systemMode = static_cast(*value); + ThermostatSystemModeWriteCallback(systemMode); + break; + } + } +} + +void AirPurifierManager::ThermostatHeatingSetpointWriteCallback(int16_t aNewHeatingSetpoint) +{ + mThermostatManager.HeatingSetpointWriteCallback(aNewHeatingSetpoint); +} + +void AirPurifierManager::ThermostatSystemModeWriteCallback(uint8_t aNewSystemMode) +{ + mThermostatManager.SystemModeWriteCallback(aNewSystemMode); +} + +void AirPurifierManager::HeatingCallback() +{ + // Check if the Fan is off and if it is, turn it on to 50% speed + DataModel::Nullable speedSetting = GetSpeedSetting(); + + if (speedSetting.IsNull() || speedSetting.Value() == 0) + { + DataModel::Nullable newSpeedSetting(5); + SetSpeedSetting(newSpeedSetting); + } +} diff --git a/examples/air-purifier-app/air-purifier-common/src/thermostat-manager.cpp b/examples/air-purifier-app/air-purifier-common/src/thermostat-manager.cpp new file mode 100644 index 00000000000000..c2536e4d99e38b --- /dev/null +++ b/examples/air-purifier-app/air-purifier-common/src/thermostat-manager.cpp @@ -0,0 +1,135 @@ +/* + * + * Copyright (c) 2024 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. + */ + +#include "thermostat-manager.h" + +using namespace chip; +using namespace chip::app; +using namespace chip::app::Clusters; + +void ThermostatManager::Init() +{ + BitMask FeatureMap; + FeatureMap.Set(Thermostat::Feature::kHeating); + EmberAfStatus status = Thermostat::Attributes::FeatureMap::Set(mEndpointId, FeatureMap.Raw()); + + status = Thermostat::Attributes::ControlSequenceOfOperation::Set(mEndpointId, + Thermostat::ControlSequenceOfOperationEnum::kHeatingOnly); + VerifyOrReturn(EMBER_ZCL_STATUS_SUCCESS == status, + ChipLogError(NotSpecified, "Failed to set Thermostat ControlSequenceOfOperation attribute")); + + status = Thermostat::Attributes::AbsMinHeatSetpointLimit::Set(mEndpointId, 500); + VerifyOrReturn(EMBER_ZCL_STATUS_SUCCESS == status, + ChipLogError(NotSpecified, "Failed to set Thermostat MinHeatSetpointLimit attribute")); + + status = Thermostat::Attributes::AbsMaxHeatSetpointLimit::Set(mEndpointId, 3000); + VerifyOrReturn(EMBER_ZCL_STATUS_SUCCESS == status, + ChipLogError(NotSpecified, "Failed to set Thermostat MaxHeatSetpointLimit attribute")); +} + +void ThermostatManager::HeatingSetpointWriteCallback(int16_t newValue) +{ + ChipLogDetail(NotSpecified, "ThermostatManager::HeatingSetpointWriteCallback: %d", newValue); + Thermostat::SystemModeEnum systemMode; + EmberAfStatus status = Thermostat::Attributes::SystemMode::Get(mEndpointId, &systemMode); + VerifyOrReturn(EMBER_ZCL_STATUS_SUCCESS == status, ChipLogError(NotSpecified, "Failed to get Thermostat SystemMode attribute")); + + // A new setpoint has been set, so we shall infer that the we want to be in Heating mode + if (systemMode == Thermostat::SystemModeEnum::kOff) + { + SetHeatMode(true); + } + + // Check the current temperature and turn on the heater if needed + DataModel::Nullable localTemperature; + status = Thermostat::Attributes::LocalTemperature::Get(mEndpointId, localTemperature); + VerifyOrReturn(EMBER_ZCL_STATUS_SUCCESS == status, + ChipLogError(NotSpecified, "Failed to get TemperatureMeasurement MeasuredValue attribute")); + + if (localTemperature.Value() < newValue) + { + SetHeating(true); + } + else + { + SetHeating(false); + } +} + +void ThermostatManager::SystemModeWriteCallback(uint8_t newValue) +{ + ChipLogDetail(NotSpecified, "ThermostatManager::SystemModeWriteCallback: %d", newValue); + if ((Thermostat::SystemModeEnum) newValue == Thermostat::SystemModeEnum::kOff) + { + SetHeating(false); + } + else if ((Thermostat::SystemModeEnum) newValue == Thermostat::SystemModeEnum::kHeat) + { + DataModel::Nullable localTemperature; + EmberAfStatus status = Thermostat::Attributes::LocalTemperature::Get(mEndpointId, localTemperature); + VerifyOrReturn(EMBER_ZCL_STATUS_SUCCESS == status, + ChipLogError(NotSpecified, "Failed to get TemperatureMeasurement MeasuredValue attribute")); + + int16_t heatingSetpoint; + status = Thermostat::Attributes::OccupiedHeatingSetpoint::Get(mEndpointId, &heatingSetpoint); + VerifyOrReturn(EMBER_ZCL_STATUS_SUCCESS == status, + ChipLogError(NotSpecified, "Failed to get Thermostat HeatingSetpoint attribute")); + + if (localTemperature.Value() < heatingSetpoint) + { + SetHeating(true); + } + } +} + +void ThermostatManager::OnLocalTemperatureChangeCallback(int16_t temperature) +{ + EmberAfStatus status = Thermostat::Attributes::LocalTemperature::Set(mEndpointId, temperature); + VerifyOrReturn(EMBER_ZCL_STATUS_SUCCESS == status, + ChipLogError(NotSpecified, "Failed to set TemperatureMeasurement MeasuredValue attribute")); +} + +void ThermostatManager::SetHeating(bool isHeating) +{ + BitMask runningState; + + if (isHeating) + { + runningState.Set(Thermostat::RelayStateBitmap::kHeat); + + if (heatingCallback) + { + heatingCallback(); + } + } + else + { + runningState.Clear(Thermostat::RelayStateBitmap::kHeat); + } + + EmberAfStatus status = Thermostat::Attributes::ThermostatRunningState::Set(mEndpointId, runningState); + VerifyOrReturn(EMBER_ZCL_STATUS_SUCCESS == status, + ChipLogError(NotSpecified, "Failed to set Thermostat RunningState attribute")); +} + +void ThermostatManager::SetHeatMode(bool heat) +{ + EmberAfStatus status = Thermostat::Attributes::SystemMode::Set( + mEndpointId, heat ? Thermostat::SystemModeEnum::kHeat : Thermostat::SystemModeEnum::kOff); + VerifyOrReturn(EMBER_ZCL_STATUS_SUCCESS == status, ChipLogError(NotSpecified, "Failed to set Thermostat SystemMode attribute")); +} diff --git a/examples/air-purifier-app/ameba/README.md b/examples/air-purifier-app/ameba/README.md index be11ad8d063210..ee2a451203cb7f 100644 --- a/examples/air-purifier-app/ameba/README.md +++ b/examples/air-purifier-app/ameba/README.md @@ -10,7 +10,7 @@ This example demonstrates the Matter air purifier application on Ameba platform. - [Commissioning](#commissioning) - [BLE mode](#ble-mode) - [IP mode](#ip-mode) - - [Cluster control](#cluster-control) + - [Cluster Control](#cluster-control) --- @@ -106,6 +106,7 @@ follows: - Air quality sensor on endpoint 2 - Temperature sensor on endpoint 3 - Relative humidity sensor on endpoint 4 +- Thermostat on endpoint 5 Example commands using the chip tool: diff --git a/examples/air-purifier-app/ameba/main/chipinterface.cpp b/examples/air-purifier-app/ameba/main/chipinterface.cpp index bcda329cdb8536..264ad532b513aa 100644 --- a/examples/air-purifier-app/ameba/main/chipinterface.cpp +++ b/examples/air-purifier-app/ameba/main/chipinterface.cpp @@ -48,6 +48,7 @@ #define AIR_QUALITY_SENSOR_ENDPOINT 2 #define TEMPERATURE_SENSOR_ENDPOINT 3 #define RELATIVE_HUMIDITY_SENSOR_ENDPOINT 4 +#define THERMOSTAT_ENDPOINT 5 using namespace ::chip; using namespace ::chip::app; @@ -116,11 +117,12 @@ static void InitAirPurifierManager(void) { Clusters::AirPurifierManager::InitInstance(EndpointId(AIR_PURIFIER_ENDPOINT), EndpointId(AIR_QUALITY_SENSOR_ENDPOINT), EndpointId(TEMPERATURE_SENSOR_ENDPOINT), - EndpointId(RELATIVE_HUMIDITY_SENSOR_ENDPOINT)); + EndpointId(RELATIVE_HUMIDITY_SENSOR_ENDPOINT), EndpointId(THERMOSTAT_ENDPOINT)); SetParentEndpointForEndpoint(AIR_QUALITY_SENSOR_ENDPOINT, AIR_PURIFIER_ENDPOINT); SetParentEndpointForEndpoint(TEMPERATURE_SENSOR_ENDPOINT, AIR_PURIFIER_ENDPOINT); SetParentEndpointForEndpoint(RELATIVE_HUMIDITY_SENSOR_ENDPOINT, AIR_PURIFIER_ENDPOINT); + SetParentEndpointForEndpoint(THERMOSTAT_ENDPOINT, AIR_PURIFIER_ENDPOINT); } static void InitServer(intptr_t context) diff --git a/examples/air-purifier-app/cc32xx/BUILD.gn b/examples/air-purifier-app/cc32xx/BUILD.gn index 51916cc32d646f..f79e76c82ce0d3 100755 --- a/examples/air-purifier-app/cc32xx/BUILD.gn +++ b/examples/air-purifier-app/cc32xx/BUILD.gn @@ -85,6 +85,7 @@ ti_simplelink_executable("air-purifier_app") { "${chip_root}/examples/air-purifier-app/air-purifier-common/src/air-purifier-manager.cpp", "${chip_root}/examples/air-purifier-app/air-purifier-common/src/air-quality-sensor-manager.cpp", "${chip_root}/examples/air-purifier-app/air-purifier-common/src/filter-delegates.cpp", + "${chip_root}/examples/air-purifier-app/air-purifier-common/src/thermostat-manager.cpp", "${project_dir}/main/AppTask.cpp", "${project_dir}/main/CHIPDeviceManager.cpp", "${project_dir}/main/CXXExceptionStubs.cpp", diff --git a/examples/air-purifier-app/cc32xx/main/AppTask.cpp b/examples/air-purifier-app/cc32xx/main/AppTask.cpp index e753e5ac4aed8f..0b284254b0c80f 100644 --- a/examples/air-purifier-app/cc32xx/main/AppTask.cpp +++ b/examples/air-purifier-app/cc32xx/main/AppTask.cpp @@ -64,6 +64,7 @@ extern void DisplayBanner(); #define AIR_QUALITY_SENSOR_ENDPOINT 2 #define TEMPERATURE_SENSOR_ENDPOINT 3 #define RELATIVE_HUMIDITY_SENSOR_ENDPOINT 4 +#define THERMOSTAT_ENDPOINT 5 // Added the below three for DNS Server Initialization using namespace ::chip; @@ -178,9 +179,11 @@ int AppTask::Init() SetParentEndpointForEndpoint(AIR_QUALITY_SENSOR_ENDPOINT, AIR_PURIFIER_ENDPOINT); SetParentEndpointForEndpoint(TEMPERATURE_SENSOR_ENDPOINT, AIR_PURIFIER_ENDPOINT); SetParentEndpointForEndpoint(RELATIVE_HUMIDITY_SENSOR_ENDPOINT, AIR_PURIFIER_ENDPOINT); + SetParentEndpointForEndpoint(THERMOSTAT_ENDPOINT, AIR_PURIFIER_ENDPOINT); AirPurifierManager::InitInstance(EndpointId(AIR_PURIFIER_ENDPOINT), EndpointId(AIR_QUALITY_SENSOR_ENDPOINT), - EndpointId(TEMPERATURE_SENSOR_ENDPOINT), EndpointId(RELATIVE_HUMIDITY_SENSOR_ENDPOINT)); + EndpointId(TEMPERATURE_SENSOR_ENDPOINT), EndpointId(RELATIVE_HUMIDITY_SENSOR_ENDPOINT), + EndpointId(THERMOSTAT_ENDPOINT)); ConfigurationMgr().LogDeviceConfig(); diff --git a/examples/air-purifier-app/linux/BUILD.gn b/examples/air-purifier-app/linux/BUILD.gn index 0a0f86cac16ec4..0f4d2a489dc18a 100644 --- a/examples/air-purifier-app/linux/BUILD.gn +++ b/examples/air-purifier-app/linux/BUILD.gn @@ -33,6 +33,7 @@ executable("chip-air-purifier-app") { "${chip_root}/examples/air-purifier-app/air-purifier-common/src/air-purifier-manager.cpp", "${chip_root}/examples/air-purifier-app/air-purifier-common/src/air-quality-sensor-manager.cpp", "${chip_root}/examples/air-purifier-app/air-purifier-common/src/filter-delegates.cpp", + "${chip_root}/examples/air-purifier-app/air-purifier-common/src/thermostat-manager.cpp", "include/CHIPProjectAppConfig.h", "main.cpp", ] diff --git a/examples/air-purifier-app/linux/README.md b/examples/air-purifier-app/linux/README.md index 88f5be738c926d..d2352bca201e1a 100644 --- a/examples/air-purifier-app/linux/README.md +++ b/examples/air-purifier-app/linux/README.md @@ -4,9 +4,10 @@ An example showing the use of CHIP on the Linux. The document will describe how to build and run CHIP Air Purifier Example on A Linux System. This doc is tested on **Ubuntu 20.04 LTS**. -The Air Purifier is a composed device with Endpoint 1 being the Air Purifier. -Endpoint 2 is an Air Quality Sensor, Endpoint 3 is a Relative Humidity Sensor -and endpoint 4 is a Temperature Sensor. +The Air Purifier example demonstrates a fully functional Matter Air Purifier +which is a composed device with Endpoint 1 being the Air Purifier. Endpoint 2 is +an Air Quality Sensor, Endpoint 3 is a Relative Humidity Sensor, Endpoint 4 is a +Temperature Sensor and Endpoint 5 is a Thermostat. To cross-compile this example on x64 host and run on **NXP i.MX 8M Mini** **EVK**, see the associated @@ -99,11 +100,11 @@ To cross-compile this example on x64 host and run on **NXP i.MX 8M Mini** RX bytes:8609495 acl:14 sco:0 events:217484 errors:0 TX bytes:92185 acl:20 sco:0 commands:5259 errors:0 - - Run Linux Lighting Example App + - Run Linux Air Purifier Example App - $ cd ~/connectedhomeip/examples/lighting-app/linux - $ sudo out/debug/chip-lighting-app --ble-device [bluetooth device number] + $ cd ~/connectedhomeip/examples/air-purifier-app/linux + $ sudo out/debug/chip-air-purifier-app --ble-device [bluetooth device number] # In this example, the device we want to use is hci1 - $ sudo out/debug/chip-lighting-app --ble-device 1 + $ sudo out/debug/chip-air-purifier-app --ble-device 1 - Test the device using ChipTool on your laptop / workstation etc. diff --git a/examples/air-purifier-app/linux/main.cpp b/examples/air-purifier-app/linux/main.cpp index 59ef9cf9595755..98d8d405cfadfb 100644 --- a/examples/air-purifier-app/linux/main.cpp +++ b/examples/air-purifier-app/linux/main.cpp @@ -27,7 +27,7 @@ #define AIR_QUALITY_SENSOR_ENDPOINT 2 #define TEMPERATURE_SENSOR_ENDPOINT 3 #define RELATIVE_HUMIDITY_SENSOR_ENDPOINT 4 -// TODO: Add support for the thermostat endpoint in future PR. +#define THERMOSTAT_ENDPOINT 5 using namespace chip; using namespace chip::app; @@ -48,11 +48,13 @@ void MatterPostAttributeChangeCallback(const chip::app::ConcreteAttributePath & void ApplicationInit() { AirPurifierManager::InitInstance(EndpointId(AIR_PURIFIER_ENDPOINT), EndpointId(AIR_QUALITY_SENSOR_ENDPOINT), - EndpointId(TEMPERATURE_SENSOR_ENDPOINT), EndpointId(RELATIVE_HUMIDITY_SENSOR_ENDPOINT)); + EndpointId(TEMPERATURE_SENSOR_ENDPOINT), EndpointId(RELATIVE_HUMIDITY_SENSOR_ENDPOINT), + EndpointId(THERMOSTAT_ENDPOINT)); SetParentEndpointForEndpoint(AIR_QUALITY_SENSOR_ENDPOINT, AIR_PURIFIER_ENDPOINT); SetParentEndpointForEndpoint(TEMPERATURE_SENSOR_ENDPOINT, AIR_PURIFIER_ENDPOINT); SetParentEndpointForEndpoint(RELATIVE_HUMIDITY_SENSOR_ENDPOINT, AIR_PURIFIER_ENDPOINT); + SetParentEndpointForEndpoint(THERMOSTAT_ENDPOINT, AIR_PURIFIER_ENDPOINT); } void ApplicationShutdown() diff --git a/examples/lighting-app/telink/prj.conf b/examples/lighting-app/telink/prj.conf index 87a5c03720bbf4..f4b2a44e1c672c 100644 --- a/examples/lighting-app/telink/prj.conf +++ b/examples/lighting-app/telink/prj.conf @@ -51,5 +51,8 @@ CONFIG_CHIP_FACTORY_DATA_BUILD=n CONFIG_CHIP_FACTORY_DATA_MERGE_WITH_FIRMWARE=n CONFIG_CHIP_CERTIFICATION_DECLARATION_STORAGE=n +#Enable PWM +CONFIG_PWM=y + # Enable Power Management CONFIG_PM=n diff --git a/examples/lock-app/telink/Kconfig b/examples/lock-app/telink/Kconfig index 5238b4423a4196..640a54e73d45a4 100644 --- a/examples/lock-app/telink/Kconfig +++ b/examples/lock-app/telink/Kconfig @@ -15,5 +15,16 @@ # mainmenu "Matter Telink Lock Example Application" +if BOARD_TLSR9528A_RETENTION || BOARD_TLSR9518ADK80D_RETENTION +config COMMON_LIBC_MALLOC_ARENA_SIZE + default 9216 +endif + +config SETTINGS_NVS_NAME_CACHE + default y + +config SETTINGS_NVS_NAME_CACHE_SIZE + default 256 + rsource "../../../config/telink/chip-module/Kconfig.defaults" source "Kconfig.zephyr" diff --git a/examples/lock-app/telink/boards/tlsr9518adk80d.overlay b/examples/lock-app/telink/boards/tlsr9518adk80d.overlay new file mode 100644 index 00000000000000..47b56fd18a0718 --- /dev/null +++ b/examples/lock-app/telink/boards/tlsr9518adk80d.overlay @@ -0,0 +1,16 @@ +/ { + keys { + compatible = "gpio-keys"; + key_5: button_5 { + gpios = <&gpioe 0 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + }; + key_6: button_6 { + gpios = <&gpioe 1 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + }; + }; +}; + +&gpioe { + interrupts = <38 1>; + status = "okay"; +}; \ No newline at end of file diff --git a/examples/lock-app/telink/boards/tlsr9528a.overlay b/examples/lock-app/telink/boards/tlsr9528a.overlay new file mode 100644 index 00000000000000..ebcb0aec07bc67 --- /dev/null +++ b/examples/lock-app/telink/boards/tlsr9528a.overlay @@ -0,0 +1,16 @@ +/ { + keys { + compatible = "gpio-keys"; + key_5: button_5 { + gpios = <&gpiob 6 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + }; + key_6: button_6 { + gpios = <&gpiob 7 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + }; + }; +}; + +&gpiob { + interrupts = <39 1>; + status = "okay"; +}; \ No newline at end of file diff --git a/examples/lock-app/telink/boards/tlsr9528a_retention.overlay b/examples/lock-app/telink/boards/tlsr9528a_retention.overlay new file mode 100644 index 00000000000000..9b728f8b4d9e10 --- /dev/null +++ b/examples/lock-app/telink/boards/tlsr9528a_retention.overlay @@ -0,0 +1,16 @@ +/ { + keys { + compatible = "gpio-keys"; + key_5: button_5 { + gpios = <&gpiob 6 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + }; + key_6: button_6 { + gpios = <&gpiob 7 (GPIO_PULL_UP | GPIO_ACTIVE_LOW)>; + }; + }; +}; + +&gpiob { + interrupts = <39 1>; + status = "okay"; +}; diff --git a/examples/lock-app/telink/include/AppConfig.h b/examples/lock-app/telink/include/AppConfig.h index 05bbd6afa79d46..cb4b0c2b488d86 100644 --- a/examples/lock-app/telink/include/AppConfig.h +++ b/examples/lock-app/telink/include/AppConfig.h @@ -23,6 +23,14 @@ #define LOCK_MANAGER_CONFIG_USE_NVM_CREDENTIAL_STORAGE 1 #define LOCK_MANAGER_ACTUATOR_MOVEMENT_TIME_MS 2000 +#define APP_MAX_USERS 10 +#define APP_MAX_CREDENTIAL 10 +#define APP_MAX_WEEKDAY_SCHEDULE_PER_USER 10 +#define APP_MAX_YEARDAY_SCHEDULE_PER_USER 10 +#define APP_MAX_HOLYDAY_SCHEDULE_PER_USER 10 + +#define APP_MAX_SCHEDULES_TOTAL 100 + #define APP_DEFAULT_USERS_COUNT 5 #define APP_DEFAULT_CREDENTIAL_COUNT 5 #define APP_DEFAULT_WEEKDAY_SCHEDULE_PER_USER_COUNT 5 diff --git a/examples/lock-app/telink/include/AppTask.h b/examples/lock-app/telink/include/AppTask.h index d5244bb7b7728f..fb0f4113d4af9f 100644 --- a/examples/lock-app/telink/include/AppTask.h +++ b/examples/lock-app/telink/include/AppTask.h @@ -40,6 +40,10 @@ class AppTask : public AppTaskCommon static void LockActionEventHandler(AppEvent * event); static void LockStateChanged(LockManager::State_t state); + static void LockJammedEventHandler(void); + static void LockJammedActionHandler(AppEvent * aEvent); + static void LockStateEventHandler(void); + static void LockStateActionHandler(AppEvent * aEvent); static AppTask sAppTask; }; diff --git a/examples/lock-app/telink/include/LockManager.h b/examples/lock-app/telink/include/LockManager.h index 72fbcc648216cd..4420b4789562ec 100644 --- a/examples/lock-app/telink/include/LockManager.h +++ b/examples/lock-app/telink/include/LockManager.h @@ -30,34 +30,27 @@ struct WeekDaysScheduleInfo { - DlScheduleStatus status; + DlScheduleStatus status = DlScheduleStatus::kAvailable; EmberAfPluginDoorLockWeekDaySchedule schedule; }; struct YearDayScheduleInfo { - DlScheduleStatus status; + DlScheduleStatus status = DlScheduleStatus::kAvailable; EmberAfPluginDoorLockYearDaySchedule schedule; }; struct HolidayScheduleInfo { - DlScheduleStatus status; + DlScheduleStatus status = DlScheduleStatus::kAvailable; EmberAfPluginDoorLockHolidaySchedule schedule; }; namespace TelinkDoorLock { namespace ResourceRanges { // Used to size arrays -static constexpr uint16_t kMaxUsers = 10; -static constexpr uint8_t kMaxCredentialsPerUser = 10; -static constexpr uint8_t kMaxWeekdaySchedulesPerUser = 10; -static constexpr uint8_t kMaxYeardaySchedulesPerUser = 10; -static constexpr uint8_t kMaxHolidaySchedules = 10; -static constexpr uint8_t kMaxCredentialSize = 20; -static constexpr uint8_t kNumCredentialTypes = 6; - -static constexpr uint8_t kMaxCredentials = kMaxUsers * kMaxCredentialsPerUser; +static constexpr uint8_t kMaxCredentialSize = 20; +static constexpr uint8_t kNumCredentialTypes = 6; } // namespace ResourceRanges @@ -197,10 +190,6 @@ class LockManager OperationSource mActuatorOperationSource = OperationSource::kButton; k_timer mActuatorTimer = {}; -#if LOCK_MANAGER_CONFIG_USE_NVM_CREDENTIAL_STORAGE - bool ReadConfigValues(); -#endif - bool setLockState(chip::EndpointId endpointId, DlLockState lockState, OperationSource source, OperationErrorEnum & err, const Nullable & fabricIdx, const Nullable & nodeId, const Optional & pin); @@ -208,15 +197,17 @@ class LockManager static void ActuatorTimerEventHandler(k_timer * timer); static void ActuatorAppEventHandler(const AppEvent & event); - EmberAfPluginDoorLockUserInfo mLockUsers[kMaxUsers]; - EmberAfPluginDoorLockCredentialInfo mLockCredentials[kNumCredentialTypes][kMaxCredentials]; - WeekDaysScheduleInfo mWeekdaySchedule[kMaxUsers][kMaxWeekdaySchedulesPerUser]; - YearDayScheduleInfo mYeardaySchedule[kMaxUsers][kMaxYeardaySchedulesPerUser]; - HolidayScheduleInfo mHolidaySchedule[kMaxHolidaySchedules]; +#if !LOCK_MANAGER_CONFIG_USE_NVM_CREDENTIAL_STORAGE + EmberAfPluginDoorLockUserInfo mLockUsers[APP_MAX_USERS]; + EmberAfPluginDoorLockCredentialInfo mLockCredentials[kNumCredentialTypes][APP_MAX_CREDENTIAL]; + WeekDaysScheduleInfo mWeekdaySchedule[APP_MAX_USERS][APP_MAX_WEEKDAY_SCHEDULE_PER_USER]; + YearDayScheduleInfo mYeardaySchedule[APP_MAX_USERS][APP_MAX_YEARDAY_SCHEDULE_PER_USER]; + HolidayScheduleInfo mHolidaySchedule[APP_MAX_HOLYDAY_SCHEDULE_PER_USER]; char mUserNames[ArraySize(mLockUsers)][DOOR_LOCK_MAX_USER_NAME_SIZE]; - uint8_t mCredentialData[kNumCredentialTypes][kMaxCredentials][kMaxCredentialSize]; - CredentialStruct mCredentials[kMaxUsers][kMaxCredentials]; + uint8_t mCredentialData[kNumCredentialTypes][APP_MAX_CREDENTIAL][kMaxCredentialSize]; + CredentialStruct mCredentials[APP_MAX_USERS][APP_MAX_CREDENTIAL]; +#endif static LockManager sLock; TelinkDoorLock::LockInitParams::LockParam LockParams; diff --git a/examples/lock-app/telink/include/LockSettingsStorage.h b/examples/lock-app/telink/include/LockSettingsStorage.h index fd2c7939139327..b33629f3fc73ff 100644 --- a/examples/lock-app/telink/include/LockSettingsStorage.h +++ b/examples/lock-app/telink/include/LockSettingsStorage.h @@ -28,14 +28,25 @@ namespace Internal { class LockSettingsStorage : ZephyrConfig { public: - static const ZephyrConfig::Key kConfigKey_LockUser; - static const ZephyrConfig::Key kConfigKey_LockUserName; - static const ZephyrConfig::Key kConfigKey_UserCredentials; - static const ZephyrConfig::Key kConfigKey_WeekDaySchedules; - static const ZephyrConfig::Key kConfigKey_YearDaySchedules; - static const ZephyrConfig::Key kConfigKey_HolidaySchedules; - static const char * kConfigKey_Credential[kNumCredentialTypes]; - static const char * kConfigKey_CredentialData[kNumCredentialTypes]; + static const char * kConfigKey_LockUser[APP_MAX_USERS]; + static const char * kConfigKey_LockUserName[APP_MAX_USERS]; + static const char * kConfigKey_UserCredentials[APP_MAX_CREDENTIAL]; + static const char * kConfigKey_WeekDaySchedules[APP_MAX_USERS][APP_MAX_WEEKDAY_SCHEDULE_PER_USER]; + static const char * kConfigKey_YearDaySchedules[APP_MAX_USERS][APP_MAX_YEARDAY_SCHEDULE_PER_USER]; + static const char * kConfigKey_HolidaySchedules[APP_MAX_HOLYDAY_SCHEDULE_PER_USER]; + + static const char * kConfigKey_CredentialPin[APP_MAX_CREDENTIAL]; + static const char * kConfigKey_CredentialFace[APP_MAX_CREDENTIAL]; + static const char * kConfigKey_CredentialFingerprint[APP_MAX_CREDENTIAL]; + static const char * kConfigKey_CredentialFingervein[APP_MAX_CREDENTIAL]; + static const char * kConfigKey_CredentialRfid[APP_MAX_CREDENTIAL]; + + static const char * kConfigKey_CredentialData[APP_MAX_CREDENTIAL]; + static const char * kConfigKey_CredentialDataPin[APP_MAX_CREDENTIAL]; + static const char * kConfigKey_CredentialDataFace[APP_MAX_CREDENTIAL]; + static const char * kConfigKey_CredentialDataFingerprint[APP_MAX_CREDENTIAL]; + static const char * kConfigKey_CredentialDataFingerVein[APP_MAX_CREDENTIAL]; + static const char * kConfigKey_CredentialDataRfid[APP_MAX_CREDENTIAL]; }; } // namespace Internal } // namespace DeviceLayer diff --git a/examples/lock-app/telink/src/AppTask.cpp b/examples/lock-app/telink/src/AppTask.cpp index 11f8499bd5bd41..19748544f8d15d 100644 --- a/examples/lock-app/telink/src/AppTask.cpp +++ b/examples/lock-app/telink/src/AppTask.cpp @@ -17,6 +17,7 @@ */ #include "AppTask.h" +#include "ButtonManager.h" #include #include #include @@ -39,12 +40,20 @@ LEDWidget sLockLED; } // namespace AppTask AppTask::sAppTask; +static const struct gpio_dt_spec sLockJammedInputDt = GPIO_DT_SPEC_GET(DT_NODELABEL(key_5), gpios); +static const struct gpio_dt_spec sLockStatusInputDt = GPIO_DT_SPEC_GET(DT_NODELABEL(key_6), gpios); +Button sLockJammedAction; +Button sLockStatusChangedAction; CHIP_ERROR AppTask::Init(void) { #if APP_USE_EXAMPLE_START_BUTTON SetExampleButtonCallbacks(LockActionEventHandler); #endif + sLockJammedAction.Configure(&sLockJammedInputDt, LockJammedEventHandler); + sLockStatusChangedAction.Configure(&sLockStatusInputDt, LockStateEventHandler); + ButtonManagerInst().AddButton(sLockJammedAction); + ButtonManagerInst().AddButton(sLockStatusChangedAction); InitCommonParts(); #if CONFIG_CHIP_ENABLE_APPLICATION_STATUS_LED @@ -200,3 +209,51 @@ void AppTask::LockStateChanged(LockManager::State_t state) break; } } + +void AppTask::LockJammedEventHandler(void) +{ + AppEvent event; + + event.Type = AppEvent::kEventType_Button; + event.ButtonEvent.Action = kButtonPushEvent; + event.Handler = LockJammedActionHandler; + GetAppTask().PostEvent(&event); +} + +void AppTask::LockJammedActionHandler(AppEvent * aEvent) +{ + LOG_INF("Sending a lock jammed event"); + + /* Generating Door Lock Jammed event */ + DoorLockServer::Instance().SendLockAlarmEvent(kExampleEndpointId, AlarmCodeEnum::kLockJammed); +} + +void AppTask::LockStateEventHandler(void) +{ + AppEvent event; + + event.Type = AppEvent::kEventType_Button; + event.ButtonEvent.Action = kButtonPushEvent; + event.Handler = LockStateActionHandler; + GetAppTask().PostEvent(&event); +} + +void AppTask::LockStateActionHandler(AppEvent * aEvent) +{ + LOG_INF("Sending a lock state event"); + + // This code was written for testing purpose only + // For real door status the level detection may be used instead of pulse + static DoorStateEnum mDoorState = DoorStateEnum::kDoorOpen; + if (mDoorState == DoorStateEnum::kDoorOpen) + { + mDoorState = DoorStateEnum::kDoorClosed; + } + else + { + mDoorState = DoorStateEnum::kDoorOpen; + } + + /* Generating Door Lock Status event */ + DoorLockServer::Instance().SetDoorState(kExampleEndpointId, mDoorState); +} diff --git a/examples/lock-app/telink/src/LockManager.cpp b/examples/lock-app/telink/src/LockManager.cpp index 529e1aa557fa7c..070503a1a144c9 100644 --- a/examples/lock-app/telink/src/LockManager.cpp +++ b/examples/lock-app/telink/src/LockManager.cpp @@ -32,61 +32,68 @@ LockManager LockManager::sLock; using namespace ::chip::DeviceLayer::Internal; using namespace TelinkDoorLock::LockInitParams; +#if LOCK_MANAGER_CONFIG_USE_NVM_CREDENTIAL_STORAGE +__attribute__((section(".data"))) EmberAfPluginDoorLockUserInfo mCurrentLockUsers; + +__attribute__((section(".data"))) char mCurrentUserNames[DOOR_LOCK_MAX_USER_NAME_SIZE]; +__attribute__((section(".data"))) uint8_t mCurrentCredentialData[kMaxCredentialSize]; +__attribute__((section(".data"))) CredentialStruct mCurrentCredentials[APP_MAX_CREDENTIAL]; +__attribute__((section(".data"))) HolidayScheduleInfo mHolidaySchedule; +__attribute__((section(".data"))) WeekDaysScheduleInfo mWeekdaySchedule; +__attribute__((section(".data"))) YearDayScheduleInfo mYeardaySchedule; +#endif + CHIP_ERROR LockManager::Init(chip::app::DataModel::Nullable state, LockParam lockParam, StateChangeCallback callback) { LockParams = lockParam; mStateChangeCallback = callback; - if (LockParams.numberOfUsers > kMaxUsers) + if (LockParams.numberOfUsers > APP_MAX_USERS) { ChipLogError(Zcl, "Max number of users %d is greater than %d, the maximum amount of users currently supported on this platform", - LockParams.numberOfUsers, kMaxUsers); + LockParams.numberOfUsers, APP_MAX_USERS); return APP_ERROR_ALLOCATION_FAILED; } - if (LockParams.numberOfCredentialsPerUser > kMaxCredentialsPerUser) + if (LockParams.numberOfCredentialsPerUser > APP_MAX_CREDENTIAL) { ChipLogError( Zcl, "Max number of credentials per user %d is greater than %d, the maximum amount of users currently supported on this " "platform", - LockParams.numberOfCredentialsPerUser, kMaxCredentialsPerUser); + LockParams.numberOfCredentialsPerUser, APP_MAX_CREDENTIAL); return APP_ERROR_ALLOCATION_FAILED; } - if (LockParams.numberOfWeekdaySchedulesPerUser > kMaxWeekdaySchedulesPerUser) + if (LockParams.numberOfWeekdaySchedulesPerUser > APP_MAX_WEEKDAY_SCHEDULE_PER_USER) { ChipLogError( Zcl, "Max number of schedules %d is greater than %d, the maximum amount of schedules currently supported on this platform", - LockParams.numberOfWeekdaySchedulesPerUser, kMaxWeekdaySchedulesPerUser); + LockParams.numberOfWeekdaySchedulesPerUser, APP_MAX_WEEKDAY_SCHEDULE_PER_USER); return APP_ERROR_ALLOCATION_FAILED; } - if (LockParams.numberOfYeardaySchedulesPerUser > kMaxYeardaySchedulesPerUser) + if (LockParams.numberOfYeardaySchedulesPerUser > APP_MAX_YEARDAY_SCHEDULE_PER_USER) { ChipLogError( Zcl, "Max number of schedules %d is greater than %d, the maximum amount of schedules currently supported on this platform", - LockParams.numberOfYeardaySchedulesPerUser, kMaxYeardaySchedulesPerUser); + LockParams.numberOfYeardaySchedulesPerUser, APP_MAX_YEARDAY_SCHEDULE_PER_USER); return APP_ERROR_ALLOCATION_FAILED; } - if (LockParams.numberOfHolidaySchedules > kMaxHolidaySchedules) + if (LockParams.numberOfHolidaySchedules > APP_MAX_HOLYDAY_SCHEDULE_PER_USER) { ChipLogError( Zcl, "Max number of schedules %d is greater than %d, the maximum amount of schedules currently supported on this platform", - LockParams.numberOfHolidaySchedules, kMaxHolidaySchedules); + LockParams.numberOfHolidaySchedules, APP_MAX_HOLYDAY_SCHEDULE_PER_USER); return APP_ERROR_ALLOCATION_FAILED; } -#if LOCK_MANAGER_CONFIG_USE_NVM_CREDENTIAL_STORAGE - ReadConfigValues(); -#endif - k_timer_init(&mActuatorTimer, &LockManager::ActuatorTimerEventHandler, nullptr); k_timer_user_data_set(&mActuatorTimer, this); @@ -393,7 +400,7 @@ void LockManager::ActuatorAppEventHandler(const AppEvent & event) bool LockManager::IsValidUserIndex(uint16_t userIndex) { - return (userIndex < kMaxUsers); + return (userIndex < APP_MAX_USERS); } bool LockManager::IsValidCredentialIndex(uint16_t credentialIndex, CredentialTypeEnum type) @@ -402,7 +409,7 @@ bool LockManager::IsValidCredentialIndex(uint16_t credentialIndex, CredentialTyp { return (0 == credentialIndex); // 0 is required index for Programming PIN } - return (credentialIndex < kMaxCredentialsPerUser); + return (credentialIndex < APP_MAX_CREDENTIAL); } bool LockManager::IsValidCredentialType(CredentialTypeEnum type) @@ -412,73 +419,61 @@ bool LockManager::IsValidCredentialType(CredentialTypeEnum type) bool LockManager::IsValidWeekdayScheduleIndex(uint8_t scheduleIndex) { - return (scheduleIndex < kMaxWeekdaySchedulesPerUser); + return (scheduleIndex < APP_MAX_WEEKDAY_SCHEDULE_PER_USER); } bool LockManager::IsValidYeardayScheduleIndex(uint8_t scheduleIndex) { - return (scheduleIndex < kMaxYeardaySchedulesPerUser); + return (scheduleIndex < APP_MAX_YEARDAY_SCHEDULE_PER_USER); } bool LockManager::IsValidHolidayScheduleIndex(uint8_t scheduleIndex) { - return (scheduleIndex < kMaxHolidaySchedules); + return (scheduleIndex < APP_MAX_HOLYDAY_SCHEDULE_PER_USER); } -#if LOCK_MANAGER_CONFIG_USE_NVM_CREDENTIAL_STORAGE -bool LockManager::ReadConfigValues() +bool LockManager::GetUser(chip::EndpointId endpointId, uint16_t userIndex, EmberAfPluginDoorLockUserInfo & user) { - size_t outLen; - ZephyrConfig::ReadConfigValueBin(LockSettingsStorage::kConfigKey_LockUser, reinterpret_cast(&mLockUsers), - sizeof(EmberAfPluginDoorLockUserInfo) * ArraySize(mLockUsers), outLen); + VerifyOrReturnValue(userIndex > 0, false); // indices are one-indexed - ZephyrConfig::ReadConfigValueBin(LockSettingsStorage::kConfigKey_LockUserName, reinterpret_cast(mUserNames), - sizeof(mUserNames), outLen); + userIndex--; - ZephyrConfig::ReadConfigValueBin(LockSettingsStorage::kConfigKey_UserCredentials, reinterpret_cast(mCredentials), - sizeof(CredentialStruct) * LockParams.numberOfUsers * LockParams.numberOfCredentialsPerUser, - outLen); + VerifyOrReturnValue(IsValidUserIndex(userIndex), false); - ZephyrConfig::ReadConfigValueBin( - LockSettingsStorage::kConfigKey_WeekDaySchedules, reinterpret_cast(mWeekdaySchedule), - sizeof(EmberAfPluginDoorLockWeekDaySchedule) * LockParams.numberOfWeekdaySchedulesPerUser * LockParams.numberOfUsers, - outLen); + ChipLogProgress(Zcl, "Door Lock App: LockManager::GetUser [endpoint=%d,userIndex=%hu]", endpointId, userIndex); + +#if LOCK_MANAGER_CONFIG_USE_NVM_CREDENTIAL_STORAGE + size_t outLen; - ZephyrConfig::ReadConfigValueBin( - LockSettingsStorage::kConfigKey_YearDaySchedules, reinterpret_cast(mYeardaySchedule), - sizeof(EmberAfPluginDoorLockYearDaySchedule) * LockParams.numberOfYeardaySchedulesPerUser * LockParams.numberOfUsers, - outLen); + auto & userInDb = mCurrentLockUsers; + auto & credentialsInStorage = mCurrentCredentials; + EmberAfPluginDoorLockUserInfo lockUser; + char userNames[DOOR_LOCK_MAX_USER_NAME_SIZE]; - ZephyrConfig::ReadConfigValueBin(LockSettingsStorage::kConfigKey_HolidaySchedules, - reinterpret_cast(&(mHolidaySchedule)), - sizeof(EmberAfPluginDoorLockHolidaySchedule) * LockParams.numberOfHolidaySchedules, outLen); + ZephyrConfig::ReadConfigValueBin(LockSettingsStorage::kConfigKey_LockUser[userIndex], reinterpret_cast(&lockUser), + sizeof(EmberAfPluginDoorLockUserInfo), outLen); + userInDb = lockUser; - for (uint8_t i = 0; i < kNumCredentialTypes; i++) + CredentialStruct credentialsUsers[APP_MAX_CREDENTIAL]; + ZephyrConfig::ReadConfigValueBin(LockSettingsStorage::kConfigKey_UserCredentials[userIndex], + reinterpret_cast(credentialsUsers), + sizeof(CredentialStruct) * LockParams.numberOfCredentialsPerUser, outLen); + for (size_t i = 0; i < userInDb.credentials.size(); ++i) { - ZephyrConfig::ReadConfigValueBin(LockSettingsStorage::kConfigKey_Credential[i], - reinterpret_cast(&mLockCredentials[i]), - sizeof(EmberAfPluginDoorLockCredentialInfo) * kMaxCredentials, outLen); - - ZephyrConfig::ReadConfigValueBin(LockSettingsStorage::kConfigKey_CredentialData[i], - reinterpret_cast(mCredentialData[i]), kMaxCredentials * kMaxCredentialSize, - outLen); + credentialsInStorage[i] = credentialsUsers[i]; } + userInDb.credentials = chip::Span(credentialsInStorage, userInDb.credentials.size()); - return true; -} -#endif + ZephyrConfig::ReadConfigValueBin(LockSettingsStorage::kConfigKey_LockUserName[userIndex], + reinterpret_cast(userNames), sizeof(userNames), outLen); -bool LockManager::GetUser(chip::EndpointId endpointId, uint16_t userIndex, EmberAfPluginDoorLockUserInfo & user) -{ - VerifyOrReturnValue(userIndex > 0, false); // indices are one-indexed - - userIndex--; + chip::Platform::CopyString(mCurrentUserNames, userNames); + userInDb.userName = chip::CharSpan(mCurrentUserNames, userInDb.userName.size()); - VerifyOrReturnValue(IsValidUserIndex(userIndex), false); - - ChipLogProgress(Zcl, "Door Lock App: LockManager::GetUser [endpoint=%d,userIndex=%hu]", endpointId, userIndex); - - const auto & userInDb = mLockUsers[userIndex]; +#else + const auto & userInDb = mLockUsers[userIndex]; + const auto & credentialsInStorage = mCredentials[userIndex]; +#endif user.userStatus = userInDb.userStatus; if (UserStatusEnum::kAvailable == user.userStatus) @@ -488,7 +483,7 @@ bool LockManager::GetUser(chip::EndpointId endpointId, uint16_t userIndex, Ember } user.userName = chip::CharSpan(userInDb.userName.data(), userInDb.userName.size()); - user.credentials = chip::Span(mCredentials[userIndex], userInDb.credentials.size()); + user.credentials = chip::Span(credentialsInStorage, userInDb.credentials.size()); user.userUniqueId = userInDb.userUniqueId; user.userType = userInDb.userType; user.credentialRule = userInDb.credentialRule; @@ -506,7 +501,6 @@ bool LockManager::GetUser(chip::EndpointId endpointId, uint16_t userIndex, Ember endpointId, static_cast(user.userName.size()), user.userName.data(), user.credentials.size(), user.userUniqueId, to_underlying(user.userType), to_underlying(user.credentialRule), user.createdBy, user.lastModifiedBy); - return true; } @@ -527,7 +521,30 @@ bool LockManager::SetUser(chip::EndpointId endpointId, uint16_t userIndex, chip: VerifyOrReturnValue(IsValidUserIndex(userIndex), false); - auto & userInStorage = mLockUsers[userIndex]; +#if LOCK_MANAGER_CONFIG_USE_NVM_CREDENTIAL_STORAGE + size_t outLen; + EmberAfPluginDoorLockUserInfo lockUser; + CredentialStruct credentialsUsers[APP_MAX_CREDENTIAL]; + char userNames[DOOR_LOCK_MAX_USER_NAME_SIZE]; + + ZephyrConfig::ReadConfigValueBin(LockSettingsStorage::kConfigKey_LockUser[userIndex], reinterpret_cast(&lockUser), + sizeof(EmberAfPluginDoorLockUserInfo), outLen); + + ZephyrConfig::ReadConfigValueBin(LockSettingsStorage::kConfigKey_UserCredentials[userIndex], + reinterpret_cast(credentialsUsers), + sizeof(CredentialStruct) * LockParams.numberOfCredentialsPerUser, outLen); + + ZephyrConfig::ReadConfigValueBin(LockSettingsStorage::kConfigKey_LockUserName[userIndex], + reinterpret_cast(userNames), sizeof(userNames), outLen); + + auto & userInStorage = lockUser; + auto & credentialsInStorage = credentialsUsers; + auto & userNamesInStorage = userNames; +#else + auto & userInStorage = mLockUsers[userIndex]; + auto & credentialsInStorage = mCredentials[userIndex]; + auto & userNamesInStorage = mUserNames[userIndex]; +#endif if (userName.size() > DOOR_LOCK_MAX_USER_NAME_SIZE) { @@ -542,8 +559,8 @@ bool LockManager::SetUser(chip::EndpointId endpointId, uint16_t userIndex, chip: return false; } - chip::Platform::CopyString(mUserNames[userIndex], userName); - userInStorage.userName = chip::CharSpan(mUserNames[userIndex], userName.size()); + chip::Platform::CopyString(userNamesInStorage, userName); + userInStorage.userName = chip::CharSpan(userNamesInStorage, userName.size()); userInStorage.userUniqueId = uniqueId; userInStorage.userStatus = userStatus; userInStorage.userType = usertype; @@ -553,33 +570,37 @@ bool LockManager::SetUser(chip::EndpointId endpointId, uint16_t userIndex, chip: for (size_t i = 0; i < totalCredentials; ++i) { - mCredentials[userIndex][i] = credentials[i]; + credentialsInStorage[i] = credentials[i]; } - userInStorage.credentials = chip::Span(mCredentials[userIndex], totalCredentials); + userInStorage.credentials = chip::Span(credentialsInStorage, totalCredentials); #if LOCK_MANAGER_CONFIG_USE_NVM_CREDENTIAL_STORAGE - // Save user information in NVM flash CHIP_ERROR err = - ZephyrConfig::WriteConfigValueBin(LockSettingsStorage::kConfigKey_LockUser, reinterpret_cast(&mLockUsers), - sizeof(EmberAfPluginDoorLockUserInfo) * LockParams.numberOfUsers); + ZephyrConfig::WriteConfigValueBin(LockSettingsStorage::kConfigKey_LockUser[userIndex], + reinterpret_cast(&lockUser), sizeof(EmberAfPluginDoorLockUserInfo)); if (err != CHIP_NO_ERROR) - ChipLogError(Zcl, - "Failed to write kConfigKey_LockUser. User data will be resetted during reboot. Not enough storage space \n"); + { + ChipLogError(Zcl, "Failed to write kConfigKey_LockUser to NVM\n"); + return false; + } - err = ZephyrConfig::WriteConfigValueBin( - LockSettingsStorage::kConfigKey_UserCredentials, reinterpret_cast(mCredentials), - sizeof(CredentialStruct) * LockParams.numberOfUsers * LockParams.numberOfCredentialsPerUser); + err = ZephyrConfig::WriteConfigValueBin(LockSettingsStorage::kConfigKey_UserCredentials[userIndex], + reinterpret_cast(credentialsUsers), + sizeof(CredentialStruct) * LockParams.numberOfCredentialsPerUser); if (err != CHIP_NO_ERROR) - ChipLogError( - Zcl, - "Failed to write kConfigKey_UserCredentials. User data will be resetted during reboot. Not enough storage space \n"); + { + ChipLogError(Zcl, "Failed to write kConfigKey_UserCredentials to NVM\n"); + return false; + } - ZephyrConfig::WriteConfigValueBin(LockSettingsStorage::kConfigKey_LockUserName, reinterpret_cast(mUserNames), - sizeof(mUserNames)); + err = ZephyrConfig::WriteConfigValueBin(LockSettingsStorage::kConfigKey_LockUserName[userIndex], + reinterpret_cast(userNames), sizeof(userNames)); if (err != CHIP_NO_ERROR) - ChipLogError( - Zcl, "Failed to write kConfigKey_LockUserName. User data will be resetted during reboot. Not enough storage space \n"); + { + ChipLogError(Zcl, "Failed to write kConfigKey_LockUserName to NVM\n"); + return false; + } #endif ChipLogProgress(Zcl, "Successfully set the user [mEndpointId=%d,index=%d]", endpointId, userIndex); @@ -590,7 +611,6 @@ bool LockManager::SetUser(chip::EndpointId endpointId, uint16_t userIndex, chip: bool LockManager::GetCredential(chip::EndpointId endpointId, uint16_t credentialIndex, CredentialTypeEnum credentialType, EmberAfPluginDoorLockCredentialInfo & credential) { - VerifyOrReturnValue(IsValidCredentialType(credentialType), false); if (CredentialTypeEnum::kProgrammingPIN == credentialType) @@ -606,7 +626,65 @@ bool LockManager::GetCredential(chip::EndpointId endpointId, uint16_t credential ChipLogProgress(Zcl, "Lock App: LockManager::GetCredential [credentialType=%u], credentialIndex=%d", to_underlying(credentialType), credentialIndex); - const auto & credentialInStorage = mLockCredentials[to_underlying(credentialType)][credentialIndex]; +#if LOCK_MANAGER_CONFIG_USE_NVM_CREDENTIAL_STORAGE + size_t outLen; + EmberAfPluginDoorLockCredentialInfo lockCredentials; + uint8_t lockCredentialsData[kMaxCredentialSize] = { 0 }; + + auto & credentialInStorage = lockCredentials; + + switch (credentialType) + { + case CredentialTypeEnum::kProgrammingPIN: + ChipLogError(Zcl, "CredentialTypeEnum::kProgrammingPIN must not be specified as a new credential\n"); + break; + case CredentialTypeEnum::kPin: + ZephyrConfig::ReadConfigValueBin(LockSettingsStorage::kConfigKey_CredentialPin[credentialIndex], + reinterpret_cast(&lockCredentials), sizeof(EmberAfPluginDoorLockCredentialInfo), + outLen); + ZephyrConfig::ReadConfigValueBin(LockSettingsStorage::kConfigKey_CredentialDataPin[credentialIndex], + reinterpret_cast(lockCredentialsData), kMaxCredentialSize, outLen); + break; + case CredentialTypeEnum::kFace: + ZephyrConfig::ReadConfigValueBin(LockSettingsStorage::kConfigKey_CredentialFace[credentialIndex], + reinterpret_cast(&lockCredentials), sizeof(EmberAfPluginDoorLockCredentialInfo), + outLen); + ZephyrConfig::ReadConfigValueBin(LockSettingsStorage::kConfigKey_CredentialDataFace[credentialIndex], + reinterpret_cast(lockCredentialsData), kMaxCredentialSize, outLen); + break; + case CredentialTypeEnum::kFingerprint: + ZephyrConfig::ReadConfigValueBin(LockSettingsStorage::kConfigKey_CredentialFingerprint[credentialIndex], + reinterpret_cast(&lockCredentials), sizeof(EmberAfPluginDoorLockCredentialInfo), + outLen); + ZephyrConfig::ReadConfigValueBin(LockSettingsStorage::kConfigKey_CredentialDataFingerprint[credentialIndex], + reinterpret_cast(lockCredentialsData), kMaxCredentialSize, outLen); + break; + case CredentialTypeEnum::kFingerVein: + ZephyrConfig::ReadConfigValueBin(LockSettingsStorage::kConfigKey_CredentialFingervein[credentialIndex], + reinterpret_cast(&lockCredentials), sizeof(EmberAfPluginDoorLockCredentialInfo), + outLen); + ZephyrConfig::ReadConfigValueBin(LockSettingsStorage::kConfigKey_CredentialDataFingerVein[credentialIndex], + reinterpret_cast(lockCredentialsData), kMaxCredentialSize, outLen); + break; + case CredentialTypeEnum::kRfid: + ZephyrConfig::ReadConfigValueBin(LockSettingsStorage::kConfigKey_CredentialRfid[credentialIndex], + reinterpret_cast(&lockCredentials), sizeof(EmberAfPluginDoorLockCredentialInfo), + outLen); + ZephyrConfig::ReadConfigValueBin(LockSettingsStorage::kConfigKey_CredentialDataRfid[credentialIndex], + reinterpret_cast(lockCredentialsData), kMaxCredentialSize, outLen); + break; + default: + ChipLogError(Zcl, + "Lock App: LockManager::GetCredential [credentialType=%u], credentialIndex=%d : Credential Type not specified", + to_underlying(credentialType), credentialIndex); + break; + } + + memcpy(mCurrentCredentialData, lockCredentialsData, credentialInStorage.credentialData.size()); + credentialInStorage.credentialData = chip::ByteSpan{ mCurrentCredentialData, credentialInStorage.credentialData.size() }; +#else + const auto & credentialInStorage = mLockCredentials[to_underlying(credentialType)][credentialIndex]; +#endif credential.status = credentialInStorage.status; ChipLogProgress(Zcl, "CredentialStatus: %d, CredentialIndex: %d ", (int) credential.status, credentialIndex); @@ -636,6 +714,11 @@ bool LockManager::SetCredential(chip::EndpointId endpointId, uint16_t credential const chip::ByteSpan & credentialData) { + // TODO: It may be a need to perform a check, if the credential type already exists. + // The credential setter doesn't contain the user index, so the amount of 10 credentials per user can be satisfied only in case, + // if each credential type exists only once per one user. Otherwise, it can be the situation, when one user creates 10 pin + // codes, so the next one user can't create any pincode, but can create the other types of credentials. + VerifyOrReturnValue(IsValidCredentialType(credentialType), false); if (CredentialTypeEnum::kProgrammingPIN == credentialType) @@ -653,35 +736,142 @@ bool LockManager::SetCredential(chip::EndpointId endpointId, uint16_t credential "[credentialStatus=%u,credentialType=%u,credentialDataSize=%u,creator=%d,modifier=%d]", to_underlying(credentialStatus), to_underlying(credentialType), credentialData.size(), creator, modifier); - auto & credentialInStorage = mLockCredentials[to_underlying(credentialType)][credentialIndex]; +#if LOCK_MANAGER_CONFIG_USE_NVM_CREDENTIAL_STORAGE + size_t outLen; + EmberAfPluginDoorLockCredentialInfo lockCredentials; + uint8_t lockCredentialsData[kMaxCredentialSize] = { 0 }; + + switch (credentialType) + { + case CredentialTypeEnum::kProgrammingPIN: + ChipLogError(Zcl, "CredentialTypeEnum::kProgrammingPIN must not be specified as a new credential\n"); + break; + case CredentialTypeEnum::kPin: + ZephyrConfig::ReadConfigValueBin(LockSettingsStorage::kConfigKey_CredentialPin[credentialIndex], + reinterpret_cast(&lockCredentials), sizeof(EmberAfPluginDoorLockCredentialInfo), + outLen); + ZephyrConfig::ReadConfigValueBin(LockSettingsStorage::kConfigKey_CredentialDataPin[credentialIndex], + reinterpret_cast(lockCredentialsData), kMaxCredentialSize, outLen); + break; + case CredentialTypeEnum::kFace: + ZephyrConfig::ReadConfigValueBin(LockSettingsStorage::kConfigKey_CredentialFace[credentialIndex], + reinterpret_cast(&lockCredentials), sizeof(EmberAfPluginDoorLockCredentialInfo), + outLen); + ZephyrConfig::ReadConfigValueBin(LockSettingsStorage::kConfigKey_CredentialDataFace[credentialIndex], + reinterpret_cast(lockCredentialsData), kMaxCredentialSize, outLen); + break; + case CredentialTypeEnum::kFingerprint: + ZephyrConfig::ReadConfigValueBin(LockSettingsStorage::kConfigKey_CredentialFingerprint[credentialIndex], + reinterpret_cast(&lockCredentials), sizeof(EmberAfPluginDoorLockCredentialInfo), + outLen); + ZephyrConfig::ReadConfigValueBin(LockSettingsStorage::kConfigKey_CredentialDataFingerprint[credentialIndex], + reinterpret_cast(lockCredentialsData), kMaxCredentialSize, outLen); + break; + case CredentialTypeEnum::kFingerVein: + ZephyrConfig::ReadConfigValueBin(LockSettingsStorage::kConfigKey_CredentialFingervein[credentialIndex], + reinterpret_cast(&lockCredentials), sizeof(EmberAfPluginDoorLockCredentialInfo), + outLen); + ZephyrConfig::ReadConfigValueBin(LockSettingsStorage::kConfigKey_CredentialDataFingerVein[credentialIndex], + reinterpret_cast(lockCredentialsData), kMaxCredentialSize, outLen); + break; + case CredentialTypeEnum::kRfid: + ZephyrConfig::ReadConfigValueBin(LockSettingsStorage::kConfigKey_CredentialRfid[credentialIndex], + reinterpret_cast(&lockCredentials), sizeof(EmberAfPluginDoorLockCredentialInfo), + outLen); + ZephyrConfig::ReadConfigValueBin(LockSettingsStorage::kConfigKey_CredentialDataRfid[credentialIndex], + reinterpret_cast(lockCredentialsData), kMaxCredentialSize, outLen); + break; + default: + ChipLogError(Zcl, + "Lock App: LockManager::GetCredential [credentialType=%u], credentialIndex=%d : Credential Type not specified", + to_underlying(credentialType), credentialIndex); + break; + } + + auto & credentialInStorage = lockCredentials; + auto & credentialDataInStorage = lockCredentialsData; +#else + auto & credentialInStorage = mLockCredentials[to_underlying(credentialType)][credentialIndex]; + auto & credentialDataInStorage = mCredentialData[to_underlying(credentialType)][credentialIndex]; +#endif credentialInStorage.status = credentialStatus; credentialInStorage.credentialType = credentialType; credentialInStorage.createdBy = creator; credentialInStorage.lastModifiedBy = modifier; - memcpy(mCredentialData[to_underlying(credentialType)][credentialIndex], credentialData.data(), credentialData.size()); - credentialInStorage.credentialData = - chip::ByteSpan{ mCredentialData[to_underlying(credentialType)][credentialIndex], credentialData.size() }; + memcpy(credentialDataInStorage, credentialData.data(), credentialData.size()); + credentialInStorage.credentialData = chip::ByteSpan{ credentialDataInStorage, credentialData.size() }; #if LOCK_MANAGER_CONFIG_USE_NVM_CREDENTIAL_STORAGE - CHIP_ERROR err; + CHIP_ERROR err = CHIP_NO_ERROR; - // Save credential information in NVM flash - err = ZephyrConfig::WriteConfigValueBin(LockSettingsStorage::kConfigKey_Credential[to_underlying(credentialType)], - reinterpret_cast(&mLockCredentials[to_underlying(credentialType)]), - sizeof(EmberAfPluginDoorLockCredentialInfo) * kMaxCredentials); - if (err != CHIP_NO_ERROR) - ChipLogError( - Zcl, "Failed to write kConfigKey_Credential. User data will be resetted during reboot. Not enough storage space \n"); + switch (credentialType) + { + case CredentialTypeEnum::kProgrammingPIN: + ChipLogError(Zcl, "CredentialTypeEnum::kProgrammingPIN must not be specified as a new credential\n"); + break; + case CredentialTypeEnum::kPin: + err = ZephyrConfig::WriteConfigValueBin(LockSettingsStorage::kConfigKey_CredentialPin[credentialIndex], + reinterpret_cast(&lockCredentials), + sizeof(EmberAfPluginDoorLockCredentialInfo)); + if (err != CHIP_NO_ERROR) + break; + + err = ZephyrConfig::WriteConfigValueBin(LockSettingsStorage::kConfigKey_CredentialDataPin[credentialIndex], + reinterpret_cast(lockCredentialsData), kMaxCredentialSize); + break; + case CredentialTypeEnum::kFace: + err = ZephyrConfig::WriteConfigValueBin(LockSettingsStorage::kConfigKey_CredentialFace[credentialIndex], + reinterpret_cast(&lockCredentials), + sizeof(EmberAfPluginDoorLockCredentialInfo)); + if (err != CHIP_NO_ERROR) + break; + + err = ZephyrConfig::WriteConfigValueBin(LockSettingsStorage::kConfigKey_CredentialDataFace[credentialIndex], + reinterpret_cast(lockCredentialsData), kMaxCredentialSize); + break; + case CredentialTypeEnum::kFingerprint: + err = ZephyrConfig::WriteConfigValueBin(LockSettingsStorage::kConfigKey_CredentialFingerprint[credentialIndex], + reinterpret_cast(&lockCredentials), + sizeof(EmberAfPluginDoorLockCredentialInfo)); + if (err != CHIP_NO_ERROR) + break; + + err = ZephyrConfig::WriteConfigValueBin(LockSettingsStorage::kConfigKey_CredentialDataFingerprint[credentialIndex], + reinterpret_cast(lockCredentialsData), kMaxCredentialSize); + break; + case CredentialTypeEnum::kFingerVein: + err = ZephyrConfig::WriteConfigValueBin(LockSettingsStorage::kConfigKey_CredentialFingervein[credentialIndex], + reinterpret_cast(&lockCredentials), + sizeof(EmberAfPluginDoorLockCredentialInfo)); + if (err != CHIP_NO_ERROR) + break; + + err = ZephyrConfig::WriteConfigValueBin(LockSettingsStorage::kConfigKey_CredentialDataFingerVein[credentialIndex], + reinterpret_cast(lockCredentialsData), kMaxCredentialSize); + break; + case CredentialTypeEnum::kRfid: + err = ZephyrConfig::WriteConfigValueBin(LockSettingsStorage::kConfigKey_CredentialRfid[credentialIndex], + reinterpret_cast(&lockCredentials), + sizeof(EmberAfPluginDoorLockCredentialInfo)); + if (err != CHIP_NO_ERROR) + break; + + err = ZephyrConfig::WriteConfigValueBin(LockSettingsStorage::kConfigKey_CredentialDataRfid[credentialIndex], + reinterpret_cast(lockCredentialsData), kMaxCredentialSize); + break; + default: + break; + } - err = ZephyrConfig::WriteConfigValueBin(LockSettingsStorage::kConfigKey_CredentialData[to_underlying(credentialType)], - reinterpret_cast(&mCredentialData[to_underlying(credentialType)]), - kMaxCredentials * kMaxCredentialSize); if (err != CHIP_NO_ERROR) + { ChipLogError( Zcl, "Failed to write kConfigKey_CredentialData. User data will be resetted during reboot. Not enough storage space \n"); + return false; + } #endif ChipLogProgress(Zcl, "Successfully set the credential [credentialType=%u]", to_underlying(credentialType)); @@ -692,7 +882,6 @@ bool LockManager::SetCredential(chip::EndpointId endpointId, uint16_t credential DlStatus LockManager::GetWeekdaySchedule(chip::EndpointId endpointId, uint8_t weekdayIndex, uint16_t userIndex, EmberAfPluginDoorLockWeekDaySchedule & schedule) { - VerifyOrReturnValue(weekdayIndex > 0, DlStatus::kFailure); // indices are one-indexed VerifyOrReturnValue(userIndex > 0, DlStatus::kFailure); // indices are one-indexed @@ -702,7 +891,23 @@ DlStatus LockManager::GetWeekdaySchedule(chip::EndpointId endpointId, uint8_t we VerifyOrReturnValue(IsValidWeekdayScheduleIndex(weekdayIndex), DlStatus::kFailure); VerifyOrReturnValue(IsValidUserIndex(userIndex), DlStatus::kFailure); - const auto & scheduleInStorage = mWeekdaySchedule[userIndex][weekdayIndex]; +#if LOCK_MANAGER_CONFIG_USE_NVM_CREDENTIAL_STORAGE + size_t outLen; + + CHIP_ERROR err = + ZephyrConfig::ReadConfigValueBin(LockSettingsStorage::kConfigKey_WeekDaySchedules[userIndex][weekdayIndex], + reinterpret_cast(&mWeekdaySchedule), sizeof(WeekDaysScheduleInfo), outLen); + if (err != CHIP_NO_ERROR) + { + ChipLogProgress(Zcl, "GetWeekdaySchedule: No schedule found for user: %d at index %d\n", userIndex, weekdayIndex); + return DlStatus::kNotFound; + } + + const auto & scheduleInStorage = mWeekdaySchedule; +#else + const auto & scheduleInStorage = mWeekdaySchedule[userIndex][weekdayIndex]; +#endif + if (DlScheduleStatus::kAvailable == scheduleInStorage.status) { return DlStatus::kNotFound; @@ -717,7 +922,6 @@ DlStatus LockManager::SetWeekdaySchedule(chip::EndpointId endpointId, uint8_t we DlScheduleStatus status, DaysMaskMap daysMask, uint8_t startHour, uint8_t startMinute, uint8_t endHour, uint8_t endMinute) { - VerifyOrReturnValue(weekdayIndex > 0, DlStatus::kFailure); // indices are one-indexed VerifyOrReturnValue(userIndex > 0, DlStatus::kFailure); // indices are one-indexed @@ -727,7 +931,16 @@ DlStatus LockManager::SetWeekdaySchedule(chip::EndpointId endpointId, uint8_t we VerifyOrReturnValue(IsValidWeekdayScheduleIndex(weekdayIndex), DlStatus::kFailure); VerifyOrReturnValue(IsValidUserIndex(userIndex), DlStatus::kFailure); - auto & scheduleInStorage = mWeekdaySchedule[userIndex][weekdayIndex]; +#if LOCK_MANAGER_CONFIG_USE_NVM_CREDENTIAL_STORAGE + size_t outLen; + + ZephyrConfig::ReadConfigValueBin(LockSettingsStorage::kConfigKey_WeekDaySchedules[userIndex][weekdayIndex], + reinterpret_cast(&mWeekdaySchedule), sizeof(WeekDaysScheduleInfo), outLen); + + auto & scheduleInStorage = mWeekdaySchedule; +#else + auto & scheduleInStorage = mWeekdaySchedule[userIndex][weekdayIndex]; +#endif scheduleInStorage.schedule.daysMask = daysMask; scheduleInStorage.schedule.startHour = startHour; @@ -737,14 +950,14 @@ DlStatus LockManager::SetWeekdaySchedule(chip::EndpointId endpointId, uint8_t we scheduleInStorage.status = status; #if LOCK_MANAGER_CONFIG_USE_NVM_CREDENTIAL_STORAGE - // Save schedule information in NVM flash - CHIP_ERROR err = ZephyrConfig::WriteConfigValueBin( - LockSettingsStorage::kConfigKey_WeekDaySchedules, reinterpret_cast(mWeekdaySchedule), - sizeof(EmberAfPluginDoorLockWeekDaySchedule) * LockParams.numberOfWeekdaySchedulesPerUser * LockParams.numberOfUsers); + CHIP_ERROR err = + ZephyrConfig::WriteConfigValueBin(LockSettingsStorage::kConfigKey_WeekDaySchedules[userIndex][weekdayIndex], + reinterpret_cast(&mWeekdaySchedule), sizeof(WeekDaysScheduleInfo)); if (err != CHIP_NO_ERROR) - ChipLogError( - Zcl, - "Failed to write kConfigKey_WeekDaySchedules. User data will be resetted during reboot. Not enough storage space \n"); + { + ChipLogError(Zcl, "Failed to write kConfigKey_WeekDaySchedules to NVM\n"); + return DlStatus::kFailure; + } #endif return DlStatus::kSuccess; @@ -762,7 +975,23 @@ DlStatus LockManager::GetYeardaySchedule(chip::EndpointId endpointId, uint8_t ye VerifyOrReturnValue(IsValidYeardayScheduleIndex(yearDayIndex), DlStatus::kFailure); VerifyOrReturnValue(IsValidUserIndex(userIndex), DlStatus::kFailure); - const auto & scheduleInStorage = mYeardaySchedule[userIndex][yearDayIndex]; +#if LOCK_MANAGER_CONFIG_USE_NVM_CREDENTIAL_STORAGE + size_t outLen; + + CHIP_ERROR err = + ZephyrConfig::ReadConfigValueBin(LockSettingsStorage::kConfigKey_YearDaySchedules[userIndex][yearDayIndex], + reinterpret_cast(&mYeardaySchedule), sizeof(YearDayScheduleInfo), outLen); + if (err != CHIP_NO_ERROR) + { + ChipLogProgress(Zcl, "GetYeardaySchedule: No schedule found for user: %d at index %d\n", userIndex, yearDayIndex); + return DlStatus::kNotFound; + } + + const auto & scheduleInStorage = mYeardaySchedule; +#else + const auto & scheduleInStorage = mYeardaySchedule[userIndex][yearDayIndex]; +#endif + if (DlScheduleStatus::kAvailable == scheduleInStorage.status) { return DlStatus::kNotFound; @@ -785,21 +1014,29 @@ DlStatus LockManager::SetYeardaySchedule(chip::EndpointId endpointId, uint8_t ye VerifyOrReturnValue(IsValidYeardayScheduleIndex(yearDayIndex), DlStatus::kFailure); VerifyOrReturnValue(IsValidUserIndex(userIndex), DlStatus::kFailure); - auto & scheduleInStorage = mYeardaySchedule[userIndex][yearDayIndex]; +#if LOCK_MANAGER_CONFIG_USE_NVM_CREDENTIAL_STORAGE + size_t outLen; + + ZephyrConfig::ReadConfigValueBin(LockSettingsStorage::kConfigKey_YearDaySchedules[userIndex][yearDayIndex], + reinterpret_cast(&mYeardaySchedule), sizeof(YearDayScheduleInfo), outLen); + + auto & scheduleInStorage = mYeardaySchedule; +#else + auto & scheduleInStorage = mYeardaySchedule[userIndex][yearDayIndex]; +#endif scheduleInStorage.schedule.localStartTime = localStartTime; scheduleInStorage.schedule.localEndTime = localEndTime; scheduleInStorage.status = status; #if LOCK_MANAGER_CONFIG_USE_NVM_CREDENTIAL_STORAGE - // Save schedule information in NVM flash - CHIP_ERROR err = ZephyrConfig::WriteConfigValueBin( - LockSettingsStorage::kConfigKey_YearDaySchedules, reinterpret_cast(mYeardaySchedule), - sizeof(EmberAfPluginDoorLockYearDaySchedule) * LockParams.numberOfYeardaySchedulesPerUser * LockParams.numberOfUsers); + CHIP_ERROR err = ZephyrConfig::WriteConfigValueBin(LockSettingsStorage::kConfigKey_YearDaySchedules[userIndex][yearDayIndex], + reinterpret_cast(&mYeardaySchedule), sizeof(YearDayScheduleInfo)); if (err != CHIP_NO_ERROR) - ChipLogError( - Zcl, - "Failed to write kConfigKey_YearDaySchedules. User data will be resetted during reboot. Not enough storage space \n"); + { + ChipLogError(Zcl, "Failed to write kConfigKey_YearDaySchedules to NVM\n"); + return DlStatus::kFailure; + } #endif return DlStatus::kSuccess; @@ -814,7 +1051,23 @@ DlStatus LockManager::GetHolidaySchedule(chip::EndpointId endpointId, uint8_t ho VerifyOrReturnValue(IsValidHolidayScheduleIndex(holidayIndex), DlStatus::kFailure); - const auto & scheduleInStorage = mHolidaySchedule[holidayIndex]; +#if LOCK_MANAGER_CONFIG_USE_NVM_CREDENTIAL_STORAGE + size_t outLen; + + CHIP_ERROR err = + ZephyrConfig::ReadConfigValueBin(LockSettingsStorage::kConfigKey_HolidaySchedules[holidayIndex], + reinterpret_cast(&mHolidaySchedule), sizeof(HolidayScheduleInfo), outLen); + if (err != CHIP_NO_ERROR) + { + ChipLogProgress(Zcl, "GetHolidaySchedule: No schedule found at index %d\n", holidayIndex); + return DlStatus::kNotFound; + } + + const auto & scheduleInStorage = mHolidaySchedule; +#else + const auto & scheduleInStorage = mHolidaySchedule[holidayIndex]; +#endif + if (DlScheduleStatus::kAvailable == scheduleInStorage.status) { return DlStatus::kNotFound; @@ -834,7 +1087,16 @@ DlStatus LockManager::SetHolidaySchedule(chip::EndpointId endpointId, uint8_t ho VerifyOrReturnValue(IsValidHolidayScheduleIndex(holidayIndex), DlStatus::kFailure); - auto & scheduleInStorage = mHolidaySchedule[holidayIndex]; +#if LOCK_MANAGER_CONFIG_USE_NVM_CREDENTIAL_STORAGE + size_t outLen; + + ZephyrConfig::ReadConfigValueBin(LockSettingsStorage::kConfigKey_HolidaySchedules[holidayIndex], + reinterpret_cast(&mHolidaySchedule), sizeof(HolidayScheduleInfo), outLen); + + auto & scheduleInStorage = mHolidaySchedule; +#else + auto & scheduleInStorage = mHolidaySchedule[holidayIndex]; +#endif scheduleInStorage.schedule.localStartTime = localStartTime; scheduleInStorage.schedule.localEndTime = localEndTime; @@ -842,14 +1104,13 @@ DlStatus LockManager::SetHolidaySchedule(chip::EndpointId endpointId, uint8_t ho scheduleInStorage.status = status; #if LOCK_MANAGER_CONFIG_USE_NVM_CREDENTIAL_STORAGE - // Save schedule information in NVM flash - CHIP_ERROR err = ZephyrConfig::WriteConfigValueBin( - LockSettingsStorage::kConfigKey_HolidaySchedules, reinterpret_cast(&(mHolidaySchedule)), - sizeof(EmberAfPluginDoorLockHolidaySchedule) * LockParams.numberOfHolidaySchedules); + CHIP_ERROR err = ZephyrConfig::WriteConfigValueBin(LockSettingsStorage::kConfigKey_HolidaySchedules[holidayIndex], + reinterpret_cast(&mHolidaySchedule), sizeof(HolidayScheduleInfo)); if (err != CHIP_NO_ERROR) - ChipLogError( - Zcl, - "Failed to write kConfigKey_YearDaySchedules. User data will be resetted during reboot. Not enough storage space \n"); + { + ChipLogError(Zcl, "Failed to write kConfigKey_HolidaySchedules to NVM\n"); + return DlStatus::kFailure; + } #endif return DlStatus::kSuccess; @@ -904,9 +1165,27 @@ bool LockManager::setLockState(chip::EndpointId endpointId, DlLockState lockStat err = OperationErrorEnum::kRestricted; return false; } - // Check the PIN code + +#if LOCK_MANAGER_CONFIG_USE_NVM_CREDENTIAL_STORAGE + size_t outLen; + EmberAfPluginDoorLockCredentialInfo lockCredentials; + uint8_t lockCredentialsData[kMaxCredentialSize]; + + for (uint8_t credentialDataIdx = 0; credentialDataIdx < APP_MAX_CREDENTIAL; credentialDataIdx++) + { + ZephyrConfig::ReadConfigValueBin(LockSettingsStorage::kConfigKey_CredentialPin[credentialDataIdx], + reinterpret_cast(&lockCredentials), sizeof(EmberAfPluginDoorLockCredentialInfo), + outLen); + ZephyrConfig::ReadConfigValueBin(LockSettingsStorage::kConfigKey_CredentialDataPin[credentialDataIdx], + reinterpret_cast(lockCredentialsData), kMaxCredentialSize, outLen); + + auto & currentCredential = lockCredentials; + auto & credentialDataInStorage = lockCredentialsData; + currentCredential.credentialData = chip::ByteSpan{ credentialDataInStorage, currentCredential.credentialData.size() }; +#else for (const auto & currentCredential : mLockCredentials[to_underlying(CredentialTypeEnum::kPin)]) { +#endif if (currentCredential.status == DlCredentialStatus::kAvailable) { continue; @@ -915,7 +1194,7 @@ bool LockManager::setLockState(chip::EndpointId endpointId, DlLockState lockStat if (currentCredential.credentialData.data_equal(pin.Value())) { - for (uint16_t i = 1; i <= kMaxUsers; ++i) + for (uint16_t i = 1; i <= APP_MAX_USERS; ++i) { EmberAfPluginDoorLockUserInfo user; if (!emberAfPluginDoorLockGetUser(endpointId, i, user)) diff --git a/examples/lock-app/telink/src/LockSettingsStorage.cpp b/examples/lock-app/telink/src/LockSettingsStorage.cpp index 73b88e2c593dea..bb128de87ec04a 100644 --- a/examples/lock-app/telink/src/LockSettingsStorage.cpp +++ b/examples/lock-app/telink/src/LockSettingsStorage.cpp @@ -38,20 +38,65 @@ namespace Internal { #define NAMESPACE_CONFIG CHIP_DEVICE_CONFIG_SETTINGS_KEY "/cfg/" -const ZephyrConfig::Key LockSettingsStorage::kConfigKey_LockUser = CONFIG_KEY(NAMESPACE_CONFIG "lock-user"); -const ZephyrConfig::Key LockSettingsStorage::kConfigKey_LockUserName = CONFIG_KEY(NAMESPACE_CONFIG "lock-user-name"); -const ZephyrConfig::Key LockSettingsStorage::kConfigKey_UserCredentials = CONFIG_KEY(NAMESPACE_CONFIG "user-credentials"); -const ZephyrConfig::Key LockSettingsStorage::kConfigKey_WeekDaySchedules = CONFIG_KEY(NAMESPACE_CONFIG "week-day-schedules"); -const ZephyrConfig::Key LockSettingsStorage::kConfigKey_YearDaySchedules = CONFIG_KEY(NAMESPACE_CONFIG "year-day-schedules"); -const ZephyrConfig::Key LockSettingsStorage::kConfigKey_HolidaySchedules = CONFIG_KEY(NAMESPACE_CONFIG "holiday-schedules"); -const char * LockSettingsStorage::kConfigKey_Credential[kNumCredentialTypes] = { - CONFIG_KEY_CREDENTIAL("programming-pin"), CONFIG_KEY_CREDENTIAL("pin"), CONFIG_KEY_CREDENTIAL("rfid"), - CONFIG_KEY_CREDENTIAL("finger-print"), CONFIG_KEY_CREDENTIAL("finger-vein"), CONFIG_KEY_CREDENTIAL("face") -}; -const char * LockSettingsStorage::kConfigKey_CredentialData[kNumCredentialTypes] = { - CONFIG_KEY_CREDENTIAL_DATA("programming-pin"), CONFIG_KEY_CREDENTIAL_DATA("pin"), CONFIG_KEY_CREDENTIAL_DATA("rfid"), - CONFIG_KEY_CREDENTIAL_DATA("finger-print"), CONFIG_KEY_CREDENTIAL_DATA("finger-vein"), CONFIG_KEY_CREDENTIAL_DATA("face") -}; +#define CONFIG_KEY_USER(index, _) (NAMESPACE_CONFIG "lock-user-" #index) +#define CONFIG_KEY_USER_NAMES(index, _) (NAMESPACE_CONFIG "lock-user-name-" #index) +#define CONFIG_KEY_USER_CREDENTIALS(index, _) (NAMESPACE_CONFIG "user-credentials-" #index) +#define CONFIG_KEY_WEEK_DAY_SCH(index, _) (NAMESPACE_CONFIG "week-day-schedules-" #index) +#define CONFIG_KEY_YEAR_DAY_SCH(index, _) (NAMESPACE_CONFIG "year-day-schedules-" #index) +#define CONFIG_KEY_HOLYDAY_SCH(index, _) (NAMESPACE_CONFIG "holiday-schedules-" #index) + +#define CONFIG_KEY_CREDENTIALS_PIN(index, _) (NAMESPACE_CONFIG "credentials-pin" #index) +#define CONFIG_KEY_CREDENTIALS_FACE(index, _) (NAMESPACE_CONFIG "credentials-face" #index) +#define CONFIG_KEY_CREDENTIALS_FINGERPTRINT(index, _) (NAMESPACE_CONFIG "credentials-fp" #index) +#define CONFIG_KEY_CREDENTIALS_FINGERVEIN(index, _) (NAMESPACE_CONFIG "credentials-fv" #index) +#define CONFIG_KEY_CREDENTIALS_RFID(index, _) (NAMESPACE_CONFIG "credentials-rfid" #index) + +#define CONFIG_KEY_USER_CREDENTIALS_DATA_PIN(index, _) (NAMESPACE_CONFIG "credentials-datapin-" #index) +#define CONFIG_KEY_USER_CREDENTIALS_DATA_FACE(index, _) (NAMESPACE_CONFIG "credentials-dataface-" #index) +#define CONFIG_KEY_USER_CREDENTIALS_DATA_FINGERPTRINT(index, _) (NAMESPACE_CONFIG "credentials-datafp-" #index) +#define CONFIG_KEY_USER_CREDENTIALS_DATA_FINGERVEIN(index, _) (NAMESPACE_CONFIG "credentials-datafv-" #index) +#define CONFIG_KEY_USER_CREDENTIALS_DATA_RFID(index, _) (NAMESPACE_CONFIG "credentials-datarfid-" #index) + +const char * LockSettingsStorage::kConfigKey_LockUser[APP_MAX_USERS] = { LISTIFY(APP_MAX_USERS, CONFIG_KEY_USER, (, )) }; +const char * LockSettingsStorage::kConfigKey_LockUserName[APP_MAX_USERS] = { LISTIFY(APP_MAX_USERS, CONFIG_KEY_USER_NAMES, (, )) }; +const char * LockSettingsStorage::kConfigKey_UserCredentials[APP_MAX_CREDENTIAL] = { LISTIFY(APP_MAX_CREDENTIAL, + CONFIG_KEY_USER_CREDENTIALS, (, )) }; +const char * LockSettingsStorage::kConfigKey_WeekDaySchedules[APP_MAX_USERS][APP_MAX_WEEKDAY_SCHEDULE_PER_USER] = { LISTIFY( + APP_MAX_SCHEDULES_TOTAL, CONFIG_KEY_WEEK_DAY_SCH, (, )) }; +const char * LockSettingsStorage::kConfigKey_YearDaySchedules[APP_MAX_USERS][APP_MAX_YEARDAY_SCHEDULE_PER_USER] = { LISTIFY( + APP_MAX_SCHEDULES_TOTAL, CONFIG_KEY_YEAR_DAY_SCH, (, )) }; +const char * LockSettingsStorage::kConfigKey_HolidaySchedules[APP_MAX_HOLYDAY_SCHEDULE_PER_USER] = { LISTIFY( + APP_MAX_HOLYDAY_SCHEDULE_PER_USER, CONFIG_KEY_HOLYDAY_SCH, (, )) }; + +const char * LockSettingsStorage::kConfigKey_CredentialPin[APP_MAX_CREDENTIAL] = { LISTIFY(APP_MAX_CREDENTIAL, + CONFIG_KEY_CREDENTIALS_PIN, (, )) }; + +const char * LockSettingsStorage::kConfigKey_CredentialFace[APP_MAX_CREDENTIAL] = { LISTIFY(APP_MAX_CREDENTIAL, + CONFIG_KEY_CREDENTIALS_FACE, (, )) }; + +const char * LockSettingsStorage::kConfigKey_CredentialFingerprint[APP_MAX_CREDENTIAL] = { LISTIFY( + APP_MAX_CREDENTIAL, CONFIG_KEY_CREDENTIALS_FINGERPTRINT, (, )) }; + +const char * LockSettingsStorage::kConfigKey_CredentialFingervein[APP_MAX_CREDENTIAL] = { LISTIFY( + APP_MAX_CREDENTIAL, CONFIG_KEY_CREDENTIALS_FINGERVEIN, (, )) }; + +const char * LockSettingsStorage::kConfigKey_CredentialRfid[APP_MAX_CREDENTIAL] = { LISTIFY(APP_MAX_CREDENTIAL, + CONFIG_KEY_CREDENTIALS_RFID, (, )) }; + +const char * LockSettingsStorage::kConfigKey_CredentialDataPin[APP_MAX_CREDENTIAL] = { LISTIFY( + APP_MAX_CREDENTIAL, CONFIG_KEY_USER_CREDENTIALS_DATA_PIN, (, )) }; + +const char * LockSettingsStorage::kConfigKey_CredentialDataFace[APP_MAX_CREDENTIAL] = { LISTIFY( + APP_MAX_CREDENTIAL, CONFIG_KEY_USER_CREDENTIALS_DATA_FACE, (, )) }; + +const char * LockSettingsStorage::kConfigKey_CredentialDataFingerprint[APP_MAX_CREDENTIAL] = { LISTIFY( + APP_MAX_CREDENTIAL, CONFIG_KEY_USER_CREDENTIALS_DATA_FINGERPTRINT, (, )) }; + +const char * LockSettingsStorage::kConfigKey_CredentialDataFingerVein[APP_MAX_CREDENTIAL] = { LISTIFY( + APP_MAX_CREDENTIAL, CONFIG_KEY_USER_CREDENTIALS_DATA_FINGERVEIN, (, )) }; + +const char * LockSettingsStorage::kConfigKey_CredentialDataRfid[APP_MAX_CREDENTIAL] = { LISTIFY( + APP_MAX_CREDENTIAL, CONFIG_KEY_USER_CREDENTIALS_DATA_RFID, (, )) }; } // namespace Internal } // namespace DeviceLayer diff --git a/examples/placeholder/templates/tests-commands.zapt b/examples/placeholder/templates/tests-commands.zapt index c1d87417bc5906..be0474f4632605 100644 --- a/examples/placeholder/templates/tests-commands.zapt +++ b/examples/placeholder/templates/tests-commands.zapt @@ -4,7 +4,7 @@ #include "TestCommand.h" -#include +#include {{>test_cluster tests="../linux/apps/app1/ciTests.json" credsIssuerConfigArg=false needsWaitDuration=false}} diff --git a/examples/tv-casting-app/android/App/app/src/main/jni/cpp/TvCastingApp-JNI.cpp b/examples/tv-casting-app/android/App/app/src/main/jni/cpp/TvCastingApp-JNI.cpp index 0d493965e21829..0cbfab8b5864b8 100644 --- a/examples/tv-casting-app/android/App/app/src/main/jni/cpp/TvCastingApp-JNI.cpp +++ b/examples/tv-casting-app/android/App/app/src/main/jni/cpp/TvCastingApp-JNI.cpp @@ -22,6 +22,7 @@ #include "ConversionUtils.h" #include "JNIDACProvider.h" +#include #include #include #include @@ -32,7 +33,6 @@ #include #include #include -#include #include #include diff --git a/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/CastingServerBridge.mm b/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/CastingServerBridge.mm index b19d72097f7ecc..86a1976aed7d18 100644 --- a/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/CastingServerBridge.mm +++ b/examples/tv-casting-app/darwin/MatterTvCastingBridge/MatterTvCastingBridge/CastingServerBridge.mm @@ -25,10 +25,10 @@ #import "MatterCallbacks.h" #import "OnboardingPayload.h" +#include #include #include #include -#include #include #include diff --git a/scripts/tools/check_includes_config.py b/scripts/tools/check_includes_config.py index abe2c0ed42f5af..b4e933f193583c 100644 --- a/scripts/tools/check_includes_config.py +++ b/scripts/tools/check_includes_config.py @@ -93,7 +93,7 @@ 'vector', # CHIP headers using STL containers. - 'lib/support/CHIPListUtils.h', # uses std::set + 'app/data-model/ListLargeSystemExtensions.h', # uses std::set 'src/platform/DeviceSafeQueue.h', # uses std::deque } @@ -113,7 +113,7 @@ 'src/lib/support/IniEscaping.h': {'string'}, # Itself in DENY. - 'src/lib/support/CHIPListUtils.h': {'set'}, + 'src/app/data-model/ListLargeSystemExtensions.h': {'set'}, 'src/platform/DeviceSafeQueue.h': {'queue'}, # Only uses for zero-cost types. diff --git a/src/app/clusters/door-lock-server/door-lock-server.h b/src/app/clusters/door-lock-server/door-lock-server.h index 675a1450baf28a..b17e20e446437d 100644 --- a/src/app/clusters/door-lock-server/door-lock-server.h +++ b/src/app/clusters/door-lock-server/door-lock-server.h @@ -723,9 +723,9 @@ enum class DlAssetSource : uint8_t */ struct EmberAfPluginDoorLockCredentialInfo { - DlCredentialStatus status; /**< Indicates if credential slot is occupied or not. */ - CredentialTypeEnum credentialType; /**< Specifies the type of the credential (PIN, RFID, etc.). */ - chip::ByteSpan credentialData; /**< Credential data bytes. */ + DlCredentialStatus status = DlCredentialStatus::kAvailable; /**< Indicates if credential slot is occupied or not. */ + CredentialTypeEnum credentialType; /**< Specifies the type of the credential (PIN, RFID, etc.). */ + chip::ByteSpan credentialData; /**< Credential data bytes. */ DlAssetSource creationSource; chip::FabricIndex createdBy; /**< Index of the fabric that created the user. */ diff --git a/src/lib/support/CHIPListUtils.h b/src/app/data-model/ListLargeSystemExtensions.h similarity index 90% rename from src/lib/support/CHIPListUtils.h rename to src/app/data-model/ListLargeSystemExtensions.h index 95e063a49581b7..fca49dd698939a 100644 --- a/src/lib/support/CHIPListUtils.h +++ b/src/app/data-model/ListLargeSystemExtensions.h @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2021 Project CHIP Authors + * Copyright (c) 2024 Project CHIP Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,10 +15,12 @@ * limitations under the License. */ -#ifndef CHIP_LISTUTILS_INTERNAL_H -#define CHIP_LISTUTILS_INTERNAL_H +#pragma once +// NOTE: Functionality in this class uses HEAP and std::set. It is generally +// intended for large systems only #include + #include #include @@ -27,6 +29,7 @@ template struct ListMemberTypeGetter { }; + template struct ListMemberTypeGetter> { @@ -63,5 +66,3 @@ struct ListFreer std::set mListHolders; }; - -#endif /* CHIP_LISTUTILS_INTERNAL_H */ diff --git a/src/app/server/BUILD.gn b/src/app/server/BUILD.gn index 690da2354071cc..7e441518c9b133 100644 --- a/src/app/server/BUILD.gn +++ b/src/app/server/BUILD.gn @@ -62,6 +62,11 @@ static_library("server") { "${chip_root}/src/transport", ] + # TODO: Server.cpp uses TestGroupData.h. Unsure why test code would be in such a central place + # This dependency is split since it should probably be removed (or naming should + # be updated if this is not really "testing" even though headers are Test*.h) + public_deps += [ "${chip_root}/src/lib/support:testing" ] + if (chip_enable_icd_server) { public_deps += [ "${chip_root}/src/app/icd/server:notifier" ] } diff --git a/src/app/tests/BUILD.gn b/src/app/tests/BUILD.gn index 88311e2b414e58..245e939fc39799 100644 --- a/src/app/tests/BUILD.gn +++ b/src/app/tests/BUILD.gn @@ -213,6 +213,7 @@ chip_test_suite_using_nltest("tests") { "${chip_root}/src/app/util/mock:mock_ember", "${chip_root}/src/lib/core", "${chip_root}/src/lib/support:test_utils", + "${chip_root}/src/lib/support:testing", "${chip_root}/src/lib/support:testing_nlunit", "${nlunit_test_root}:nlunit-test", ] diff --git a/src/app/tests/suites/certification/Test_TC_IDM_1_3.yaml b/src/app/tests/suites/certification/Test_TC_IDM_1_3.yaml index 3cd059db6e8e73..de5625a8d11ad4 100644 --- a/src/app/tests/suites/certification/Test_TC_IDM_1_3.yaml +++ b/src/app/tests/suites/certification/Test_TC_IDM_1_3.yaml @@ -46,7 +46,7 @@ tests: test step can be simulated using chip-repl (when DUT is a commissioner/Client). The cluster used in the below command is an example, User can use any supported chip cluster/attribute/command. Note in this example the unique path is created by using 2 different endpoints. - `await devCtrl.SendBatchCommands(0x12344321, [Clusters.Command.InvokeRequestInfo(1, Clusters.OnOff.Commands.Toggle()), Clusters.Command.InvokeRequestInfo(2, Clusters.OnOff.Commands.Toggle())]` + `await devCtrl.SendBatchCommands(0x12344321, [chip.clusters.Command.InvokeRequestInfo(1, chip.clusters.OnOff.Commands.Toggle()), chip.clusters.Command.InvokeRequestInfo(2, chip.clusters.OnOff.Commands.Toggle())])` On TH(all-clusters-app), Verify that the EndpointIDs, CommandIDs, ClusterIDs in the InvokeRequestMessage (as below) matching with the data sent in the above command @@ -110,7 +110,7 @@ tests: test step can be simulated using chip-repl (when DUT is a commissioner/Client). The cluster used in the below command is an example, User can use any supported chip cluster/attribute/command. Note in this example the unique path is created by using 2 different endpoints. - `await devCtrl.SendBatchCommands(0x12344321, [Clusters.Command.InvokeRequestInfo(1, Clusters.OnOff.Commands.Toggle()), Clusters.Command.InvokeRequestInfo(2, Clusters.OnOff.Commands.Toggle())]` + `await devCtrl.SendBatchCommands(0x12344321, [chip.clusters.Command.InvokeRequestInfo(1, chip.clusters.OnOff.Commands.Toggle()), chip.clusters.Command.InvokeRequestInfo(2, chip.clusters.OnOff.Commands.Toggle())])` Verify DUT doesn't crash by seeing next step execute. disabled: true @@ -131,7 +131,7 @@ tests: test step can be simulated using chip-repl (when DUT is a commissioner/Client). The cluster used in the below command is an example, User can use any supported chip cluster/attribute/command. Note in this example the unique path is created by using 2 different endpoints. - `await devCtrl.SendBatchCommands(0x12344321, [Clusters.Command.InvokeRequestInfo(1, Clusters.OnOff.Commands.Toggle()), Clusters.Command.InvokeRequestInfo(2, Clusters.OnOff.Commands.Toggle())]` + `await devCtrl.SendBatchCommands(0x12344321, [chip.clusters.Command.InvokeRequestInfo(1, chip.clusters.OnOff.Commands.Toggle()), chip.clusters.Command.InvokeRequestInfo(2, chip.clusters.OnOff.Commands.Toggle())])` Verify DUT doesn't crash by seeing next step execute. disabled: true @@ -152,7 +152,7 @@ tests: test step can be simulated using chip-repl (when DUT is a commissioner/Client). The cluster used in the below command is an example, User can use any supported chip cluster/attribute/command. Note in this example the unique path is created by using 2 different endpoints. - `await devCtrl.SendBatchCommands(0x12344321, [Clusters.Command.InvokeRequestInfo(1, Clusters.OnOff.Commands.Toggle()), Clusters.Command.InvokeRequestInfo(2, Clusters.OnOff.Commands.Toggle())]` + `await devCtrl.SendBatchCommands(0x12344321, [chip.clusters.Command.InvokeRequestInfo(1, chip.clusters.OnOff.Commands.Toggle()), chip.clusters.Command.InvokeRequestInfo(2, chip.clusters.OnOff.Commands.Toggle())])` Verify DUT doesn't crash by seeing next step execute. disabled: true @@ -169,7 +169,7 @@ tests: test step can be simulated using chip-repl (when DUT is a commissioner/Client). The cluster used in the below command is an example, User can use any supported chip cluster/attribute/command. Note in this example the unique path is created by using 2 different endpoints. - `await devCtrl.SendCommands(0x12344321, 1, Clusters.OnOff.Commands.Toggle())` + `await devCtrl.SendCommand(0x12344321, 1, chip.clusters.OnOff.Commands.Toggle())` On TH(all-clusters-app), Verify that we recieves an InvokeRequestMessage that contains a single InvokeRequests diff --git a/src/app/zap-templates/zcl/data-model/chip/drlc-cluster.xml b/src/app/zap-templates/zcl/data-model/chip/drlc-cluster.xml index fdffc7d58d051c..dce7ff59f3fdac 100644 --- a/src/app/zap-templates/zcl/data-model/chip/drlc-cluster.xml +++ b/src/app/zap-templates/zcl/data-model/chip/drlc-cluster.xml @@ -15,7 +15,7 @@ See the License for the specific language governing permissions and limitations under the License. --> - + @@ -177,7 +177,7 @@ limitations under the License. Demand Response Load Control - Energy + Energy Management This cluster provides an interface to the functionality of Smart Energy Demand Response and Load Control. 0x0096 DEMAND_RESPONSE_LOAD_CONTROL_CLUSTER diff --git a/src/controller/BUILD.gn b/src/controller/BUILD.gn index 435e405c299c97..9742bf05684b3c 100644 --- a/src/controller/BUILD.gn +++ b/src/controller/BUILD.gn @@ -81,5 +81,10 @@ static_library("controller") { deps = [ "${chip_root}/src/lib/address_resolve" ] + if (chip_controller && chip_build_controller) { + # ExampleOperationalCredentialsIssuer uses TestGroupData + deps += [ "${chip_root}/src/lib/support:testing" ] + } + defines = [] } diff --git a/src/controller/python/BUILD.gn b/src/controller/python/BUILD.gn index c8d2ac32779726..e14b7127dec68d 100644 --- a/src/controller/python/BUILD.gn +++ b/src/controller/python/BUILD.gn @@ -130,6 +130,7 @@ shared_library("ChipDeviceCtrl") { public_deps += [ "${chip_root}/src/controller/data_model", "${chip_root}/src/credentials:file_attestation_trust_store", + "${chip_root}/src/lib/support:testing", "${chip_root}/src/tracing/json", "${chip_root}/src/tracing/perfetto", "${chip_root}/src/tracing/perfetto:file_output", diff --git a/src/credentials/tests/BUILD.gn b/src/credentials/tests/BUILD.gn index 101abc31dd890e..3b0458233ac757 100644 --- a/src/credentials/tests/BUILD.gn +++ b/src/credentials/tests/BUILD.gn @@ -70,6 +70,7 @@ chip_test_suite_using_nltest("tests") { "${chip_root}/src/credentials", "${chip_root}/src/credentials:default_attestation_verifier", "${chip_root}/src/lib/core", + "${chip_root}/src/lib/support:testing", "${chip_root}/src/lib/support:testing_nlunit", "${nlunit_test_root}:nlunit-test", ] diff --git a/src/crypto/tests/BUILD.gn b/src/crypto/tests/BUILD.gn index 55fc502484c681..1599b942269ae6 100644 --- a/src/crypto/tests/BUILD.gn +++ b/src/crypto/tests/BUILD.gn @@ -69,6 +69,7 @@ chip_test_suite_using_nltest("tests") { "${chip_root}/src/credentials/tests:cert_test_vectors", "${chip_root}/src/crypto", "${chip_root}/src/lib/core", + "${chip_root}/src/lib/support:testing", "${chip_root}/src/lib/support:testing_nlunit", "${chip_root}/src/platform", "${nlunit_test_root}:nlunit-test", diff --git a/src/darwin/Framework/CHIP/templates/MTRBaseClusters-src.zapt b/src/darwin/Framework/CHIP/templates/MTRBaseClusters-src.zapt index de92791826c666..9d6e786ce03149 100644 --- a/src/darwin/Framework/CHIP/templates/MTRBaseClusters-src.zapt +++ b/src/darwin/Framework/CHIP/templates/MTRBaseClusters-src.zapt @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include diff --git a/src/darwin/Framework/CHIP/templates/MTRCommandPayloadsObjc-src.zapt b/src/darwin/Framework/CHIP/templates/MTRCommandPayloadsObjc-src.zapt index c58c75f77d9d38..783fe2aff9555f 100644 --- a/src/darwin/Framework/CHIP/templates/MTRCommandPayloadsObjc-src.zapt +++ b/src/darwin/Framework/CHIP/templates/MTRCommandPayloadsObjc-src.zapt @@ -12,7 +12,7 @@ #include #include -#include +#include #include #include diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.mm b/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.mm index cdb3a18b67c06b..9900b52d1c311f 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.mm +++ b/src/darwin/Framework/CHIP/zap-generated/MTRBaseClusters.mm @@ -30,9 +30,9 @@ #import "NSStringSpanConversion.h" #include +#include #include #include -#include #include #include diff --git a/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.mm b/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.mm index 6e7f500929877d..0e172b2118b5fc 100644 --- a/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.mm +++ b/src/darwin/Framework/CHIP/zap-generated/MTRCommandPayloadsObjc.mm @@ -26,8 +26,8 @@ #import "NSStringSpanConversion.h" #include +#include #include -#include #include #include diff --git a/src/lib/core/BUILD.gn b/src/lib/core/BUILD.gn index eb66f46fd8aa8d..27611376c10069 100644 --- a/src/lib/core/BUILD.gn +++ b/src/lib/core/BUILD.gn @@ -101,6 +101,7 @@ source_set("error") { public_deps = [ ":chip_config_header", "${chip_root}/src/lib/support:attributes", + "${chip_root}/src/lib/support:type-traits", ] } diff --git a/src/lib/support/BUILD.gn b/src/lib/support/BUILD.gn index 410f3beaf21141..3e426746ad3d2b 100644 --- a/src/lib/support/BUILD.gn +++ b/src/lib/support/BUILD.gn @@ -160,6 +160,17 @@ source_set("chip_version_header") { deps = [ ":gen_chip_version" ] } +source_set("testing") { + sources = [ + "TestGroupData.h", + "TestPersistentStorageDelegate.h", + ] +} + +source_set("type-traits") { + sources = [ "TypeTraits.h" ] +} + static_library("support") { output_name = "libSupportLayer" @@ -179,6 +190,8 @@ static_library("support") { "CHIPArgParser.cpp", "CHIPCounter.h", "CHIPMemString.h", + "CommonIterator.h", + "CommonPersistentData.h", "DLLUtil.h", "DefaultStorageKeyAllocator.h", "Defer.h", @@ -186,21 +199,31 @@ static_library("support") { "FibonacciUtils.h", "FixedBufferAllocator.cpp", "FixedBufferAllocator.h", + "Fold.h", + "FunctionTraits.h", "IniEscaping.cpp", "IniEscaping.h", + "IntrusiveList.h", "Iterators.h", + "LambdaBridge.h", "LifetimePersistedCounter.h", "ObjectLifeCycle.h", + "OwnerOf.h", "PersistedCounter.h", + "PersistentData.h", "PersistentStorageAudit.cpp", "PersistentStorageAudit.h", "PersistentStorageMacros.h", "Pool.cpp", "Pool.h", + "PoolWrapper.h", "PrivateHeap.cpp", "PrivateHeap.h", "ReferenceCountedHandle.h", + "SafePointerCast.h", + "SafeString.h", "Scoped.h", + "ScopedBuffer.h", "SerializableIntegerSet.cpp", "SerializableIntegerSet.h", "SetupDiscriminator.h", @@ -252,6 +275,7 @@ static_library("support") { ":safeint", ":span", ":text_only_logging", + ":type-traits", ":verifymacros", ":verifymacros_no_logging", "${chip_root}/src/lib/core:chip_config_header", @@ -335,6 +359,7 @@ static_library("testing_nlunit") { output_dir = "${root_out_dir}/lib" sources = [ + "UnitTestContext.h", "UnitTestExtendedAssertions.h", "UnitTestRegistration.cpp", "UnitTestRegistration.h", diff --git a/src/lib/support/tests/BUILD.gn b/src/lib/support/tests/BUILD.gn index 7a3b738ef4491a..d0b91feeba7061 100644 --- a/src/lib/support/tests/BUILD.gn +++ b/src/lib/support/tests/BUILD.gn @@ -79,6 +79,7 @@ chip_test_suite_using_nltest("tests") { public_deps = [ "${chip_root}/src/credentials", "${chip_root}/src/lib/core", + "${chip_root}/src/lib/support:testing", "${chip_root}/src/lib/support:testing_nlunit", "${chip_root}/src/lib/support/jsontlv", "${chip_root}/src/platform", diff --git a/src/messaging/BUILD.gn b/src/messaging/BUILD.gn index 7d402e78ee2306..b2c053f70a28c6 100644 --- a/src/messaging/BUILD.gn +++ b/src/messaging/BUILD.gn @@ -45,6 +45,7 @@ static_library("messaging") { sources = [ "ApplicationExchangeDispatch.cpp", "ApplicationExchangeDispatch.h", + "EphemeralExchangeDispatch.h", "ErrorCategory.cpp", "ErrorCategory.h", "ExchangeContext.cpp", diff --git a/src/messaging/tests/BUILD.gn b/src/messaging/tests/BUILD.gn index b3f41b6bb08457..b6f1dcb02c5ce7 100644 --- a/src/messaging/tests/BUILD.gn +++ b/src/messaging/tests/BUILD.gn @@ -32,6 +32,7 @@ static_library("helpers") { deps = [ "${chip_root}/src/credentials/tests:cert_test_vectors", + "${chip_root}/src/lib/support:testing", "${chip_root}/src/messaging", "${chip_root}/src/protocols", "${chip_root}/src/transport", diff --git a/src/platform/telink/1m_flash.overlay b/src/platform/telink/1m_flash.overlay index 0b1fd1b2213c23..3a05c3cd43b8d0 100644 --- a/src/platform/telink/1m_flash.overlay +++ b/src/platform/telink/1m_flash.overlay @@ -21,15 +21,15 @@ }; slot0_partition: partition@19000 { label = "image-0"; - reg = <0x19000 0xda000>; + reg = <0x19000 0xd9000>; }; - factory_partition: partition@f3000 { + factory_partition: partition@f2000 { label = "factory-data"; - reg = <0xf3000 0x1000>; + reg = <0xf2000 0x1000>; }; - storage_partition: partition@f4000 { + storage_partition: partition@f3000 { label = "storage"; - reg = <0xf4000 0xa000>; + reg = <0xf3000 0xb000>; }; vendor_partition: partition@fe000 { label = "vendor-data"; diff --git a/src/platform/telink/2m_flash.overlay b/src/platform/telink/2m_flash.overlay index 95f1a749057436..09e60eca748805 100644 --- a/src/platform/telink/2m_flash.overlay +++ b/src/platform/telink/2m_flash.overlay @@ -21,19 +21,19 @@ }; slot0_partition: partition@19000 { label = "image-0"; - reg = <0x19000 0xed000>; + reg = <0x19000 0xec000>; }; - factory_partition: partition@106000{ + factory_partition: partition@105000 { label = "factory-data"; - reg = <0x106000 0x1000>; + reg = <0x105000 0x1000>; }; - storage_partition: partition@107000 { + storage_partition: partition@106000 { label = "storage"; - reg = <0x107000 0xa000>; + reg = <0x106000 0xc000>; }; - slot1_partition: partition@111000 { + slot1_partition: partition@112000 { label = "image-1"; - reg = <0x111000 0xed000>; + reg = <0x112000 0xec000>; }; vendor_partition: partition@1fe000 { label = "vendor-data"; diff --git a/src/platform/telink/4m_flash.overlay b/src/platform/telink/4m_flash.overlay index e22c007e0bc235..657684d8fc5672 100644 --- a/src/platform/telink/4m_flash.overlay +++ b/src/platform/telink/4m_flash.overlay @@ -21,19 +21,19 @@ }; slot0_partition: partition@19000 { label = "image-0"; - reg = <0x19000 0x1ed000>; + reg = <0x19000 0x1ec000>; }; - factory_partition: partition@206000 { + factory_partition: partition@205000 { label = "factory-data"; - reg = <0x206000 0x1000>; + reg = <0x205000 0x1000>; }; - storage_partition: partition@207000 { + storage_partition: partition@206000 { label = "storage"; - reg = <0x207000 0xa000>; + reg = <0x206000 0xc000>; }; - slot1_partition: partition@211000 { + slot1_partition: partition@212000 { label = "image-1"; - reg = <0x211000 0x1ed000>; + reg = <0x212000 0x1ec000>; }; vendor_partition: partition@3fe000 { label = "vendor-data"; diff --git a/src/platform/telink/CHIPDevicePlatformConfig.h b/src/platform/telink/CHIPDevicePlatformConfig.h index 07967f8b273e4f..245b802f9a88cd 100644 --- a/src/platform/telink/CHIPDevicePlatformConfig.h +++ b/src/platform/telink/CHIPDevicePlatformConfig.h @@ -200,11 +200,7 @@ #endif // CHIP_DEVICE_CONFIG_CHIP_TASK_PRIORITY #ifndef CHIP_DEVICE_CONFIG_CHIP_TASK_STACK_SIZE -#ifdef CONFIG_PM -#define CHIP_DEVICE_CONFIG_CHIP_TASK_STACK_SIZE 4864 -#else -#define CHIP_DEVICE_CONFIG_CHIP_TASK_STACK_SIZE 8192 -#endif +#define CHIP_DEVICE_CONFIG_CHIP_TASK_STACK_SIZE CONFIG_CHIP_TASK_STACK_SIZE #endif // CHIP_DEVICE_CONFIG_CHIP_TASK_STACK_SIZE #define CHIP_DEVICE_CONFIG_ENABLE_WIFI_TELEMETRY 0 diff --git a/src/protocols/secure_channel/BUILD.gn b/src/protocols/secure_channel/BUILD.gn index 2061b04e82b6d5..f596345474301e 100644 --- a/src/protocols/secure_channel/BUILD.gn +++ b/src/protocols/secure_channel/BUILD.gn @@ -12,6 +12,7 @@ static_library("type_definitions") { cflags = [ "-Wconversion" ] public_deps = [ + "${chip_root}/src/lib/support:type-traits", "${chip_root}/src/protocols:type_definitions", "${chip_root}/src/system", ] @@ -55,6 +56,7 @@ static_library("secure_channel") { "${chip_root}/src/crypto", "${chip_root}/src/lib/core", "${chip_root}/src/lib/support", + "${chip_root}/src/lib/support:type-traits", "${chip_root}/src/messaging", "${chip_root}/src/system", "${chip_root}/src/tracing", diff --git a/src/protocols/secure_channel/tests/BUILD.gn b/src/protocols/secure_channel/tests/BUILD.gn index b77fb6976734c6..9a0ec760950d3f 100644 --- a/src/protocols/secure_channel/tests/BUILD.gn +++ b/src/protocols/secure_channel/tests/BUILD.gn @@ -29,6 +29,7 @@ chip_test_suite_using_nltest("tests") { "${chip_root}/src/lib/core", "${chip_root}/src/lib/support", "${chip_root}/src/lib/support:test_utils", + "${chip_root}/src/lib/support:testing", "${chip_root}/src/lib/support:testing_nlunit", "${chip_root}/src/messaging/tests:helpers", "${chip_root}/src/protocols", diff --git a/src/transport/raw/BUILD.gn b/src/transport/raw/BUILD.gn index ae3aeb58f8e3e9..736b16cdb08477 100644 --- a/src/transport/raw/BUILD.gn +++ b/src/transport/raw/BUILD.gn @@ -44,6 +44,7 @@ static_library("raw") { "${chip_root}/src/inet", "${chip_root}/src/lib/core", "${chip_root}/src/lib/support", + "${chip_root}/src/lib/support:type-traits", "${chip_root}/src/platform", ] } diff --git a/src/transport/tests/BUILD.gn b/src/transport/tests/BUILD.gn index 6f454f4502e0c0..057065a3d1a1bc 100644 --- a/src/transport/tests/BUILD.gn +++ b/src/transport/tests/BUILD.gn @@ -54,6 +54,7 @@ chip_test_suite_using_nltest("tests") { "${chip_root}/src/inet/tests:helpers", "${chip_root}/src/lib/core", "${chip_root}/src/lib/support", + "${chip_root}/src/lib/support:testing", "${chip_root}/src/lib/support:testing_nlunit", "${chip_root}/src/protocols", "${chip_root}/src/transport", diff --git a/zzz_generated/placeholder/app1/zap-generated/test/Commands.h b/zzz_generated/placeholder/app1/zap-generated/test/Commands.h index 35de801fb5d94d..fd7e5da8588d13 100644 --- a/zzz_generated/placeholder/app1/zap-generated/test/Commands.h +++ b/zzz_generated/placeholder/app1/zap-generated/test/Commands.h @@ -21,7 +21,7 @@ #include "TestCommand.h" -#include +#include class Test_TC_WNCV_5_1_SimulatedSuite : public TestCommand { diff --git a/zzz_generated/placeholder/app2/zap-generated/test/Commands.h b/zzz_generated/placeholder/app2/zap-generated/test/Commands.h index 35de801fb5d94d..fd7e5da8588d13 100644 --- a/zzz_generated/placeholder/app2/zap-generated/test/Commands.h +++ b/zzz_generated/placeholder/app2/zap-generated/test/Commands.h @@ -21,7 +21,7 @@ #include "TestCommand.h" -#include +#include class Test_TC_WNCV_5_1_SimulatedSuite : public TestCommand {