diff --git a/.github/workflows/examples-nrfconnect.yaml b/.github/workflows/examples-nrfconnect.yaml index f2d1c5ee108c62..96b09cb932add4 100644 --- a/.github/workflows/examples-nrfconnect.yaml +++ b/.github/workflows/examples-nrfconnect.yaml @@ -25,7 +25,7 @@ concurrency: jobs: nrfconnect: name: nRF Connect SDK - timeout-minutes: 120 + timeout-minutes: 125 env: BUILD_TYPE: nrfconnect @@ -174,7 +174,7 @@ jobs: examples/pump-controller-app/nrfconnect/build/zephyr/zephyr.elf \ /tmp/bloat_reports/ - name: Build example nRF Connect SDK All Clusters App on nRF52840 DK - timeout-minutes: 10 + timeout-minutes: 15 run: | scripts/examples/nrfconnect_example.sh all-clusters-app nrf52840dk_nrf52840 -DCONF_FILE=prj_dfu.conf .environment/pigweed-venv/bin/python3 scripts/tools/memory/gh_sizes.py \ diff --git a/examples/lock-app/cc13x2x7_26x2x7/args.gni b/examples/lock-app/cc13x2x7_26x2x7/args.gni index ebb3a78797278f..d982dce73c11c5 100644 --- a/examples/lock-app/cc13x2x7_26x2x7/args.gni +++ b/examples/lock-app/cc13x2x7_26x2x7/args.gni @@ -30,8 +30,8 @@ chip_enable_ota_requestor = true # Disable CHIP Logging #chip_progress_logging = false -#chip_detail_logging = false -#chip_automation_logging = false +chip_detail_logging = false +chip_automation_logging = false # BLE options chip_config_network_layer_ble = true diff --git a/examples/lock-app/efr32/BUILD.gn b/examples/lock-app/efr32/BUILD.gn index f9bbbcab940988..56b75c8530a6d9 100644 --- a/examples/lock-app/efr32/BUILD.gn +++ b/examples/lock-app/efr32/BUILD.gn @@ -15,9 +15,9 @@ import("//build_overrides/build.gni") import("//build_overrides/chip.gni") import("//build_overrides/efr32_sdk.gni") +import("//build_overrides/pigweed.gni") import("${build_root}/config/defaults.gni") - import("${efr32_sdk_build_root}/efr32_executable.gni") import("${efr32_sdk_build_root}/efr32_sdk.gni") @@ -40,6 +40,7 @@ declare_args() { # PIN code for PASE session establishment. setupPinCode = 20202021 + setupDiscriminator = 3840 # Monitor & log memory usage at runtime. enable_heap_monitoring = false @@ -115,6 +116,7 @@ efr32_sdk("sdk") { defines = [ "BOARD_ID=${efr32_board}", "CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE=${setupPinCode}", + "CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR=${setupDiscriminator}", "OTA_PERIODIC_TIMEOUT=${OTA_periodic_query_timeout}", ] @@ -124,13 +126,6 @@ efr32_sdk("sdk") { "PW_RPC_ENABLED", ] } - if (use_rs911x) { - defines += rs911x_defs - include_dirs += rs911x_plat_incs - } else if (use_wf200) { - defines += wf200_defs - include_dirs += wf200_plat_incs - } # WiFi Settings if (chip_enable_wifi) { @@ -149,7 +144,6 @@ efr32_sdk("sdk") { # Using LWIP instead of the native TCP/IP stack defines += efr32_lwip_defs } - if (sl_wfx_config_softap) { defines += [ "SL_WFX_CONFIG_SOFTAP" ] } @@ -162,7 +156,6 @@ efr32_sdk("sdk") { efr32_executable("lock_app") { output_name = "chip-efr32-lock-example.out" include_dirs = [ "include" ] - defines = [] sources = [ @@ -170,7 +163,7 @@ efr32_executable("lock_app") { "${examples_plat_dir}/heap_4_silabs.c", "${examples_plat_dir}/init_efrPlatform.cpp", "src/AppTask.cpp", - "src/BoltLockManager.cpp", + "src/LockManager.cpp", "src/ZclCallbacks.cpp", "src/main.cpp", ] @@ -248,7 +241,6 @@ efr32_executable("lock_app") { defines += [ "DISPLAY_ENABLED" ] if (show_qr_code) { defines += [ "QR_CODE_ENABLED" ] - deps += [ "${chip_root}/examples/common/QRCode" ] } } @@ -295,16 +287,16 @@ efr32_executable("lock_app") { } if (enable_heap_monitoring) { - defines += [ "HEAP_MONITORING" ] sources += [ "${examples_plat_dir}/MemMonitoring.cpp" ] + defines += [ "HEAP_MONITORING" ] } ldscript = "${examples_plat_dir}/ldscripts/${efr32_family}.ld" - ldflags = [ "-T" + rebase_path(ldscript, root_build_dir) ] - inputs = [ ldscript ] + ldflags = [ "-T" + rebase_path(ldscript, root_build_dir) ] + if (chip_print_memory_usage) { ldflags += [ "-Wl,--print-memory-usage", @@ -322,7 +314,6 @@ efr32_executable("lock_app") { output_dir = root_out_dir } - group("efr32") { deps = [ ":lock_app" ] } diff --git a/examples/lock-app/efr32/README.md b/examples/lock-app/efr32/README.md index ab1fe655e5a037..b8a4e5e1730d8b 100644 --- a/examples/lock-app/efr32/README.md +++ b/examples/lock-app/efr32/README.md @@ -262,9 +262,9 @@ combination with JLinkRTTClient as follows: **LED 1** Simulates the Lock The following states are possible: - - _Solid On_ ; Bolt is locked + - _Solid On_ ; Bolt is unlocked - _Blinking_ ; Bolt is moving to the desired state - - _Off_ ; Bolt is unlocked + - _Off_ ; Bolt is locked **Push Button 0** @@ -284,12 +284,47 @@ combination with JLinkRTTClient as follows: [CHIPTool](https://github.com/project-chip/connectedhomeip/blob/master/examples/chip-tool/README.md) - Here is an example with the CHIPTool: +Here is some CHIPTool examples: + Pairing with chip-tool: ``` chip-tool pairing ble-thread 1 hex: 20202021 3840 + ``` - chip-tool onoff toggle 1 1 + Set a user: + ``` + ./out/chip-tool doorlock set-user OperationType UserIndex UserName UserUniqueId UserStatus UserType CredentialRule node-id/group-id + ./out/chip-tool doorlock set-user 0 1 "mike" 5 1 0 0 1 1 --timedInteractionTimeoutMs 1000 + ``` + + Set a credential: + ``` + ./out/chip-tool doorlock set-credential OperationType Credential CredentialData UserIndex UserStatus UserType node-id/group-id + ./out/chip-tool doorlock set-credential 0 '{ "credentialType": 1, "credentialIndex": 1 }' "123456" 1 null null 1 1 --timedInteractionTimeoutMs 1000 + ``` + + Changing a credential: + ``` + ./out/chip-tool doorlock set-credential OperationType Credential CredentialData UserIndex UserStatus UserType node-id/group-id + ./out/chip-tool doorlock set-credential 2 '{ "credentialType": 1, "credentialIndex": 1 }' "123457" 1 null null 1 1 --timedInteractionTimeoutMs 1000 + ``` + + Get a user: + ``` + ./out/chip-tool doorlock get-user UserIndex node-id/group-id + ./out/chip-tool doorlock get-user 1 1 1 + ``` + + Unlock door: + ``` + ./out/chip-tool doorlock unlock-door node-id/group-id + ./out/chip-tool doorlock unlock-door 1 1 + ``` + + Lock door: + ``` + ./out/chip-tool doorlock lock-door node-id/group-id + ./out/chip-tool doorlock lock-door 1 1 ``` ### Notes diff --git a/examples/lock-app/efr32/include/AppConfig.h b/examples/lock-app/efr32/include/AppConfig.h index 84b588c4997970..852083cb9cbd91 100644 --- a/examples/lock-app/efr32/include/AppConfig.h +++ b/examples/lock-app/efr32/include/AppConfig.h @@ -19,13 +19,13 @@ #pragma once -// ---- Lock Example App Config ---- +// ---- Door lock Example App Config ---- -#define APP_TASK_NAME "Lck" +#define APP_TASK_NAME "Lock" // Time it takes in ms for the simulated actuator to move from one // state to another. -#define ACTUATOR_MOVEMENT_PERIOS_MS 2000 +#define ACTUATOR_MOVEMENT_PERIOS_MS 10 // EFR Logging #ifdef __cplusplus diff --git a/examples/lock-app/efr32/include/AppTask.h b/examples/lock-app/efr32/include/AppTask.h index 9c871c2bfcae54..67803623f2fbc8 100644 --- a/examples/lock-app/efr32/include/AppTask.h +++ b/examples/lock-app/efr32/include/AppTask.h @@ -23,7 +23,7 @@ #include #include "AppEvent.h" -#include "BoltLockManager.h" +#include "LockManager.h" #include "sl_simple_button_instances.h" #include "FreeRTOS.h" @@ -46,7 +46,7 @@ class AppTask CHIP_ERROR StartAppTask(); static void AppTaskMain(void * pvParameter); - void PostLockActionRequest(int32_t aActor, BoltLockManager::Action_t aAction); + void ActionRequest(int32_t aActor, LockManager::Action_t aAction); void PostEvent(const AppEvent * event); void ButtonEventHandler(const sl_button_t * buttonHandle, uint8_t btnAction); @@ -56,8 +56,8 @@ class AppTask CHIP_ERROR Init(); - static void ActionInitiated(BoltLockManager::Action_t aAction, int32_t aActor); - static void ActionCompleted(BoltLockManager::Action_t aAction); + static void ActionInitiated(LockManager::Action_t aAction, int32_t aActor); + static void ActionCompleted(LockManager::Action_t aAction); void CancelTimer(void); diff --git a/examples/lock-app/efr32/include/BoltLockManager.h b/examples/lock-app/efr32/include/BoltLockManager.h deleted file mode 100644 index febb9b7c071928..00000000000000 --- a/examples/lock-app/efr32/include/BoltLockManager.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - * - * Copyright (c) 2019 Google LLC. - * 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 - -#include "AppEvent.h" - -#include "FreeRTOS.h" -#include "timers.h" // provides FreeRTOS timer support - -#include - -class BoltLockManager -{ -public: - enum Action_t - { - LOCK_ACTION = 0, - UNLOCK_ACTION, - - INVALID_ACTION - } Action; - - enum State_t - { - kState_LockingInitiated = 0, - kState_LockingCompleted, - kState_UnlockingInitiated, - kState_UnlockingCompleted, - } State; - - CHIP_ERROR Init(); - bool IsUnlocked(); - void EnableAutoRelock(bool aOn); - void SetAutoLockDuration(uint32_t aDurationInSecs); - bool IsActionInProgress(); - bool InitiateAction(int32_t aActor, Action_t aAction); - - typedef void (*Callback_fn_initiated)(Action_t, int32_t aActor); - typedef void (*Callback_fn_completed)(Action_t); - void SetCallbacks(Callback_fn_initiated aActionInitiated_CB, Callback_fn_completed aActionCompleted_CB); - -private: - friend BoltLockManager & BoltLockMgr(void); - State_t mState; - - Callback_fn_initiated mActionInitiated_CB; - Callback_fn_completed mActionCompleted_CB; - - bool mAutoRelock; - uint32_t mAutoLockDuration; - bool mAutoLockTimerArmed; - - void CancelTimer(void); - void StartTimer(uint32_t aTimeoutMs); - - static void TimerEventHandler(TimerHandle_t xTimer); - static void AutoReLockTimerEventHandler(AppEvent * aEvent); - static void ActuatorMovementTimerEventHandler(AppEvent * aEvent); - - static BoltLockManager sLock; -}; - -inline BoltLockManager & BoltLockMgr(void) -{ - return BoltLockManager::sLock; -} diff --git a/examples/lock-app/efr32/include/CHIPProjectConfig.h b/examples/lock-app/efr32/include/CHIPProjectConfig.h index cc930f85bc796f..118cb5e3fd31f7 100644 --- a/examples/lock-app/efr32/include/CHIPProjectConfig.h +++ b/examples/lock-app/efr32/include/CHIPProjectConfig.h @@ -32,7 +32,10 @@ #ifndef CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE #define CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE 20202021 #endif + +#ifndef CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR #define CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR 0xF00 +#endif // For convenience, Chip Security Test Mode can be enabled and the // requirement for authentication in various protocols can be disabled. @@ -41,18 +44,19 @@ // including message encryption. Because of this they MUST NEVER BE ENABLED IN PRODUCTION BUILDS. // #define CHIP_CONFIG_SECURITY_TEST_MODE 0 +#define CHIP_CONFIG_REQUIRE_AUTH 1 /** * CHIP_DEVICE_CONFIG_DEVICE_VENDOR_ID * - * 0xFFF1: Test vendor. + * 0xFFF1: Test vendor */ #define CHIP_DEVICE_CONFIG_DEVICE_VENDOR_ID 0xFFF1 /** * CHIP_DEVICE_CONFIG_DEVICE_PRODUCT_ID * - * 0x8006: example lock-app + * 0x8006: example lock app */ #define CHIP_DEVICE_CONFIG_DEVICE_PRODUCT_ID 0x8006 diff --git a/examples/lock-app/efr32/include/FreeRTOSConfig.h b/examples/lock-app/efr32/include/FreeRTOSConfig.h index a747d9a8b413ca..54d7b544fda0ff 100644 --- a/examples/lock-app/efr32/include/FreeRTOSConfig.h +++ b/examples/lock-app/efr32/include/FreeRTOSConfig.h @@ -163,7 +163,7 @@ to all Cortex-M ports, and do not rely on any particular library functions. */ #define configKERNEL_INTERRUPT_PRIORITY (255) /* !!!! configMAX_SYSCALL_INTERRUPT_PRIORITY must not be set to zero !!!! See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */ -#define configMAX_SYSCALL_INTERRUPT_PRIORITY 48 // 96 +#define configMAX_SYSCALL_INTERRUPT_PRIORITY 48 #define configENABLE_FPU 0 #define configENABLE_MPU 0 /* FreeRTOS Secure Side Only and TrustZone Security Extension */ @@ -189,7 +189,7 @@ See http://www.FreeRTOS.org/RTOS-Cortex-M3-M4.html. */ #define configUSE_TRACE_FACILITY 1 #define configQUEUE_REGISTRY_SIZE (10) #define configUSE_QUEUE_SETS (0) -#define configUSE_NEWLIB_REENTRANT (0) +#define configUSE_NEWLIB_REENTRANT (1) #define configENABLE_BACKWARD_COMPATIBILITY (1) #define configSUPPORT_STATIC_ALLOCATION (1) #define configSUPPORT_DYNAMIC_ALLOCATION (1) diff --git a/examples/lock-app/efr32/include/LockManager.h b/examples/lock-app/efr32/include/LockManager.h new file mode 100644 index 00000000000000..dad3c119884b18 --- /dev/null +++ b/examples/lock-app/efr32/include/LockManager.h @@ -0,0 +1,114 @@ +/* + * + * Copyright (c) 2019 Google LLC. + * 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 +#include + +#include "AppEvent.h" + +#include "FreeRTOS.h" +#include "timers.h" // provides FreeRTOS timer support + +#include + +using namespace ::chip; + +#define DOOR_LOCK_MAX_CREDENTIAL_SIZE 8 + +static constexpr size_t DOOR_LOCK_CREDENTIAL_INFO_MAX_DATA_SIZE = 20; + +class LockManager +{ +public: + enum Action_t + { + LOCK_ACTION = 0, + UNLOCK_ACTION, + + INVALID_ACTION + } Action; + + enum State_t + { + kState_LockInitiated = 0, + kState_LockCompleted, + kState_UnlockInitiated, + kState_UnlockCompleted, + } State; + + CHIP_ERROR Init(chip::app::DataModel::Nullable state); + bool NextState(); + bool IsActionInProgress(); + bool InitiateAction(int32_t aActor, Action_t aAction); + + typedef void (*Callback_fn_initiated)(Action_t, int32_t aActor); + typedef void (*Callback_fn_completed)(Action_t); + void SetCallbacks(Callback_fn_initiated aActionInitiated_CB, Callback_fn_completed aActionCompleted_CB); + + bool Lock(chip::EndpointId endpointId, const Optional & pin, DlOperationError & err); + bool Unlock(chip::EndpointId endpointId, const Optional & pin, DlOperationError & err); + + bool GetUser(uint16_t userIndex, EmberAfPluginDoorLockUserInfo & user) const; + bool SetUser(uint16_t userIndex, chip::FabricIndex creator, chip::FabricIndex modifier, const chip::CharSpan & userName, + uint32_t uniqueId, DlUserStatus userStatus, DlUserType usertype, DlCredentialRule credentialRule, + const DlCredential * credentials, size_t totalCredentials); + + bool GetCredential(chip::EndpointId endpointId, uint16_t credentialIndex, DlCredentialType credentialType, + EmberAfPluginDoorLockCredentialInfo & credential) const; + + bool SetCredential(chip::EndpointId endpointId, uint16_t credentialIndex, DlCredentialStatus credentialStatus, + DlCredentialType credentialType, const chip::ByteSpan & credentialData); + + bool setLockState(chip::EndpointId endpointId, DlLockState lockState, const Optional & pin, + DlOperationError & err); + const char * lockStateToString(DlLockState lockState) const; + + bool ReadConfigValues(); + +private: + friend LockManager & LockMgr(); + chip::EndpointId mEndpointId; + State_t mState; + + Callback_fn_initiated mActionInitiated_CB; + Callback_fn_completed mActionCompleted_CB; + + void CancelTimer(void); + void StartTimer(uint32_t aTimeoutMs); + + static void TimerEventHandler(TimerHandle_t xTimer); + static void AutoLockTimerEventHandler(AppEvent * aEvent); + static void ActuatorMovementTimerEventHandler(AppEvent * aEvent); + + EmberAfPluginDoorLockUserInfo mLockUser; + EmberAfPluginDoorLockCredentialInfo mLockCredentials; + + char mUserName[DOOR_LOCK_MAX_USER_NAME_SIZE]; + uint8_t mCredentialData[DOOR_LOCK_MAX_CREDENTIAL_SIZE]; + DlCredential mCredentials[DOOR_LOCK_MAX_CREDENTIALS_PER_USER]; + + static LockManager sLock; +}; + +inline LockManager & LockMgr() +{ + return LockManager::sLock; +} diff --git a/examples/lock-app/efr32/src/AppTask.cpp b/examples/lock-app/efr32/src/AppTask.cpp index ec4bb10f44a964..1f593f41322ab2 100644 --- a/examples/lock-app/efr32/src/AppTask.cpp +++ b/examples/lock-app/efr32/src/AppTask.cpp @@ -26,9 +26,15 @@ #include "qrcodegen.h" #endif // DISPLAY_ENABLED #include "sl_simple_led_instances.h" +#include #include #include +#include #include +#include + +#include +#include #include #include #include @@ -38,11 +44,13 @@ #include #include -#include - #include #include +#include + +#include + #include #if CHIP_ENABLE_OPENTHREAD #include @@ -53,7 +61,7 @@ #include "wfx_host_events.h" #include #include -#endif +#endif /* SL_WIFI */ #define FACTORY_RESET_TRIGGER_TIMEOUT 3000 #define FACTORY_RESET_CANCEL_WINDOW_TIMEOUT 3000 @@ -64,12 +72,15 @@ #define SYSTEM_STATE_LED &sl_led_led0 #define LOCK_STATE_LED &sl_led_led1 #define APP_FUNCTION_BUTTON &sl_button_btn0 -#define APP_LOCK_BUTTON &sl_button_btn1 +#define APP_LOCK_SWITCH &sl_button_btn1 + +using chip::app::Clusters::DoorLock::DlLockState; +using chip::app::Clusters::DoorLock::DlOperationError; +using chip::app::Clusters::DoorLock::DlOperationSource; using namespace chip; -using namespace chip::TLV; -using namespace ::chip::Credentials; using namespace ::chip::DeviceLayer; +using namespace ::chip::DeviceLayer::Internal; namespace { TimerHandle_t sFunctionTimer; // FreeRTOS app sw timer. @@ -87,23 +98,86 @@ bool sIsWiFiAttached = false; app::Clusters::NetworkCommissioning::Instance sWiFiNetworkCommissioningInstance(0 /* Endpoint Id */, &(NetworkCommissioning::SlWiFiDriver::GetInstance())); -#endif +#endif /* SL_WIFI */ #if CHIP_ENABLE_OPENTHREAD bool sIsThreadProvisioned = false; bool sIsThreadEnabled = false; -#endif +#endif /* CHIP_ENABLE_OPENTHREAD */ bool sHaveBLEConnections = false; +bool configValueSet = false; + +EmberAfIdentifyEffectIdentifier sIdentifyEffect = EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_STOP_EFFECT; + +uint8_t sAppEventQueueBuffer[APP_EVENT_QUEUE_SIZE * sizeof(AppEvent)]; +StaticQueue_t sAppEventQueueStruct; StackType_t appStack[APP_TASK_STACK_SIZE / sizeof(StackType_t)]; StaticTask_t appTaskStruct; + +/********************************************************** + * Identify Callbacks + *********************************************************/ + +namespace { +void OnTriggerIdentifyEffectCompleted(chip::System::Layer * systemLayer, void * appState) +{ + sIdentifyEffect = EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_STOP_EFFECT; +} +} // namespace + +void OnTriggerIdentifyEffect(Identify * identify) +{ + sIdentifyEffect = identify->mCurrentEffectIdentifier; + + if (identify->mCurrentEffectIdentifier == EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_CHANNEL_CHANGE) + { + ChipLogProgress(Zcl, "IDENTIFY_EFFECT_IDENTIFIER_CHANNEL_CHANGE - Not supported, use effect varriant %d", + identify->mEffectVariant); + sIdentifyEffect = static_cast(identify->mEffectVariant); + } + + switch (sIdentifyEffect) + { + case EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_BLINK: + case EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_BREATHE: + case EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_OKAY: + (void) chip::DeviceLayer::SystemLayer().StartTimer(chip::System::Clock::Seconds16(5), OnTriggerIdentifyEffectCompleted, + identify); + break; + case EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_FINISH_EFFECT: + (void) chip::DeviceLayer::SystemLayer().CancelTimer(OnTriggerIdentifyEffectCompleted, identify); + (void) chip::DeviceLayer::SystemLayer().StartTimer(chip::System::Clock::Seconds16(1), OnTriggerIdentifyEffectCompleted, + identify); + break; + case EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_STOP_EFFECT: + (void) chip::DeviceLayer::SystemLayer().CancelTimer(OnTriggerIdentifyEffectCompleted, identify); + sIdentifyEffect = EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_STOP_EFFECT; + break; + default: + ChipLogProgress(Zcl, "No identifier effect"); + } +} + +Identify gIdentify = { + chip::EndpointId{ 1 }, + [](Identify *) { ChipLogProgress(Zcl, "onIdentifyStart"); }, + [](Identify *) { ChipLogProgress(Zcl, "onIdentifyStop"); }, + EMBER_ZCL_IDENTIFY_IDENTIFY_TYPE_VISIBLE_LED, + OnTriggerIdentifyEffect, +}; + } // namespace +using namespace chip::TLV; +using namespace ::chip::Credentials; +using namespace ::chip::DeviceLayer; + AppTask AppTask::sAppTask; CHIP_ERROR AppTask::StartAppTask() { - sAppEventQueue = xQueueCreate(APP_EVENT_QUEUE_SIZE, sizeof(AppEvent)); + sAppEventQueue = xQueueCreateStatic(APP_EVENT_QUEUE_SIZE, sizeof(AppEvent), sAppEventQueueBuffer, &sAppEventQueueStruct); if (sAppEventQueue == NULL) { EFR32_LOG("Failed to allocate app event queue"); @@ -117,6 +191,8 @@ CHIP_ERROR AppTask::StartAppTask() CHIP_ERROR AppTask::Init() { + CHIP_ERROR err = CHIP_NO_ERROR; + #ifdef SL_WIFI /* * Wait for the WiFi to be initialized @@ -151,26 +227,42 @@ CHIP_ERROR AppTask::Init() } EFR32_LOG("Current Software Version: %s", CHIP_DEVICE_CONFIG_DEVICE_SOFTWARE_VERSION_STRING); - CHIP_ERROR err = BoltLockMgr().Init(); + + // Initial lock state + chip::app::DataModel::Nullable state; + chip::EndpointId endpointId{ 1 }; + chip::DeviceLayer::PlatformMgr().LockChipStack(); + chip::app::Clusters::DoorLock::Attributes::LockState::Get(endpointId, state); + chip::DeviceLayer::PlatformMgr().UnlockChipStack(); + + err = LockMgr().Init(state); if (err != CHIP_NO_ERROR) { - EFR32_LOG("BoltLockMgr().Init() failed"); + EFR32_LOG("LockMgr().Init() failed"); appError(err); } - BoltLockMgr().SetCallbacks(ActionInitiated, ActionCompleted); + LockMgr().SetCallbacks(ActionInitiated, ActionCompleted); // Initialize LEDs LEDWidget::InitGpio(); sStatusLED.Init(SYSTEM_STATE_LED); - sLockLED.Init(LOCK_STATE_LED); - sLockLED.Set(!BoltLockMgr().IsUnlocked()); + + if (state.Value() == DlLockState::kUnlocked) + { + sLockLED.Set(true); + } + else + { + sLockLED.Set(false); + } + chip::DeviceLayer::PlatformMgr().ScheduleWork(UpdateClusterState, reinterpret_cast(nullptr)); ConfigurationMgr().LogDeviceConfig(); - // Print setup info on LCD if available +// Print setup info on LCD if available #ifdef DISPLAY_ENABLED std::string QRCode; @@ -204,6 +296,13 @@ void AppTask::AppTaskMain(void * pvParameter) while (true) { + // Users and credentials should be checked once from nvm flash on boot + if (!configValueSet) + { + LockMgr().ReadConfigValues(); + configValueSet = true; + } + BaseType_t eventReceived = xQueueReceive(sAppEventQueue, &event, pdMS_TO_TICKS(10)); while (eventReceived == pdTRUE) { @@ -222,11 +321,11 @@ void AppTask::AppTaskMain(void * pvParameter) sIsWiFiProvisioned = ConnectivityMgr().IsWiFiStationProvisioned(); sIsWiFiEnabled = ConnectivityMgr().IsWiFiStationEnabled(); sIsWiFiAttached = ConnectivityMgr().IsWiFiStationConnected(); -#endif +#endif /* SL_WIFI */ #if CHIP_ENABLE_OPENTHREAD sIsThreadProvisioned = ConnectivityMgr().IsThreadProvisioned(); sIsThreadEnabled = ConnectivityMgr().IsThreadEnabled(); -#endif +#endif /* CHIP_ENABLE_OPENTHREAD */ sHaveBLEConnections = (ConnectivityMgr().NumBLEConnections() != 0); PlatformMgr().UnlockChipStack(); } @@ -245,6 +344,25 @@ void AppTask::AppTaskMain(void * pvParameter) // Otherwise, blink the LED ON for a very short time. if (sAppTask.mFunction != kFunction_FactoryReset) { + if (gIdentify.mActive) + { + sStatusLED.Blink(250, 250); + } + if (sIdentifyEffect != EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_STOP_EFFECT) + { + if (sIdentifyEffect == EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_BLINK) + { + sStatusLED.Blink(50, 50); + } + if (sIdentifyEffect == EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_BREATHE) + { + sStatusLED.Blink(1000, 1000); + } + if (sIdentifyEffect == EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_OKAY) + { + sStatusLED.Blink(300, 700); + } + } #if CHIP_ENABLE_OPENTHREAD if (sIsThreadProvisioned && sIsThreadEnabled) #else @@ -265,24 +383,24 @@ void AppTask::AppTaskMain(void * pvParameter) void AppTask::LockActionEventHandler(AppEvent * aEvent) { bool initiated = false; - BoltLockManager::Action_t action; + LockManager::Action_t action; int32_t actor; CHIP_ERROR err = CHIP_NO_ERROR; if (aEvent->Type == AppEvent::kEventType_Lock) { - action = static_cast(aEvent->LockEvent.Action); + action = static_cast(aEvent->LockEvent.Action); actor = aEvent->LockEvent.Actor; } else if (aEvent->Type == AppEvent::kEventType_Button) { - if (BoltLockMgr().IsUnlocked()) + if (LockMgr().NextState() == true) { - action = BoltLockManager::LOCK_ACTION; + action = LockManager::LOCK_ACTION; } else { - action = BoltLockManager::UNLOCK_ACTION; + action = LockManager::UNLOCK_ACTION; } actor = AppEvent::kEventType_Button; } @@ -293,7 +411,7 @@ void AppTask::LockActionEventHandler(AppEvent * aEvent) if (err == CHIP_NO_ERROR) { - initiated = BoltLockMgr().InitiateAction(actor, action); + initiated = LockMgr().InitiateAction(actor, action); if (!initiated) { @@ -313,7 +431,7 @@ void AppTask::ButtonEventHandler(const sl_button_t * buttonHandle, uint8_t btnAc button_event.Type = AppEvent::kEventType_Button; button_event.ButtonEvent.Action = btnAction; - if (buttonHandle == APP_LOCK_BUTTON && btnAction == SL_SIMPLE_BUTTON_PRESSED) + if (buttonHandle == APP_LOCK_SWITCH && btnAction == SL_SIMPLE_BUTTON_PRESSED) { button_event.Handler = LockActionEventHandler; sAppTask.PostEvent(&button_event); @@ -398,7 +516,7 @@ void AppTask::FunctionHandler(AppEvent * aEvent) if (!ConnectivityMgr().IsWiFiStationProvisioned()) #else if (!ConnectivityMgr().IsThreadProvisioned()) -#endif +#endif /* !SL_WIFI */ { // Enable BLE advertisements ConnectivityMgr().SetBLEAdvertisingEnabled(true); @@ -409,7 +527,7 @@ void AppTask::FunctionHandler(AppEvent * aEvent) else if (sAppTask.mFunctionTimerActive && sAppTask.mFunction == kFunction_FactoryReset) { // Set lock status LED back to show state of lock. - sLockLED.Set(!BoltLockMgr().IsUnlocked()); + sLockLED.Set(!LockMgr().NextState()); sAppTask.CancelTimer(); @@ -453,43 +571,38 @@ void AppTask::StartTimer(uint32_t aTimeoutInMs) mFunctionTimerActive = true; } -void AppTask::ActionInitiated(BoltLockManager::Action_t aAction, int32_t aActor) +void AppTask::ActionInitiated(LockManager::Action_t aAction, int32_t aActor) { - // If the action has been initiated by the lock, update the bolt lock trait - // and start flashing the LEDs rapidly to indicate action initiation. - if (aAction == BoltLockManager::LOCK_ACTION) + // Action initiated, update the light led + if (aAction == LockManager::LOCK_ACTION) { EFR32_LOG("Lock Action has been initiated") + sLockLED.Set(false); } - else if (aAction == BoltLockManager::UNLOCK_ACTION) + else if (aAction == LockManager::UNLOCK_ACTION) { EFR32_LOG("Unlock Action has been initiated") + sLockLED.Set(true); } if (aActor == AppEvent::kEventType_Button) { sAppTask.mSyncClusterToButtonAction = true; } - - sLockLED.Blink(50, 50); } -void AppTask::ActionCompleted(BoltLockManager::Action_t aAction) +void AppTask::ActionCompleted(LockManager::Action_t aAction) { - // if the action has been completed by the lock, update the bolt lock trait. - // Turn on the lock LED if in a LOCKED state OR - // Turn off the lock LED if in an UNLOCKED state. - if (aAction == BoltLockManager::LOCK_ACTION) + // if the action has been completed by the lock, update the lock trait. + // Turn off the lock LED if in a LOCKED state OR + // Turn on the lock LED if in an UNLOCKED state. + if (aAction == LockManager::LOCK_ACTION) { EFR32_LOG("Lock Action has been completed") - - sLockLED.Set(true); } - else if (aAction == BoltLockManager::UNLOCK_ACTION) + else if (aAction == LockManager::UNLOCK_ACTION) { EFR32_LOG("Unlock Action has been completed") - - sLockLED.Set(false); } if (sAppTask.mSyncClusterToButtonAction) @@ -499,7 +612,7 @@ void AppTask::ActionCompleted(BoltLockManager::Action_t aAction) } } -void AppTask::PostLockActionRequest(int32_t aActor, BoltLockManager::Action_t aAction) +void AppTask::ActionRequest(int32_t aActor, LockManager::Action_t aAction) { AppEvent event; event.Type = AppEvent::kEventType_Lock; @@ -535,6 +648,10 @@ void AppTask::PostEvent(const AppEvent * aEvent) if (!status) EFR32_LOG("Failed to post event to app task event queue"); } + else + { + EFR32_LOG("Event Queue is NULL should never happen"); + } } void AppTask::DispatchEvent(AppEvent * aEvent) @@ -551,13 +668,17 @@ void AppTask::DispatchEvent(AppEvent * aEvent) void AppTask::UpdateClusterState(intptr_t context) { - uint8_t newValue = !BoltLockMgr().IsUnlocked(); + bool unlocked = LockMgr().NextState(); + DlLockState newState = unlocked ? DlLockState::kUnlocked : DlLockState::kLocked; + + DlOperationSource source = DlOperationSource::kUnspecified; + + // write the new lock value + EmberAfStatus status = + DoorLockServer::Instance().SetLockState(1, newState, source) ? EMBER_ZCL_STATUS_SUCCESS : EMBER_ZCL_STATUS_FAILURE; - // write the new on/off value - EmberAfStatus status = emberAfWriteAttribute(1, ZCL_ON_OFF_CLUSTER_ID, ZCL_ON_OFF_ATTRIBUTE_ID, CLUSTER_MASK_SERVER, - (uint8_t *) &newValue, ZCL_BOOLEAN_ATTRIBUTE_TYPE); if (status != EMBER_ZCL_STATUS_SUCCESS) { - EFR32_LOG("ERR: updating on/off %x", status); + EFR32_LOG("ERR: updating lock state %x", status); } } diff --git a/examples/lock-app/efr32/src/BoltLockManager.cpp b/examples/lock-app/efr32/src/BoltLockManager.cpp deleted file mode 100644 index e68f67d52fbe17..00000000000000 --- a/examples/lock-app/efr32/src/BoltLockManager.cpp +++ /dev/null @@ -1,225 +0,0 @@ -/* - * - * Copyright (c) 2020 Project CHIP Authors - * Copyright (c) 2019 Google LLC. - * 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 "BoltLockManager.h" - -#include "AppConfig.h" -#include "AppTask.h" -#include - -BoltLockManager BoltLockManager::sLock; - -TimerHandle_t sLockTimer; - -CHIP_ERROR BoltLockManager::Init() -{ - // Create FreeRTOS sw timer for lock timer. - sLockTimer = xTimerCreate("lockTmr", // Just a text name, not used by the RTOS kernel - 1, // == default timer period (mS) - false, // no timer reload (==one-shot) - (void *) this, // init timer id = lock obj context - TimerEventHandler // timer callback handler - ); - - if (sLockTimer == NULL) - { - EFR32_LOG("sLockTimer timer create failed"); - appError(APP_ERROR_CREATE_TIMER_FAILED); - } - - mState = kState_LockingCompleted; - mAutoLockTimerArmed = false; - mAutoRelock = false; - mAutoLockDuration = 0; - - return CHIP_NO_ERROR; -} - -void BoltLockManager::SetCallbacks(Callback_fn_initiated aActionInitiated_CB, Callback_fn_completed aActionCompleted_CB) -{ - mActionInitiated_CB = aActionInitiated_CB; - mActionCompleted_CB = aActionCompleted_CB; -} - -bool BoltLockManager::IsActionInProgress() -{ - return (mState == kState_LockingInitiated || mState == kState_UnlockingInitiated); -} - -bool BoltLockManager::IsUnlocked() -{ - return (mState == kState_UnlockingCompleted); -} - -void BoltLockManager::EnableAutoRelock(bool aOn) -{ - mAutoRelock = aOn; -} - -void BoltLockManager::SetAutoLockDuration(uint32_t aDurationInSecs) -{ - mAutoLockDuration = aDurationInSecs; -} - -bool BoltLockManager::InitiateAction(int32_t aActor, Action_t aAction) -{ - bool action_initiated = false; - State_t new_state; - - // Initiate Lock/Unlock Action only when the previous one is complete. - if (mState == kState_LockingCompleted && aAction == UNLOCK_ACTION) - { - action_initiated = true; - - new_state = kState_UnlockingInitiated; - } - else if (mState == kState_UnlockingCompleted && aAction == LOCK_ACTION) - { - action_initiated = true; - - new_state = kState_LockingInitiated; - } - - if (action_initiated) - { - if (mAutoLockTimerArmed && new_state == kState_LockingInitiated) - { - // If auto lock timer has been armed and someone initiates locking, - // cancel the timer and continue as normal. - mAutoLockTimerArmed = false; - - CancelTimer(); - } - - StartTimer(ACTUATOR_MOVEMENT_PERIOS_MS); - - // Since the timer started successfully, update the state and trigger callback - mState = new_state; - - if (mActionInitiated_CB) - { - mActionInitiated_CB(aAction, aActor); - } - } - - return action_initiated; -} - -void BoltLockManager::StartTimer(uint32_t aTimeoutMs) -{ - if (xTimerIsTimerActive(sLockTimer)) - { - EFR32_LOG("app timer already started!"); - CancelTimer(); - } - - // timer is not active, change its period to required value (== restart). - // FreeRTOS- Block for a maximum of 100 ticks if the change period command - // cannot immediately be sent to the timer command queue. - if (xTimerChangePeriod(sLockTimer, (aTimeoutMs / portTICK_PERIOD_MS), 100) != pdPASS) - { - EFR32_LOG("sLockTimer timer start() failed"); - appError(APP_ERROR_START_TIMER_FAILED); - } -} - -void BoltLockManager::CancelTimer(void) -{ - if (xTimerStop(sLockTimer, 0) == pdFAIL) - { - EFR32_LOG("Lock timer timer stop() failed"); - appError(APP_ERROR_STOP_TIMER_FAILED); - } -} - -void BoltLockManager::TimerEventHandler(TimerHandle_t xTimer) -{ - // Get lock obj context from timer id. - BoltLockManager * lock = static_cast(pvTimerGetTimerID(xTimer)); - - // The timer event handler will be called in the context of the timer task - // once sLockTimer expires. Post an event to apptask queue with the actual handler - // so that the event can be handled in the context of the apptask. - AppEvent event; - event.Type = AppEvent::kEventType_Timer; - event.TimerEvent.Context = lock; - if (lock->mAutoLockTimerArmed) - { - event.Handler = AutoReLockTimerEventHandler; - } - else - { - event.Handler = ActuatorMovementTimerEventHandler; - } - GetAppTask().PostEvent(&event); -} - -void BoltLockManager::AutoReLockTimerEventHandler(AppEvent * aEvent) -{ - BoltLockManager * lock = static_cast(aEvent->TimerEvent.Context); - int32_t actor = 0; - - // Make sure auto lock timer is still armed. - if (!lock->mAutoLockTimerArmed) - { - return; - } - - lock->mAutoLockTimerArmed = false; - - EFR32_LOG("Auto Re-Lock has been triggered!"); - - lock->InitiateAction(actor, LOCK_ACTION); -} - -void BoltLockManager::ActuatorMovementTimerEventHandler(AppEvent * aEvent) -{ - Action_t actionCompleted = INVALID_ACTION; - - BoltLockManager * lock = static_cast(aEvent->TimerEvent.Context); - - if (lock->mState == kState_LockingInitiated) - { - lock->mState = kState_LockingCompleted; - actionCompleted = LOCK_ACTION; - } - else if (lock->mState == kState_UnlockingInitiated) - { - lock->mState = kState_UnlockingCompleted; - actionCompleted = UNLOCK_ACTION; - } - - if (actionCompleted != INVALID_ACTION) - { - if (lock->mActionCompleted_CB) - { - lock->mActionCompleted_CB(actionCompleted); - } - - if (lock->mAutoRelock && actionCompleted == UNLOCK_ACTION) - { - // Start the timer for auto relock - lock->StartTimer(lock->mAutoLockDuration * 1000); - - lock->mAutoLockTimerArmed = true; - - EFR32_LOG("Auto Re-lock enabled. Will be triggered in %u seconds", lock->mAutoLockDuration); - } - } -} diff --git a/examples/lock-app/efr32/src/LockManager.cpp b/examples/lock-app/efr32/src/LockManager.cpp new file mode 100644 index 00000000000000..39b507daa4e6d4 --- /dev/null +++ b/examples/lock-app/efr32/src/LockManager.cpp @@ -0,0 +1,421 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * Copyright (c) 2019 Google LLC. + * 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 "LockManager.h" + +#include "AppConfig.h" +#include "AppTask.h" +#include +#include +#include + +LockManager LockManager::sLock; + +TimerHandle_t sLockTimer; + +using namespace ::chip::DeviceLayer::Internal; + +CHIP_ERROR LockManager::Init(chip::app::DataModel::Nullable state) +{ + // Create FreeRTOS sw timer for lock timer. + sLockTimer = xTimerCreate("lockTmr", // Just a text name, not used by the RTOS kernel + 1, // == default timer period (mS) + false, // no timer reload (==one-shot) + (void *) this, // init timer id = lock obj context + TimerEventHandler // timer callback handler + ); + + if (sLockTimer == NULL) + { + EFR32_LOG("sLockTimer timer create failed"); + return APP_ERROR_CREATE_TIMER_FAILED; + } + + if (state.Value() == DlLockState::kUnlocked) + mState = kState_UnlockCompleted; + else + mState = kState_LockCompleted; + + return CHIP_NO_ERROR; +} + +bool LockManager::ReadConfigValues() +{ + size_t outLen; + EFR32Config::ReadConfigValueBin(EFR32Config::kConfigKey_LockUser, reinterpret_cast(&mLockUser), + sizeof(EmberAfPluginDoorLockUserInfo), outLen); + EFR32Config::ReadConfigValueBin(EFR32Config::kConfigKey_Credential, reinterpret_cast(&mLockCredentials), + sizeof(EmberAfPluginDoorLockCredentialInfo), outLen); + + EFR32Config::ReadConfigValueStr(EFR32Config::kConfigKey_LockUserName, mUserName, DOOR_LOCK_USER_NAME_BUFFER_SIZE, outLen); + + EFR32Config::ReadConfigValueBin(EFR32Config::kConfigKey_CredentialData, mCredentialData, sizeof(mCredentialData), outLen); + + EFR32Config::ReadConfigValueBin(EFR32Config::kConfigKey_UserCredentials, reinterpret_cast(&mCredentials), + sizeof(DlCredential), outLen); + + return true; +} + +void LockManager::SetCallbacks(Callback_fn_initiated aActionInitiated_CB, Callback_fn_completed aActionCompleted_CB) +{ + mActionInitiated_CB = aActionInitiated_CB; + mActionCompleted_CB = aActionCompleted_CB; +} + +bool LockManager::IsActionInProgress() +{ + return (mState == kState_LockInitiated || mState == kState_UnlockInitiated); +} + +bool LockManager::NextState() +{ + return (mState == kState_UnlockCompleted); +} + +bool LockManager::InitiateAction(int32_t aActor, Action_t aAction) +{ + bool action_initiated = false; + State_t new_state; + + // Initiate Turn Lock/Unlock Action only when the previous one is complete. + if (mState == kState_LockCompleted && aAction == UNLOCK_ACTION) + { + action_initiated = true; + + new_state = kState_UnlockInitiated; + } + else if (mState == kState_UnlockCompleted && aAction == LOCK_ACTION) + { + action_initiated = true; + + new_state = kState_LockInitiated; + } + + if (action_initiated) + { + + StartTimer(ACTUATOR_MOVEMENT_PERIOS_MS); + + // Since the timer started successfully, update the state and trigger callback + mState = new_state; + + if (mActionInitiated_CB) + { + mActionInitiated_CB(aAction, aActor); + } + } + + return action_initiated; +} + +void LockManager::StartTimer(uint32_t aTimeoutMs) +{ + if (xTimerIsTimerActive(sLockTimer)) + { + EFR32_LOG("app timer already started!"); + CancelTimer(); + } + + // timer is not active, change its period to required value (== restart). + // FreeRTOS- Block for a maximum of 100 ticks if the change period command + // cannot immediately be sent to the timer command queue. + if (xTimerChangePeriod(sLockTimer, (aTimeoutMs / portTICK_PERIOD_MS), 100) != pdPASS) + { + EFR32_LOG("sLockTimer timer start() failed"); + appError(APP_ERROR_START_TIMER_FAILED); + } +} + +void LockManager::CancelTimer(void) +{ + if (xTimerStop(sLockTimer, 0) == pdFAIL) + { + EFR32_LOG("sLockTimer stop() failed"); + appError(APP_ERROR_STOP_TIMER_FAILED); + } +} + +void LockManager::TimerEventHandler(TimerHandle_t xTimer) +{ + // Get lock obj context from timer id. + LockManager * lock = static_cast(pvTimerGetTimerID(xTimer)); + + // The timer event handler will be called in the context of the timer task + // once sLockTimer expires. Post an event to apptask queue with the actual handler + // so that the event can be handled in the context of the apptask. + AppEvent event; + event.Type = AppEvent::kEventType_Timer; + event.TimerEvent.Context = lock; + event.Handler = ActuatorMovementTimerEventHandler; + GetAppTask().PostEvent(&event); +} + +void LockManager::ActuatorMovementTimerEventHandler(AppEvent * aEvent) +{ + Action_t actionCompleted = INVALID_ACTION; + + LockManager * lock = static_cast(aEvent->TimerEvent.Context); + + if (lock->mState == kState_LockInitiated) + { + lock->mState = kState_LockCompleted; + actionCompleted = LOCK_ACTION; + } + else if (lock->mState == kState_UnlockInitiated) + { + lock->mState = kState_UnlockCompleted; + actionCompleted = UNLOCK_ACTION; + } + + if (actionCompleted != INVALID_ACTION) + { + if (lock->mActionCompleted_CB) + { + lock->mActionCompleted_CB(actionCompleted); + } + } +} + +bool LockManager::Lock(chip::EndpointId endpointId, const Optional & pin, DlOperationError & err) +{ + return setLockState(endpointId, DlLockState::kLocked, pin, err); +} + +bool LockManager::Unlock(chip::EndpointId endpointId, const Optional & pin, DlOperationError & err) +{ + return setLockState(endpointId, DlLockState::kUnlocked, pin, err); +} + +bool LockManager::GetUser(uint16_t userIndex, EmberAfPluginDoorLockUserInfo & user) const +{ + // chip::ByteSpan credentialData(mLockCredentials.credentialData, mLockCredentials.credentialDataSize); + ChipLogProgress(Zcl, "Door Lock App: LockManager::GetUser [endpoint=%d,userIndex=%hu]", mEndpointId, userIndex); + + const auto & userInDb = mLockUser; + user.userStatus = userInDb.userStatus; + if (DlUserStatus::kAvailable == user.userStatus) + { + ChipLogDetail(Zcl, "Found unoccupied user [endpoint=%d]", mEndpointId); + return true; + } + + user.userName = chip::CharSpan(userInDb.userName.data(), userInDb.userName.size()); + user.credentials = chip::Span(userInDb.credentials.data(), userInDb.credentials.size()); + user.userUniqueId = userInDb.userUniqueId; + user.userType = userInDb.userType; + user.credentialRule = userInDb.credentialRule; + user.createdBy = userInDb.createdBy; + user.lastModifiedBy = userInDb.lastModifiedBy; + + ChipLogDetail(Zcl, + "Found occupied user " + "[endpoint=%d,name=\"%.*s\",credentialsCount=%u,uniqueId=%lx,type=%u,credentialRule=%u," + "createdBy=%d,lastModifiedBy=%d]", + mEndpointId, 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; +} + +bool LockManager::SetUser(uint16_t userIndex, chip::FabricIndex creator, chip::FabricIndex modifier, + const chip::CharSpan & userName, uint32_t uniqueId, DlUserStatus userStatus, DlUserType usertype, + DlCredentialRule credentialRule, const DlCredential * credentials, size_t totalCredentials) +{ + ChipLogProgress(Zcl, + "Door Lock App: LockManager::SetUser " + "[endpoint=%d,userIndex=%d,creator=%d,modifier=%d,userName=%s,uniqueId=%ld " + "userStatus=%u,userType=%u,credentialRule=%u,credentials=%p,totalCredentials=%u]", + mEndpointId, userIndex, creator, modifier, userName.data(), uniqueId, to_underlying(userStatus), + to_underlying(usertype), to_underlying(credentialRule), credentials, totalCredentials); + + auto & userInStorage = mLockUser; + + if (userName.size() > DOOR_LOCK_MAX_USER_NAME_SIZE) + { + ChipLogError(Zcl, "Cannot set user - user name is too long [endpoint=%d,index=%d]", mEndpointId, userIndex); + return false; + } + + if (totalCredentials > sizeof(DOOR_LOCK_MAX_CREDENTIALS_PER_USER)) + { + ChipLogError(Zcl, "Cannot set user - total number of credentials is too big [endpoint=%d,index=%d,totalCredentials=%u]", + mEndpointId, userIndex, totalCredentials); + return false; + } + + chip::Platform::CopyString(mUserName, userName); + mUserName[userName.size()] = 0; + userInStorage.userName = chip::CharSpan(mUserName, userName.size()); + userInStorage.userUniqueId = uniqueId; + userInStorage.userStatus = userStatus; + userInStorage.userType = usertype; + userInStorage.credentialRule = credentialRule; + userInStorage.lastModifiedBy = modifier; + userInStorage.createdBy = creator; + + for (size_t i = 0; i < totalCredentials; ++i) + { + mCredentials[i] = credentials[i]; + mCredentials[i].CredentialType = 1; + mCredentials[i].CredentialIndex = i + 1; + } + + userInStorage.credentials = chip::Span(mCredentials, totalCredentials); + + // Save user information in NVM flash + EFR32Config::WriteConfigValueBin(EFR32Config::kConfigKey_LockUser, reinterpret_cast(&userInStorage), + sizeof(EmberAfPluginDoorLockUserInfo)); + + EFR32Config::WriteConfigValueBin(EFR32Config::kConfigKey_UserCredentials, reinterpret_cast(&mCredentials), + sizeof(DlCredential)); + + EFR32Config::WriteConfigValueStr(EFR32Config::kConfigKey_LockUserName, mUserName, sizeof(userName.size())); + + ChipLogProgress(Zcl, "Successfully set the user [mEndpointId=%d,index=%d]", mEndpointId, userIndex); + + return true; +} + +bool LockManager::GetCredential(chip::EndpointId endpointId, uint16_t credentialIndex, DlCredentialType credentialType, + EmberAfPluginDoorLockCredentialInfo & credential) const +{ + ChipLogProgress(Zcl, "Lock App: LockManager::GetCredential [credentialType=%u]", to_underlying(credentialType)); + + const auto & credentialInStorage = mLockCredentials; + + credential.status = credentialInStorage.status; + if (DlCredentialStatus::kAvailable == credential.status) + { + ChipLogDetail(Zcl, "Found unoccupied credential "); + return true; + } + credential.credentialType = credentialInStorage.credentialType; + credential.credentialData = credentialInStorage.credentialData; + + ChipLogDetail(Zcl, "Found occupied credential [type=%u,dataSize=%u]", to_underlying(credential.credentialType), + credential.credentialData.size()); + + return true; +} + +bool LockManager::SetCredential(chip::EndpointId endpointId, uint16_t credentialIndex, DlCredentialStatus credentialStatus, + DlCredentialType credentialType, const chip::ByteSpan & credentialData) +{ + ChipLogProgress(Zcl, + "Door Lock App: LockManager::SetCredential " + "[credentialStatus=%u,credentialType=%u,credentialDataSize=%u]", + to_underlying(credentialStatus), to_underlying(credentialType), credentialData.size()); + + auto & credentialInStorage = mLockCredentials; + if (credentialData.size() > DOOR_LOCK_CREDENTIAL_INFO_MAX_DATA_SIZE) + { + ChipLogError(Zcl, + "Cannot get the credential - data size exceeds limit " + "[dataSize=%u,maxDataSize=%u]", + credentialData.size(), DOOR_LOCK_CREDENTIAL_INFO_MAX_DATA_SIZE); + return false; + } + credentialInStorage.status = credentialStatus; + credentialInStorage.credentialType = credentialType; + + memcpy(mCredentialData, credentialData.data(), credentialData.size()); + mCredentialData[credentialData.size()] = 0; + + credentialInStorage.credentialData = chip::ByteSpan{ mCredentialData, credentialData.size() }; + + // Save user information in NVM flash + EFR32Config::WriteConfigValueBin(EFR32Config::kConfigKey_Credential, reinterpret_cast(&credentialInStorage), + sizeof(EmberAfPluginDoorLockCredentialInfo)); + + EFR32Config::WriteConfigValueBin(EFR32Config::kConfigKey_CredentialData, reinterpret_cast(&mCredentialData), + credentialData.size()); + + ChipLogProgress(Zcl, "Successfully set the credential [credentialType=%u]", to_underlying(credentialType)); + + return true; +} + +const char * LockManager::lockStateToString(DlLockState lockState) const +{ + switch (lockState) + { + case DlLockState::kNotFullyLocked: + return "Not Fully Locked"; + case DlLockState::kLocked: + return "Locked"; + case DlLockState::kUnlocked: + return "Unlocked"; + } + + return "Unknown"; +} + +bool LockManager::setLockState(chip::EndpointId endpointId, DlLockState lockState, const Optional & pin, + DlOperationError & err) +{ + DlLockState curState = DlLockState::kLocked; + if (mState == kState_UnlockCompleted) + curState = DlLockState::kUnlocked; + + if (curState == lockState) + { + ChipLogDetail(Zcl, "Door Lock App: door is already locked, ignoring command to set lock state to \"%s\" [endpointId=%d]", + lockStateToString(lockState), mEndpointId); + return false; + } + + if (!pin.HasValue()) + { + ChipLogDetail(Zcl, "Door Lock App: PIN code is not specified, setting door lock state to \"%s\" [endpointId=%d]", + lockStateToString(lockState), mEndpointId); + curState = lockState; + + return true; + } + + // Check the PIN code + for (uint8_t i; i < 10; i++) + { + if (mLockCredentials.credentialType != DlCredentialType::kPin || mLockCredentials.status == DlCredentialStatus::kAvailable) + { + continue; + } + + if (mLockCredentials.credentialData.data_equal(pin.Value())) + { + ChipLogDetail(Zcl, + "Lock App: specified PIN code was found in the database, setting lock state to \"%s\" [endpointId=%d]", + lockStateToString(lockState), mEndpointId); + + curState = lockState; + + return true; + } + } + + ChipLogDetail(Zcl, + "Door Lock App: specified PIN code was not found in the database, ignoring command to set lock state to \"%s\" " + "[endpointId=%d]", + lockStateToString(lockState), mEndpointId); + + err = DlOperationError::kInvalidCredential; + return false; +} diff --git a/examples/lock-app/efr32/src/ZclCallbacks.cpp b/examples/lock-app/efr32/src/ZclCallbacks.cpp index bdccc6859fbf4c..1f8bd0600ce791 100644 --- a/examples/lock-app/efr32/src/ZclCallbacks.cpp +++ b/examples/lock-app/efr32/src/ZclCallbacks.cpp @@ -21,7 +21,8 @@ */ #include "AppConfig.h" -#include "BoltLockManager.h" +#include "LockManager.h" +#include #include #include @@ -30,18 +31,22 @@ using namespace ::chip; using namespace ::chip::app::Clusters; +using namespace ::chip::DeviceLayer::Internal; void MatterPostAttributeChangeCallback(const chip::app::ConcreteAttributePath & attributePath, uint8_t mask, uint8_t type, uint16_t size, uint8_t * value) { - if (attributePath.mClusterId == OnOff::Id && attributePath.mAttributeId == OnOff::Attributes::OnOff::Id) + ClusterId clusterId = attributePath.mClusterId; + AttributeId attributeId = attributePath.mAttributeId; + ChipLogProgress(Zcl, "Cluster callback: " ChipLogFormatMEI, ChipLogValueMEI(clusterId)); + + if (clusterId == DoorLock::Id && attributeId == DoorLock::Attributes::LockState::Id) { - BoltLockMgr().InitiateAction(AppEvent::kEventType_Lock, - *value ? BoltLockManager::LOCK_ACTION : BoltLockManager::UNLOCK_ACTION); + ChipLogProgress(Zcl, "Door lock cluster: " ChipLogFormatMEI, ChipLogValueMEI(clusterId)); } } -/** @brief OnOff Cluster Init +/** @brief DoorLock Cluster Init * * This function is called when a specific cluster is initialized. It gives the * application an opportunity to take care of cluster initialization procedures. @@ -49,14 +54,85 @@ void MatterPostAttributeChangeCallback(const chip::app::ConcreteAttributePath & * * @param endpoint Ver.: always * - * TODO Issue #3841 - * emberAfOnOffClusterInitCallback happens before the stack initialize the cluster - * attributes to the default value. - * The logic here expects something similar to the deprecated Plugins callback - * emberAfPluginOnOffClusterServerPostInitCallback. - * */ -void emberAfOnOffClusterInitCallback(EndpointId endpoint) +void emberAfDoorLockClusterInitCallback(EndpointId endpoint) { // TODO: implement any additional Cluster Server init actions } + +bool emberAfPluginDoorLockOnDoorLockCommand(chip::EndpointId endpointId, const Optional & pinCode, DlOperationError & err) +{ + ChipLogProgress(Zcl, "Door Lock App: Lock Command endpoint=%d", endpointId); + bool status = LockMgr().Lock(endpointId, pinCode, err); + if (status == true) + { + LockMgr().InitiateAction(AppEvent::kEventType_Lock, LockManager::LOCK_ACTION); + } + return status; +} + +bool emberAfPluginDoorLockOnDoorUnlockCommand(chip::EndpointId endpointId, const Optional & pinCode, + DlOperationError & err) +{ + ChipLogProgress(Zcl, "Door Lock App: Unlock Command endpoint=%d", endpointId); + bool status = LockMgr().Unlock(endpointId, pinCode, err); + if (status == true) + { + LockMgr().InitiateAction(AppEvent::kEventType_Lock, LockManager::UNLOCK_ACTION); + } + + return status; +} + +bool emberAfPluginDoorLockGetCredential(chip::EndpointId endpointId, uint16_t credentialIndex, DlCredentialType credentialType, + EmberAfPluginDoorLockCredentialInfo & credential) +{ + return LockMgr().GetCredential(endpointId, credentialIndex, credentialType, credential); +} + +bool emberAfPluginDoorLockSetCredential(chip::EndpointId endpointId, uint16_t credentialIndex, DlCredentialStatus credentialStatus, + DlCredentialType credentialType, const chip::ByteSpan & credentialData) +{ + return LockMgr().SetCredential(endpointId, credentialIndex, credentialStatus, credentialType, credentialData); +} + +bool emberAfPluginDoorLockGetUser(chip::EndpointId endpointId, uint16_t userIndex, EmberAfPluginDoorLockUserInfo & user) +{ + return LockMgr().GetUser(userIndex, user); +} + +bool emberAfPluginDoorLockSetUser(chip::EndpointId endpointId, uint16_t userIndex, chip::FabricIndex creator, + chip::FabricIndex modifier, const chip::CharSpan & userName, uint32_t uniqueId, + DlUserStatus userStatus, DlUserType usertype, DlCredentialRule credentialRule, + const DlCredential * credentials, size_t totalCredentials) +{ + + return LockMgr().SetUser(userIndex, creator, modifier, userName, uniqueId, userStatus, usertype, credentialRule, credentials, + totalCredentials); +} + +// TODO: These functions will be supported by door-lock-server in the future. These are set to return failure until implemented. +DlStatus emberAfPluginDoorLockGetSchedule(chip::EndpointId endpointId, uint8_t weekdayIndex, uint16_t userIndex, + EmberAfPluginDoorLockWeekDaySchedule & schedule) +{ + return DlStatus::kFailure; +} + +DlStatus emberAfPluginDoorLockGetSchedule(chip::EndpointId endpointId, uint8_t yearDayIndex, uint16_t userIndex, + EmberAfPluginDoorLockYearDaySchedule & schedule) +{ + return DlStatus::kFailure; +} + +DlStatus emberAfPluginDoorLockSetSchedule(chip::EndpointId endpointId, uint8_t weekdayIndex, uint16_t userIndex, + DlScheduleStatus status, DlDaysMaskMap daysMask, uint8_t startHour, uint8_t startMinute, + uint8_t endHour, uint8_t endMinute) +{ + return DlStatus::kFailure; +} + +DlStatus emberAfPluginDoorLockSetSchedule(chip::EndpointId endpointId, uint8_t yearDayIndex, uint16_t userIndex, + DlScheduleStatus status, uint32_t localStartTime, uint32_t localEndTime) +{ + return DlStatus::kFailure; +} diff --git a/examples/lock-app/efr32/src/main.cpp b/examples/lock-app/efr32/src/main.cpp index a67a7b7967719c..79b1ff23c6053d 100644 --- a/examples/lock-app/efr32/src/main.cpp +++ b/examples/lock-app/efr32/src/main.cpp @@ -40,6 +40,10 @@ #include "sl_system_kernel.h" #include +#ifdef EFR32_OTA_ENABLED +#include "OTAConfig.h" +#endif // EFR32_OTA_ENABLED + #ifdef HEAP_MONITORING #include "MemMonitoring.h" #endif @@ -48,18 +52,6 @@ #include "lcd.h" #endif -#if PW_RPC_ENABLED -#include "Rpc.h" -#endif - -#ifdef ENABLE_CHIP_SHELL -#include "matter_shell.h" -#endif - -#ifdef EFR32_OTA_ENABLED -#include "OTAConfig.h" -#endif // EFR32_OTA_ENABLED - #include #if CHIP_ENABLE_OPENTHREAD #include @@ -78,6 +70,15 @@ #include "wfx_host_events.h" #endif /* RS911X_WIFI */ +#if PW_RPC_ENABLED +#include "Rpc.h" +#endif + +#ifdef ENABLE_CHIP_SHELL +#include "matter_shell.h" +#endif + +#define BLE_DEV_NAME "SiLabs-Door-Lock" using namespace ::chip; using namespace ::chip::Inet; using namespace ::chip::DeviceLayer; @@ -124,12 +125,15 @@ int main(void) chip::rpc::Init(); #endif +#ifdef HEAP_MONITORING + MemMonitoring::startHeapMonitoring(); +#endif + EFR32_LOG("=================================================="); - EFR32_LOG("chip-efr32-lock-example starting"); + EFR32_LOG("chip-efr32-door-lock-example starting"); EFR32_LOG("=================================================="); EFR32_LOG("Init CHIP Stack"); - // Init Chip memory management before the stack chip::Platform::MemoryInit(); @@ -139,7 +143,7 @@ int main(void) EFR32_LOG("PlatformMgr().InitChipStack() failed"); appError(ret); } - chip::DeviceLayer::ConnectivityMgr().SetBLEDeviceName("EFR32_LOCK"); + chip::DeviceLayer::ConnectivityMgr().SetBLEDeviceName(BLE_DEV_NAME); #if CHIP_ENABLE_OPENTHREAD EFR32_LOG("Initializing OpenThread stack"); ret = ThreadStackMgr().InitThreadStack(); @@ -180,6 +184,14 @@ int main(void) appError(ret); } +#ifdef WF200_WIFI + // Start wfx bus communication task. + wfx_bus_start(); +#ifdef SL_WFX_USE_SECURE_LINK + wfx_securelink_task_start(); // start securelink key renegotiation task +#endif // SL_WFX_USE_SECURE_LINK +#endif /* WF200_WIFI */ + #if CHIP_ENABLE_OPENTHREAD EFR32_LOG("Starting OpenThread task"); @@ -191,13 +203,13 @@ int main(void) appError(ret); } #endif // CHIP_ENABLE_OPENTHREAD -#ifdef WF200_WIFI - // Start wfx bus communication task. - wfx_bus_start(); -#ifdef SL_WFX_USE_SECURE_LINK - wfx_securelink_task_start(); // start securelink key renegotiation task -#endif // SL_WFX_USE_SECURE_LINK -#endif /* WF200_WIFI */ +#ifdef RS911X_WIFI + /* + * Start up any RSI interface stuff + * (Not required) - Note that wfx_wifi_start will deal with + * starting up a rsi task - which will initialize the SPI interface. + */ +#endif #ifdef EFR32_OTA_ENABLED chip::DeviceLayer::PlatformMgr().LockChipStack(); OTAConfig::Init(); diff --git a/examples/lock-app/efr32/with_pw_rpc.gni b/examples/lock-app/efr32/with_pw_rpc.gni index eddb9ae4278054..d0a8f2c0485f06 100644 --- a/examples/lock-app/efr32/with_pw_rpc.gni +++ b/examples/lock-app/efr32/with_pw_rpc.gni @@ -14,7 +14,6 @@ # add this gni as import in your build args to use pigweed in the example # 'import("//with_pw_rpc.gni")' -# *WIP* pigweed is not fully integrated in this EFR example yet import("//build_overrides/chip.gni") import("${chip_root}/config/efr32/lib/pw_rpc/pw_rpc.gni") diff --git a/examples/lock-app/esp32/main/CMakeLists.txt b/examples/lock-app/esp32/main/CMakeLists.txt index 85f8d7b0963d93..f194e021bbfdf5 100644 --- a/examples/lock-app/esp32/main/CMakeLists.txt +++ b/examples/lock-app/esp32/main/CMakeLists.txt @@ -61,6 +61,8 @@ idf_component_register(INCLUDE_DIRS "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/power-source-configuration-server" "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/power-source-server" "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/door-lock-server" + "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/identify-server" + "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/groups-server" PRIV_REQUIRES bt chip QRCode) get_filename_component(CHIP_ROOT ${CMAKE_SOURCE_DIR}/third_party/connectedhomeip REALPATH) @@ -174,6 +176,8 @@ idf_component_register(PRIV_INCLUDE_DIRS "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/power-source-server" "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/user-label-server" "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/door-lock-server" + "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/identify-server" + "${CMAKE_SOURCE_DIR}/third_party/connectedhomeip/src/app/clusters/groups-server" PRIV_REQUIRES chip QRCode bt) set_property(TARGET ${COMPONENT_LIB} PROPERTY CXX_STANDARD 17) diff --git a/examples/lock-app/lock-common/lock-app.matter b/examples/lock-app/lock-common/lock-app.matter index 0d02f98dc247a2..e4a3d37b2cf6f2 100644 --- a/examples/lock-app/lock-common/lock-app.matter +++ b/examples/lock-app/lock-common/lock-app.matter @@ -927,6 +927,99 @@ server cluster GeneralDiagnostics = 51 { readonly attribute int16u clusterRevision = 65533; } +server cluster Groups = 4 { + readonly attribute bitmap8 nameSupport = 0; + readonly attribute int16u clusterRevision = 65533; + + request struct AddGroupRequest { + group_id groupId = 0; + CHAR_STRING groupName = 1; + } + + request struct ViewGroupRequest { + group_id groupId = 0; + } + + request struct GetGroupMembershipRequest { + group_id groupList[] = 0; + } + + request struct RemoveGroupRequest { + group_id groupId = 0; + } + + request struct AddGroupIfIdentifyingRequest { + group_id groupId = 0; + CHAR_STRING groupName = 1; + } + + response struct AddGroupResponse = 0 { + ENUM8 status = 0; + group_id groupId = 1; + } + + response struct ViewGroupResponse = 1 { + ENUM8 status = 0; + group_id groupId = 1; + CHAR_STRING groupName = 2; + } + + response struct GetGroupMembershipResponse = 2 { + nullable INT8U capacity = 0; + group_id groupList[] = 1; + } + + response struct RemoveGroupResponse = 3 { + ENUM8 status = 0; + group_id groupId = 1; + } + + command access(invoke: manage) AddGroup(AddGroupRequest): AddGroupResponse = 0; + command ViewGroup(ViewGroupRequest): ViewGroupResponse = 1; + command GetGroupMembership(GetGroupMembershipRequest): GetGroupMembershipResponse = 2; + command access(invoke: manage) RemoveGroup(RemoveGroupRequest): RemoveGroupResponse = 3; + command access(invoke: manage) RemoveAllGroups(): DefaultSuccess = 4; + command access(invoke: manage) AddGroupIfIdentifying(AddGroupIfIdentifyingRequest): DefaultSuccess = 5; +} + +server cluster Identify = 3 { + enum IdentifyEffectIdentifier : ENUM8 { + kBlink = 0; + kBreathe = 1; + kOkay = 2; + kChannelChange = 11; + kFinishEffect = 254; + kStopEffect = 255; + } + + enum IdentifyEffectVariant : ENUM8 { + kDefault = 0; + } + + enum IdentifyIdentifyType : ENUM8 { + kNone = 0; + kVisibleLight = 1; + kVisibleLED = 2; + kAudibleBeep = 3; + kDisplay = 4; + kActuator = 5; + } + + attribute int16u identifyTime = 0; + readonly attribute int16u clusterRevision = 65533; + + request struct IdentifyRequest { + INT16U identifyTime = 0; + } + + response struct IdentifyQueryResponse = 0 { + INT16U timeout = 0; + } + + command access(invoke: manage) Identify(IdentifyRequest): DefaultSuccess = 0; + command access(invoke: manage) IdentifyQuery(): IdentifyQueryResponse = 1; +} + server cluster LocalizationConfiguration = 43 { attribute char_string<35> activeLocale = 1; readonly attribute CHAR_STRING supportedLocales[] = 2; @@ -1735,6 +1828,8 @@ endpoint 0 { endpoint 1 { server cluster Descriptor; server cluster DoorLock; + server cluster Groups; + server cluster Identify; server cluster OnOff; server cluster PowerSource; } diff --git a/examples/lock-app/lock-common/lock-app.zap b/examples/lock-app/lock-common/lock-app.zap index ee25a90a9d4b5a..52143ca2713b50 100755 --- a/examples/lock-app/lock-common/lock-app.zap +++ b/examples/lock-app/lock-common/lock-app.zap @@ -5128,7 +5128,7 @@ "mfgCode": null, "define": "IDENTIFY_CLUSTER", "side": "server", - "enabled": 0, + "enabled": 1, "commands": [ { "name": "IdentifyQueryResponse", @@ -5253,7 +5253,7 @@ "mfgCode": null, "define": "GROUPS_CLUSTER", "side": "server", - "enabled": 0, + "enabled": 1, "commands": [ { "name": "AddGroupResponse", @@ -6719,10 +6719,10 @@ "mfgCode": null, "side": "server", "included": 1, - "storageOption": "RAM", + "storageOption": "NVM", "singleton": 0, "bounded": 0, - "defaultValue": "2", + "defaultValue": "1", "reportable": 1, "minInterval": 0, "maxInterval": 65344, @@ -7388,6 +7388,36 @@ "maxInterval": 65534, "reportableChange": 0 }, + { + "name": "GeneratedCommandList", + "code": 65528, + "mfgCode": null, + "side": "server", + "included": 0, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, + { + "name": "AcceptedCommandList", + "code": 65529, + "mfgCode": null, + "side": "server", + "included": 0, + "storageOption": "External", + "singleton": 0, + "bounded": 0, + "defaultValue": "", + "reportable": 1, + "minInterval": 1, + "maxInterval": 65534, + "reportableChange": 0 + }, { "name": "AttributeList", "code": 65531, @@ -7556,4 +7586,4 @@ } ], "log": [] -} +} \ No newline at end of file diff --git a/src/platform/EFR32/EFR32Config.h b/src/platform/EFR32/EFR32Config.h index 1943b902ca2e61..78019633342ae7 100644 --- a/src/platform/EFR32/EFR32Config.h +++ b/src/platform/EFR32/EFR32Config.h @@ -114,6 +114,11 @@ class EFR32Config static constexpr Key kConfigKey_WiFiPSK = EFR32ConfigKey(kMatterConfig_KeyBase, 0x0D); static constexpr Key kConfigKey_WiFiSEC = EFR32ConfigKey(kMatterConfig_KeyBase, 0x0E); static constexpr Key kConfigKey_GroupKeyBase = EFR32ConfigKey(kMatterConfig_KeyBase, 0x0F); + static constexpr Key kConfigKey_LockUser = EFR32ConfigKey(kMatterConfig_KeyBase, 0x10); + static constexpr Key kConfigKey_Credential = EFR32ConfigKey(kMatterConfig_KeyBase, 0x11); + static constexpr Key kConfigKey_LockUserName = EFR32ConfigKey(kMatterConfig_KeyBase, 0x12); + static constexpr Key kConfigKey_CredentialData = EFR32ConfigKey(kMatterConfig_KeyBase, 0x13); + static constexpr Key kConfigKey_UserCredentials = EFR32ConfigKey(kMatterConfig_KeyBase, 0x14); static constexpr Key kConfigKey_GroupKeyMax = EFR32ConfigKey(kMatterConfig_KeyBase, 0x1E); // Allows 16 Group Keys to be created. static constexpr Key kConfigKey_UniqueId = EFR32ConfigKey(kMatterFactory_KeyBase, 0x1F); diff --git a/zzz_generated/lock-app/zap-generated/IMClusterCommandHandler.cpp b/zzz_generated/lock-app/zap-generated/IMClusterCommandHandler.cpp index e65fe6cb694505..df6e20c7b712be 100644 --- a/zzz_generated/lock-app/zap-generated/IMClusterCommandHandler.cpp +++ b/zzz_generated/lock-app/zap-generated/IMClusterCommandHandler.cpp @@ -392,6 +392,134 @@ void DispatchServerCommand(CommandHandler * apCommandObj, const ConcreteCommandP } // namespace GeneralCommissioning +namespace Groups { + +void DispatchServerCommand(CommandHandler * apCommandObj, const ConcreteCommandPath & aCommandPath, TLV::TLVReader & aDataTlv) +{ + CHIP_ERROR TLVError = CHIP_NO_ERROR; + bool wasHandled = false; + { + switch (aCommandPath.mCommandId) + { + case Commands::AddGroup::Id: { + Commands::AddGroup::DecodableType commandData; + TLVError = DataModel::Decode(aDataTlv, commandData); + if (TLVError == CHIP_NO_ERROR) + { + wasHandled = emberAfGroupsClusterAddGroupCallback(apCommandObj, aCommandPath, commandData); + } + break; + } + case Commands::ViewGroup::Id: { + Commands::ViewGroup::DecodableType commandData; + TLVError = DataModel::Decode(aDataTlv, commandData); + if (TLVError == CHIP_NO_ERROR) + { + wasHandled = emberAfGroupsClusterViewGroupCallback(apCommandObj, aCommandPath, commandData); + } + break; + } + case Commands::GetGroupMembership::Id: { + Commands::GetGroupMembership::DecodableType commandData; + TLVError = DataModel::Decode(aDataTlv, commandData); + if (TLVError == CHIP_NO_ERROR) + { + wasHandled = emberAfGroupsClusterGetGroupMembershipCallback(apCommandObj, aCommandPath, commandData); + } + break; + } + case Commands::RemoveGroup::Id: { + Commands::RemoveGroup::DecodableType commandData; + TLVError = DataModel::Decode(aDataTlv, commandData); + if (TLVError == CHIP_NO_ERROR) + { + wasHandled = emberAfGroupsClusterRemoveGroupCallback(apCommandObj, aCommandPath, commandData); + } + break; + } + case Commands::RemoveAllGroups::Id: { + Commands::RemoveAllGroups::DecodableType commandData; + TLVError = DataModel::Decode(aDataTlv, commandData); + if (TLVError == CHIP_NO_ERROR) + { + wasHandled = emberAfGroupsClusterRemoveAllGroupsCallback(apCommandObj, aCommandPath, commandData); + } + break; + } + case Commands::AddGroupIfIdentifying::Id: { + Commands::AddGroupIfIdentifying::DecodableType commandData; + TLVError = DataModel::Decode(aDataTlv, commandData); + if (TLVError == CHIP_NO_ERROR) + { + wasHandled = emberAfGroupsClusterAddGroupIfIdentifyingCallback(apCommandObj, aCommandPath, commandData); + } + break; + } + default: { + // Unrecognized command ID, error status will apply. + apCommandObj->AddStatus(aCommandPath, Protocols::InteractionModel::Status::UnsupportedCommand); + ChipLogError(Zcl, "Unknown command " ChipLogFormatMEI " for cluster " ChipLogFormatMEI, + ChipLogValueMEI(aCommandPath.mCommandId), ChipLogValueMEI(aCommandPath.mClusterId)); + return; + } + } + } + + if (CHIP_NO_ERROR != TLVError || !wasHandled) + { + apCommandObj->AddStatus(aCommandPath, Protocols::InteractionModel::Status::InvalidCommand); + ChipLogProgress(Zcl, "Failed to dispatch command, TLVError=%" CHIP_ERROR_FORMAT, TLVError.Format()); + } +} + +} // namespace Groups + +namespace Identify { + +void DispatchServerCommand(CommandHandler * apCommandObj, const ConcreteCommandPath & aCommandPath, TLV::TLVReader & aDataTlv) +{ + CHIP_ERROR TLVError = CHIP_NO_ERROR; + bool wasHandled = false; + { + switch (aCommandPath.mCommandId) + { + case Commands::Identify::Id: { + Commands::Identify::DecodableType commandData; + TLVError = DataModel::Decode(aDataTlv, commandData); + if (TLVError == CHIP_NO_ERROR) + { + wasHandled = emberAfIdentifyClusterIdentifyCallback(apCommandObj, aCommandPath, commandData); + } + break; + } + case Commands::IdentifyQuery::Id: { + Commands::IdentifyQuery::DecodableType commandData; + TLVError = DataModel::Decode(aDataTlv, commandData); + if (TLVError == CHIP_NO_ERROR) + { + wasHandled = emberAfIdentifyClusterIdentifyQueryCallback(apCommandObj, aCommandPath, commandData); + } + break; + } + default: { + // Unrecognized command ID, error status will apply. + apCommandObj->AddStatus(aCommandPath, Protocols::InteractionModel::Status::UnsupportedCommand); + ChipLogError(Zcl, "Unknown command " ChipLogFormatMEI " for cluster " ChipLogFormatMEI, + ChipLogValueMEI(aCommandPath.mCommandId), ChipLogValueMEI(aCommandPath.mClusterId)); + return; + } + } + } + + if (CHIP_NO_ERROR != TLVError || !wasHandled) + { + apCommandObj->AddStatus(aCommandPath, Protocols::InteractionModel::Status::InvalidCommand); + ChipLogProgress(Zcl, "Failed to dispatch command, TLVError=%" CHIP_ERROR_FORMAT, TLVError.Format()); + } +} + +} // namespace Identify + namespace NetworkCommissioning { void DispatchServerCommand(CommandHandler * apCommandObj, const ConcreteCommandPath & aCommandPath, TLV::TLVReader & aDataTlv) @@ -816,6 +944,12 @@ void DispatchSingleClusterCommand(const ConcreteCommandPath & aCommandPath, TLV: case Clusters::GeneralCommissioning::Id: Clusters::GeneralCommissioning::DispatchServerCommand(apCommandObj, aCommandPath, aReader); break; + case Clusters::Groups::Id: + Clusters::Groups::DispatchServerCommand(apCommandObj, aCommandPath, aReader); + break; + case Clusters::Identify::Id: + Clusters::Identify::DispatchServerCommand(apCommandObj, aCommandPath, aReader); + break; case Clusters::NetworkCommissioning::Id: Clusters::NetworkCommissioning::DispatchServerCommand(apCommandObj, aCommandPath, aReader); break; diff --git a/zzz_generated/lock-app/zap-generated/PluginApplicationCallbacks.h b/zzz_generated/lock-app/zap-generated/PluginApplicationCallbacks.h index 67145acc8f0389..06a4d946cef149 100644 --- a/zzz_generated/lock-app/zap-generated/PluginApplicationCallbacks.h +++ b/zzz_generated/lock-app/zap-generated/PluginApplicationCallbacks.h @@ -32,6 +32,8 @@ MatterFixedLabelPluginServerInitCallback(); \ MatterGeneralCommissioningPluginServerInitCallback(); \ MatterGeneralDiagnosticsPluginServerInitCallback(); \ + MatterGroupsPluginServerInitCallback(); \ + MatterIdentifyPluginServerInitCallback(); \ MatterLocalizationConfigurationPluginServerInitCallback(); \ MatterNetworkCommissioningPluginServerInitCallback(); \ MatterOtaSoftwareUpdateProviderPluginClientInitCallback(); \ diff --git a/zzz_generated/lock-app/zap-generated/access.h b/zzz_generated/lock-app/zap-generated/access.h index 011901d517f30a..15851d1a390ef2 100644 --- a/zzz_generated/lock-app/zap-generated/access.h +++ b/zzz_generated/lock-app/zap-generated/access.h @@ -210,6 +210,12 @@ 48, /* Cluster: General Commissioning, Command: ArmFailSafe, Privilege: administer */ \ 48, /* Cluster: General Commissioning, Command: SetRegulatoryConfig, Privilege: administer */ \ 48, /* Cluster: General Commissioning, Command: CommissioningComplete, Privilege: administer */ \ + 4, /* Cluster: Groups, Command: AddGroup, Privilege: manage */ \ + 4, /* Cluster: Groups, Command: RemoveGroup, Privilege: manage */ \ + 4, /* Cluster: Groups, Command: RemoveAllGroups, Privilege: manage */ \ + 4, /* Cluster: Groups, Command: AddGroupIfIdentifying, Privilege: manage */ \ + 3, /* Cluster: Identify, Command: Identify, Privilege: manage */ \ + 3, /* Cluster: Identify, Command: IdentifyQuery, Privilege: manage */ \ 49, /* Cluster: Network Commissioning, Command: ScanNetworks, Privilege: administer */ \ 49, /* Cluster: Network Commissioning, Command: AddOrUpdateWiFiNetwork, Privilege: administer */ \ 49, /* Cluster: Network Commissioning, Command: AddOrUpdateThreadNetwork, Privilege: administer */ \ @@ -247,6 +253,12 @@ 0, /* Cluster: General Commissioning, Command: ArmFailSafe, Privilege: administer */ \ 2, /* Cluster: General Commissioning, Command: SetRegulatoryConfig, Privilege: administer */ \ 4, /* Cluster: General Commissioning, Command: CommissioningComplete, Privilege: administer */ \ + 0, /* Cluster: Groups, Command: AddGroup, Privilege: manage */ \ + 3, /* Cluster: Groups, Command: RemoveGroup, Privilege: manage */ \ + 4, /* Cluster: Groups, Command: RemoveAllGroups, Privilege: manage */ \ + 5, /* Cluster: Groups, Command: AddGroupIfIdentifying, Privilege: manage */ \ + 0, /* Cluster: Identify, Command: Identify, Privilege: manage */ \ + 1, /* Cluster: Identify, Command: IdentifyQuery, Privilege: manage */ \ 0, /* Cluster: Network Commissioning, Command: ScanNetworks, Privilege: administer */ \ 2, /* Cluster: Network Commissioning, Command: AddOrUpdateWiFiNetwork, Privilege: administer */ \ 3, /* Cluster: Network Commissioning, Command: AddOrUpdateThreadNetwork, Privilege: administer */ \ @@ -284,6 +296,12 @@ kMatterAccessPrivilegeAdminister, /* Cluster: General Commissioning, Command: ArmFailSafe, Privilege: administer */ \ kMatterAccessPrivilegeAdminister, /* Cluster: General Commissioning, Command: SetRegulatoryConfig, Privilege: administer */ \ kMatterAccessPrivilegeAdminister, /* Cluster: General Commissioning, Command: CommissioningComplete, Privilege: administer */ \ + kMatterAccessPrivilegeManage, /* Cluster: Groups, Command: AddGroup, Privilege: manage */ \ + kMatterAccessPrivilegeManage, /* Cluster: Groups, Command: RemoveGroup, Privilege: manage */ \ + kMatterAccessPrivilegeManage, /* Cluster: Groups, Command: RemoveAllGroups, Privilege: manage */ \ + kMatterAccessPrivilegeManage, /* Cluster: Groups, Command: AddGroupIfIdentifying, Privilege: manage */ \ + kMatterAccessPrivilegeManage, /* Cluster: Identify, Command: Identify, Privilege: manage */ \ + kMatterAccessPrivilegeManage, /* Cluster: Identify, Command: IdentifyQuery, Privilege: manage */ \ kMatterAccessPrivilegeAdminister, /* Cluster: Network Commissioning, Command: ScanNetworks, Privilege: administer */ \ kMatterAccessPrivilegeAdminister, /* Cluster: Network Commissioning, Command: AddOrUpdateWiFiNetwork, Privilege: administer */ \ kMatterAccessPrivilegeAdminister, /* Cluster: Network Commissioning, Command: AddOrUpdateThreadNetwork, Privilege: administer */ \ diff --git a/zzz_generated/lock-app/zap-generated/callback-stub.cpp b/zzz_generated/lock-app/zap-generated/callback-stub.cpp index 6c3b8338df0036..15b215628ecb48 100644 --- a/zzz_generated/lock-app/zap-generated/callback-stub.cpp +++ b/zzz_generated/lock-app/zap-generated/callback-stub.cpp @@ -59,6 +59,12 @@ void emberAfClusterInitCallback(EndpointId endpoint, ClusterId clusterId) case ZCL_GENERAL_DIAGNOSTICS_CLUSTER_ID: emberAfGeneralDiagnosticsClusterInitCallback(endpoint); break; + case ZCL_GROUPS_CLUSTER_ID: + emberAfGroupsClusterInitCallback(endpoint); + break; + case ZCL_IDENTIFY_CLUSTER_ID: + emberAfIdentifyClusterInitCallback(endpoint); + break; case ZCL_LOCALIZATION_CONFIGURATION_CLUSTER_ID: emberAfLocalizationConfigurationClusterInitCallback(endpoint); break; @@ -154,6 +160,16 @@ void __attribute__((weak)) emberAfGeneralDiagnosticsClusterInitCallback(Endpoint // To prevent warning (void) endpoint; } +void __attribute__((weak)) emberAfGroupsClusterInitCallback(EndpointId endpoint) +{ + // To prevent warning + (void) endpoint; +} +void __attribute__((weak)) emberAfIdentifyClusterInitCallback(EndpointId endpoint) +{ + // To prevent warning + (void) endpoint; +} void __attribute__((weak)) emberAfLocalizationConfigurationClusterInitCallback(EndpointId endpoint) { // To prevent warning diff --git a/zzz_generated/lock-app/zap-generated/endpoint_config.h b/zzz_generated/lock-app/zap-generated/endpoint_config.h index 9e8c29b5115e8b..2f937716d3c907 100644 --- a/zzz_generated/lock-app/zap-generated/endpoint_config.h +++ b/zzz_generated/lock-app/zap-generated/endpoint_config.h @@ -565,7 +565,7 @@ #define ZAP_ATTRIBUTE_MASK(mask) ATTRIBUTE_MASK_##mask // This is an array of EmberAfAttributeMetadata structures. -#define GENERATED_ATTRIBUTE_COUNT 237 +#define GENERATED_ATTRIBUTE_COUNT 241 #define GENERATED_ATTRIBUTES \ { \ \ @@ -843,6 +843,14 @@ ZAP_EMPTY_DEFAULT() }, /* label list */ \ { 0x0000FFFD, ZAP_TYPE(INT16U), 2, 0, ZAP_SIMPLE_DEFAULT(1) }, /* ClusterRevision */ \ \ + /* Endpoint: 1, Cluster: Identify (server) */ \ + { 0x00000000, ZAP_TYPE(INT16U), 2, ZAP_ATTRIBUTE_MASK(WRITABLE), ZAP_SIMPLE_DEFAULT(0x0000) }, /* identify time */ \ + { 0x0000FFFD, ZAP_TYPE(INT16U), 2, 0, ZAP_SIMPLE_DEFAULT(4) }, /* ClusterRevision */ \ + \ + /* Endpoint: 1, Cluster: Groups (server) */ \ + { 0x00000000, ZAP_TYPE(BITMAP8), 1, 0, ZAP_EMPTY_DEFAULT() }, /* name support */ \ + { 0x0000FFFD, ZAP_TYPE(INT16U), 2, 0, ZAP_SIMPLE_DEFAULT(4) }, /* ClusterRevision */ \ + \ /* Endpoint: 1, Cluster: On/Off (server) */ \ { 0x00000000, ZAP_TYPE(BOOLEAN), 1, 0, ZAP_SIMPLE_DEFAULT(0x00) }, /* OnOff */ \ { 0x00004000, ZAP_TYPE(BOOLEAN), 1, 0, ZAP_SIMPLE_DEFAULT(1) }, /* GlobalSceneControl */ \ @@ -873,10 +881,11 @@ { 0x0000FFFD, ZAP_TYPE(INT16U), 2, 0, ZAP_SIMPLE_DEFAULT(1) }, /* ClusterRevision */ \ \ /* Endpoint: 1, Cluster: Door Lock (server) */ \ - { 0x00000000, ZAP_TYPE(ENUM8), 1, ZAP_ATTRIBUTE_MASK(NULLABLE), ZAP_SIMPLE_DEFAULT(2) }, /* LockState */ \ - { 0x00000001, ZAP_TYPE(ENUM8), 1, 0, ZAP_EMPTY_DEFAULT() }, /* LockType */ \ - { 0x00000002, ZAP_TYPE(BOOLEAN), 1, 0, ZAP_EMPTY_DEFAULT() }, /* ActuatorEnabled */ \ - { 0x00000003, ZAP_TYPE(ENUM8), 1, ZAP_ATTRIBUTE_MASK(NULLABLE), ZAP_EMPTY_DEFAULT() }, /* DoorState */ \ + { 0x00000000, ZAP_TYPE(ENUM8), 1, ZAP_ATTRIBUTE_MASK(TOKENIZE) | ZAP_ATTRIBUTE_MASK(NULLABLE), \ + ZAP_SIMPLE_DEFAULT(1) }, /* LockState */ \ + { 0x00000001, ZAP_TYPE(ENUM8), 1, 0, ZAP_EMPTY_DEFAULT() }, /* LockType */ \ + { 0x00000002, ZAP_TYPE(BOOLEAN), 1, 0, ZAP_EMPTY_DEFAULT() }, /* ActuatorEnabled */ \ + { 0x00000003, ZAP_TYPE(ENUM8), 1, ZAP_ATTRIBUTE_MASK(NULLABLE), ZAP_EMPTY_DEFAULT() }, /* DoorState */ \ { 0x00000011, ZAP_TYPE(INT16U), 2, 0, ZAP_SIMPLE_DEFAULT(10) }, /* NumberOfTotalUsersSupported */ \ { 0x00000012, ZAP_TYPE(INT16U), 2, 0, ZAP_SIMPLE_DEFAULT(10) }, /* NumberOfPINUsersSupported */ \ { 0x00000013, ZAP_TYPE(INT16U), 2, 0, ZAP_SIMPLE_DEFAULT(10) }, /* NumberOfRFIDUsersSupported */ \ @@ -926,6 +935,13 @@ (EmberAfGenericClusterFunction) emberAfTimeFormatLocalizationClusterServerInitCallback, \ (EmberAfGenericClusterFunction) MatterTimeFormatLocalizationClusterServerPreAttributeChangedCallback, \ }; \ + const EmberAfGenericClusterFunction chipFuncArrayIdentifyServer[] = { \ + (EmberAfGenericClusterFunction) emberAfIdentifyClusterServerInitCallback, \ + (EmberAfGenericClusterFunction) MatterIdentifyClusterServerAttributeChangedCallback, \ + }; \ + const EmberAfGenericClusterFunction chipFuncArrayGroupsServer[] = { \ + (EmberAfGenericClusterFunction) emberAfGroupsClusterServerInitCallback, \ + }; \ const EmberAfGenericClusterFunction chipFuncArrayOnOffServer[] = { \ (EmberAfGenericClusterFunction) emberAfOnOffClusterServerInitCallback, \ }; \ @@ -1007,6 +1023,29 @@ 0x00000005 /* CSRResponse */, \ 0x00000008 /* NOCResponse */, \ chip::kInvalidCommandId /* end of list */, \ + /* Endpoint: 1, Cluster: Identify (server) */\ + /* client_generated */ \ + 0x00000000 /* Identify */, \ + 0x00000001 /* IdentifyQuery */, \ + chip::kInvalidCommandId /* end of list */, \ + /* server_generated */ \ + 0x00000000 /* IdentifyQueryResponse */, \ + chip::kInvalidCommandId /* end of list */, \ + /* Endpoint: 1, Cluster: Groups (server) */\ + /* client_generated */ \ + 0x00000000 /* AddGroup */, \ + 0x00000001 /* ViewGroup */, \ + 0x00000002 /* GetGroupMembership */, \ + 0x00000003 /* RemoveGroup */, \ + 0x00000004 /* RemoveAllGroups */, \ + 0x00000005 /* AddGroupIfIdentifying */, \ + chip::kInvalidCommandId /* end of list */, \ + /* server_generated */ \ + 0x00000000 /* AddGroupResponse */, \ + 0x00000001 /* ViewGroupResponse */, \ + 0x00000002 /* GetGroupMembershipResponse */, \ + 0x00000003 /* RemoveGroupResponse */, \ + chip::kInvalidCommandId /* end of list */, \ /* Endpoint: 1, Cluster: On/Off (server) */\ /* client_generated */ \ 0x00000000 /* Off */, \ @@ -1036,7 +1075,7 @@ // clang-format on #define ZAP_CLUSTER_MASK(mask) CLUSTER_MASK_##mask -#define GENERATED_CLUSTER_COUNT 25 +#define GENERATED_CLUSTER_COUNT 27 // clang-format off #define GENERATED_CLUSTERS { \ @@ -1271,21 +1310,43 @@ .acceptedCommandList = nullptr ,\ .generatedCommandList = nullptr ,\ },\ + { \ + /* Endpoint: 1, Cluster: Identify (server) */ \ + .clusterId = 0x00000003, \ + .attributes = ZAP_ATTRIBUTE_INDEX(190), \ + .attributeCount = 2, \ + .clusterSize = 4, \ + .mask = ZAP_CLUSTER_MASK(SERVER) | ZAP_CLUSTER_MASK(INIT_FUNCTION) | ZAP_CLUSTER_MASK(ATTRIBUTE_CHANGED_FUNCTION), \ + .functions = chipFuncArrayIdentifyServer, \ + .acceptedCommandList = ZAP_GENERATED_COMMANDS_INDEX( 48 ) ,\ + .generatedCommandList = ZAP_GENERATED_COMMANDS_INDEX( 51 ) ,\ + },\ + { \ + /* Endpoint: 1, Cluster: Groups (server) */ \ + .clusterId = 0x00000004, \ + .attributes = ZAP_ATTRIBUTE_INDEX(192), \ + .attributeCount = 2, \ + .clusterSize = 3, \ + .mask = ZAP_CLUSTER_MASK(SERVER) | ZAP_CLUSTER_MASK(INIT_FUNCTION), \ + .functions = chipFuncArrayGroupsServer, \ + .acceptedCommandList = ZAP_GENERATED_COMMANDS_INDEX( 53 ) ,\ + .generatedCommandList = ZAP_GENERATED_COMMANDS_INDEX( 60 ) ,\ + },\ { \ /* Endpoint: 1, Cluster: On/Off (server) */ \ .clusterId = 0x00000006, \ - .attributes = ZAP_ATTRIBUTE_INDEX(190), \ + .attributes = ZAP_ATTRIBUTE_INDEX(194), \ .attributeCount = 7, \ .clusterSize = 13, \ .mask = ZAP_CLUSTER_MASK(SERVER) | ZAP_CLUSTER_MASK(INIT_FUNCTION), \ .functions = chipFuncArrayOnOffServer, \ - .acceptedCommandList = ZAP_GENERATED_COMMANDS_INDEX( 48 ) ,\ + .acceptedCommandList = ZAP_GENERATED_COMMANDS_INDEX( 65 ) ,\ .generatedCommandList = nullptr ,\ },\ { \ /* Endpoint: 1, Cluster: Descriptor (server) */ \ .clusterId = 0x0000001D, \ - .attributes = ZAP_ATTRIBUTE_INDEX(197), \ + .attributes = ZAP_ATTRIBUTE_INDEX(201), \ .attributeCount = 5, \ .clusterSize = 0, \ .mask = ZAP_CLUSTER_MASK(SERVER), \ @@ -1296,7 +1357,7 @@ { \ /* Endpoint: 1, Cluster: Power Source (server) */ \ .clusterId = 0x0000002F, \ - .attributes = ZAP_ATTRIBUTE_INDEX(202), \ + .attributes = ZAP_ATTRIBUTE_INDEX(206), \ .attributeCount = 9, \ .clusterSize = 133, \ .mask = ZAP_CLUSTER_MASK(SERVER), \ @@ -1307,12 +1368,12 @@ { \ /* Endpoint: 1, Cluster: Door Lock (server) */ \ .clusterId = 0x00000101, \ - .attributes = ZAP_ATTRIBUTE_INDEX(211), \ + .attributes = ZAP_ATTRIBUTE_INDEX(215), \ .attributeCount = 26, \ .clusterSize = 40, \ .mask = ZAP_CLUSTER_MASK(SERVER) | ZAP_CLUSTER_MASK(ATTRIBUTE_CHANGED_FUNCTION) | ZAP_CLUSTER_MASK(PRE_ATTRIBUTE_CHANGED_FUNCTION), \ .functions = chipFuncArrayDoorLockServer, \ - .acceptedCommandList = ZAP_GENERATED_COMMANDS_INDEX( 52 ) ,\ + .acceptedCommandList = ZAP_GENERATED_COMMANDS_INDEX( 69 ) ,\ .generatedCommandList = nullptr ,\ },\ } @@ -1321,12 +1382,12 @@ #define ZAP_CLUSTER_INDEX(index) (&generatedClusters[index]) -#define ZAP_FIXED_ENDPOINT_DATA_VERSION_COUNT 24 +#define ZAP_FIXED_ENDPOINT_DATA_VERSION_COUNT 26 // This is an array of EmberAfEndpointType structures. #define GENERATED_ENDPOINT_TYPES \ { \ - { ZAP_CLUSTER_INDEX(0), 21, 593 }, { ZAP_CLUSTER_INDEX(21), 4, 186 }, \ + { ZAP_CLUSTER_INDEX(0), 21, 593 }, { ZAP_CLUSTER_INDEX(21), 6, 193 }, \ } // Largest attribute size is needed for various buffers @@ -1338,7 +1399,7 @@ static_assert(ATTRIBUTE_LARGEST <= CHIP_CONFIG_MAX_ATTRIBUTE_STORE_ELEMENT_SIZE, #define ATTRIBUTE_SINGLETONS_SIZE (37) // Total size of attribute storage -#define ATTRIBUTE_MAX_SIZE (779) +#define ATTRIBUTE_MAX_SIZE (786) // Number of fixed endpoints #define FIXED_ENDPOINT_COUNT (2) diff --git a/zzz_generated/lock-app/zap-generated/gen_config.h b/zzz_generated/lock-app/zap-generated/gen_config.h index cfb19fdb9885f4..38cfa7f1165da7 100644 --- a/zzz_generated/lock-app/zap-generated/gen_config.h +++ b/zzz_generated/lock-app/zap-generated/gen_config.h @@ -39,6 +39,8 @@ #define EMBER_AF_FIXED_LABEL_CLUSTER_SERVER_ENDPOINT_COUNT (1) #define EMBER_AF_GENERAL_COMMISSIONING_CLUSTER_SERVER_ENDPOINT_COUNT (1) #define EMBER_AF_GENERAL_DIAGNOSTICS_CLUSTER_SERVER_ENDPOINT_COUNT (1) +#define EMBER_AF_GROUPS_CLUSTER_SERVER_ENDPOINT_COUNT (1) +#define EMBER_AF_IDENTIFY_CLUSTER_SERVER_ENDPOINT_COUNT (1) #define EMBER_AF_LOCALIZATION_CONFIGURATION_CLUSTER_SERVER_ENDPOINT_COUNT (1) #define EMBER_AF_NETWORK_COMMISSIONING_CLUSTER_SERVER_ENDPOINT_COUNT (1) #define EMBER_AF_OTA_PROVIDER_CLUSTER_CLIENT_ENDPOINT_COUNT (1) @@ -105,6 +107,16 @@ #define EMBER_AF_PLUGIN_GENERAL_DIAGNOSTICS_SERVER #define EMBER_AF_PLUGIN_GENERAL_DIAGNOSTICS +// Use this macro to check if the server side of the Groups cluster is included +#define ZCL_USING_GROUPS_CLUSTER_SERVER +#define EMBER_AF_PLUGIN_GROUPS_SERVER +#define EMBER_AF_PLUGIN_GROUPS + +// Use this macro to check if the server side of the Identify cluster is included +#define ZCL_USING_IDENTIFY_CLUSTER_SERVER +#define EMBER_AF_PLUGIN_IDENTIFY_SERVER +#define EMBER_AF_PLUGIN_IDENTIFY + // Use this macro to check if the server side of the Localization Configuration cluster is included #define ZCL_USING_LOCALIZATION_CONFIGURATION_CLUSTER_SERVER #define EMBER_AF_PLUGIN_LOCALIZATION_CONFIGURATION_SERVER