Skip to content

Commit

Permalink
virtual-device-app: Add DoorLock/PowerSource Manager for DoorLock (#2…
Browse files Browse the repository at this point in the history
…8784)

Signed-off-by: Jaehoon You <[email protected]>
Signed-off-by: Charles Kim <[email protected]>
  • Loading branch information
Jaehoon-You authored Aug 21, 2023
1 parent 48420b4 commit 270d8e2
Show file tree
Hide file tree
Showing 10 changed files with 563 additions and 1 deletion.
6 changes: 6 additions & 0 deletions examples/virtual-device-app/android/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,14 @@ shared_library("jni") {
"java/ColorControlManager.cpp",
"java/ColorControlManager.h",
"java/DeviceApp-JNI.cpp",
"java/DoorLockManager.cpp",
"java/DoorLockManager.h",
"java/JNIDACProvider.cpp",
"java/JNIDACProvider.h",
"java/OnOffManager.cpp",
"java/OnOffManager.h",
"java/PowerSourceManager.cpp",
"java/PowerSourceManager.h",
]

deps = [
Expand Down Expand Up @@ -72,7 +76,9 @@ android_library("java") {
"java/src/com/matter/virtual/device/app/DeviceApp.java",
"java/src/com/matter/virtual/device/app/DeviceAppCallback.java",
"java/src/com/matter/virtual/device/app/DeviceEventType.java",
"java/src/com/matter/virtual/device/app/DoorLockManager.java",
"java/src/com/matter/virtual/device/app/OnOffManager.java",
"java/src/com/matter/virtual/device/app/PowerSourceManager.java",
]

javac_flags = [ "-Xlint:deprecation" ]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
*/

#include "ColorControlManager.h"
#include "DoorLockManager.h"
#include "OnOffManager.h"
#include <app-common/zap-generated/attributes/Accessors.h>
#include <app-common/zap-generated/ids/Attributes.h>
Expand Down Expand Up @@ -89,6 +90,19 @@ static void ColorControlClusterAttributeChangeCallback(const app::ConcreteAttrib
}
}

static void DoorLockClusterAttributeChangeCallback(const app::ConcreteAttributePath & attributePath, uint16_t size, uint8_t * value)
{
if (attributePath.mAttributeId == DoorLock::Attributes::LockState::Id)
{
uint8_t lockState = *value;

ChipLogProgress(Zcl, "Received lock state command endpoint %d value = %d", static_cast<int>(attributePath.mEndpointId),
lockState);

DoorLockManager().PostLockStateChanged(attributePath.mEndpointId, lockState);
}
}

void MatterPostAttributeChangeCallback(const app::ConcreteAttributePath & attributePath, uint8_t type, uint16_t size,
uint8_t * value)
{
Expand All @@ -103,6 +117,9 @@ void MatterPostAttributeChangeCallback(const app::ConcreteAttributePath & attrib
case ColorControl::Id:
ColorControlClusterAttributeChangeCallback(attributePath, size, value);
break;
case DoorLock::Id:
DoorLockClusterAttributeChangeCallback(attributePath, size, value);
break;

default:
break;
Expand Down
66 changes: 66 additions & 0 deletions examples/virtual-device-app/android/java/DeviceApp-JNI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@
#include "JNIDACProvider.h"

#include "ColorControlManager.h"
#include "DoorLockManager.h"
#include "OnOffManager.h"
#include "PowerSourceManager.h"
#include "credentials/DeviceAttestationCredsProvider.h"
#include <app/app-platform/ContentAppPlatform.h>
#include <app/server/Dnssd.h>
Expand Down Expand Up @@ -166,3 +168,67 @@ JNI_METHOD(void, setColorControlManager)(JNIEnv *, jobject, jint endpoint, jobje
{
ColorControlManager::NewManager(endpoint, manager);
}

/*
* Door Lock Manager
*/
JNI_METHOD(void, setDoorLockManager)(JNIEnv *, jobject, jint endpoint, jobject manager)
{
DoorLockManager::NewManager(endpoint, manager);
}

JNI_METHOD(jboolean, setLockType)(JNIEnv *, jobject, jint endpoint, jint value)
{
return DeviceLayer::SystemLayer().ScheduleLambda([endpoint, value] { DoorLockManager::SetLockType(endpoint, value); }) ==
CHIP_NO_ERROR;
}

JNI_METHOD(jboolean, setLockState)(JNIEnv *, jobject, jint endpoint, jint value)
{
return DeviceLayer::SystemLayer().ScheduleLambda([endpoint, value] { DoorLockManager::SetLockState(endpoint, value); }) ==
CHIP_NO_ERROR;
}

JNI_METHOD(jboolean, setActuatorEnabled)(JNIEnv *, jobject, jint endpoint, jboolean value)
{
return DeviceLayer::SystemLayer().ScheduleLambda([endpoint, value] { DoorLockManager::SetActuatorEnabled(endpoint, value); }) ==
CHIP_NO_ERROR;
}

JNI_METHOD(jboolean, setAutoRelockTime)(JNIEnv *, jobject, jint endpoint, jint value)
{
return DeviceLayer::SystemLayer().ScheduleLambda([endpoint, value] { DoorLockManager::SetAutoRelockTime(endpoint, value); }) ==
CHIP_NO_ERROR;
}

JNI_METHOD(jboolean, setOperatingMode)(JNIEnv *, jobject, jint endpoint, jint value)
{
return DeviceLayer::SystemLayer().ScheduleLambda([endpoint, value] { DoorLockManager::SetOperatingMode(endpoint, value); }) ==
CHIP_NO_ERROR;
}

JNI_METHOD(jboolean, setSupportedOperatingModes)(JNIEnv *, jobject, jint endpoint, jint value)
{
return DeviceLayer::SystemLayer().ScheduleLambda(
[endpoint, value] { DoorLockManager::SetSupportedOperatingModes(endpoint, value); }) == CHIP_NO_ERROR;
}

JNI_METHOD(jboolean, sendLockAlarmEvent)(JNIEnv *, jobject, jint endpoint)
{
return DeviceLayer::SystemLayer().ScheduleLambda([endpoint] { DoorLockManager::SendLockAlarmEvent(endpoint); }) ==
CHIP_NO_ERROR;
}

/*
* Power Source Manager
*/
JNI_METHOD(void, setPowerSourceManager)(JNIEnv *, jobject, jint endpoint, jobject manager)
{
PowerSourceManager::NewManager(endpoint, manager);
}

JNI_METHOD(jboolean, setBatPercentRemaining)(JNIEnv *, jobject, jint endpoint, jint value)
{
return DeviceLayer::SystemLayer().ScheduleLambda(
[endpoint, value] { PowerSourceManager::SetBatPercentRemaining(endpoint, value); }) == CHIP_NO_ERROR;
}
195 changes: 195 additions & 0 deletions examples/virtual-device-app/android/java/DoorLockManager.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
/**
*
* Copyright (c) 2023 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.
* 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 "DoorLockManager.h"
#include "DeviceApp-JNI.h"
#include <app-common/zap-generated/attributes/Accessors.h>
#include <app-common/zap-generated/ids/Clusters.h>
#include <app/ConcreteAttributePath.h>
#include <app/clusters/door-lock-server/door-lock-server.h>
#include <app/reporting/reporting.h>
#include <app/util/af.h>
#include <jni.h>
#include <lib/support/CHIPJNIError.h>
#include <lib/support/JniReferences.h>
#include <lib/support/JniTypeWrappers.h>
#include <lib/support/ZclString.h>
#include <platform/PlatformManager.h>
#include <vector>

using namespace chip;
using namespace chip::app::Clusters;
using namespace chip::app::Clusters::DoorLock;
using namespace chip::DeviceLayer;

static constexpr size_t kDoorLockManagerTableSize =
EMBER_AF_DOOR_LOCK_CLUSTER_SERVER_ENDPOINT_COUNT + CHIP_DEVICE_CONFIG_DYNAMIC_ENDPOINT_COUNT;

namespace {

DoorLockManager * gDoorLockManagerTable[kDoorLockManagerTableSize] = { nullptr };

}

void emberAfDoorLockClusterInitCallback(EndpointId endpoint)
{
ChipLogProgress(Zcl, "Device App::DoorLock::PostClusterInit");
DeviceAppJNIMgr().PostClusterInit(chip::app::Clusters::DoorLock::Id, endpoint);
DoorLockServer::Instance().InitServer(endpoint);
EmberAfStatus status = DoorLock::Attributes::FeatureMap::Set(endpoint, 0);
if (status != EMBER_ZCL_STATUS_SUCCESS)
{
ChipLogProgress(Zcl, "Device App::DoorLock::emberAfDoorLockClusterInitCallback()::Updating feature map %x", status);
}
}

bool emberAfPluginDoorLockOnDoorLockCommand(EndpointId endpointId, const Nullable<chip::FabricIndex> & fabricIdx,
const Nullable<chip::NodeId> & nodeId, const Optional<ByteSpan> & pinCode,
OperationErrorEnum & err)
{
ChipLogProgress(Zcl, "Device App::DoorLock::emberAfPluginDoorLockOnDoorLockCommand");
return DoorLockServer::Instance().SetLockState(endpointId, DlLockState::kLocked);
}

bool emberAfPluginDoorLockOnDoorUnlockCommand(EndpointId endpointId, const Nullable<chip::FabricIndex> & fabricIdx,
const Nullable<chip::NodeId> & nodeId, const Optional<ByteSpan> & pinCode,
OperationErrorEnum & err)
{
ChipLogProgress(Zcl, "Device App::DoorLock::emberAfPluginDoorLockOnDoorUnlockCommand");
return DoorLockServer::Instance().SetLockState(endpointId, DlLockState::kUnlocked);
}

void DoorLockManager::NewManager(jint endpoint, jobject manager)
{
ChipLogProgress(Zcl, "Device App: DoorLockManager::NewManager");
uint16_t ep = emberAfGetClusterServerEndpointIndex(static_cast<chip::EndpointId>(endpoint), app::Clusters::DoorLock::Id,
EMBER_AF_DOOR_LOCK_CLUSTER_SERVER_ENDPOINT_COUNT);
VerifyOrReturn(ep < kDoorLockManagerTableSize,
ChipLogError(Zcl, "Device App::DoorLock::NewManager: endpoint %d not found", endpoint));

VerifyOrReturn(gDoorLockManagerTable[ep] == nullptr,
ChipLogError(Zcl, "Device App::DoorLock::NewManager: endpoint %d already has a manager", endpoint));
DoorLockManager * mgr = new DoorLockManager();
CHIP_ERROR err = mgr->InitializeWithObjects(manager);
if (err != CHIP_NO_ERROR)
{
ChipLogError(Zcl, "Device App::DoorLock::NewManager: failed to initialize manager for endpoint %d", endpoint);
delete mgr;
}
else
{
gDoorLockManagerTable[ep] = mgr;
}
}

DoorLockManager * GetDoorLockManager(EndpointId endpoint)
{
uint16_t ep = emberAfGetClusterServerEndpointIndex(endpoint, app::Clusters::DoorLock::Id,
EMBER_AF_DOOR_LOCK_CLUSTER_SERVER_ENDPOINT_COUNT);
return ((ep >= kDoorLockManagerTableSize) ? nullptr : gDoorLockManagerTable[ep]);
}

jboolean DoorLockManager::SetLockType(jint endpoint, jint value)
{
EmberAfStatus status = app::Clusters::DoorLock::Attributes::LockType::Set(
static_cast<chip::EndpointId>(endpoint), static_cast<app::Clusters::DoorLock::DlLockType>(value));
return status == EMBER_ZCL_STATUS_SUCCESS;
}

jboolean DoorLockManager::SetLockState(jint endpoint, jint value)
{
return DoorLockServer::Instance().SetLockState(static_cast<chip::EndpointId>(endpoint),
static_cast<app::Clusters::DoorLock::DlLockState>(value));
}

jboolean DoorLockManager::SetActuatorEnabled(jint endpoint, jboolean value)
{
return DoorLockServer::Instance().SetActuatorEnabled(static_cast<chip::EndpointId>(endpoint), value);
}

jboolean DoorLockManager::SetAutoRelockTime(jint endpoint, jint value)
{
return DoorLockServer::Instance().SetAutoRelockTime(static_cast<chip::EndpointId>(endpoint), static_cast<uint32_t>(value));
}

jboolean DoorLockManager::SetOperatingMode(jint endpoint, jint value)
{
EmberAfStatus status = app::Clusters::DoorLock::Attributes::OperatingMode::Set(
static_cast<chip::EndpointId>(endpoint), static_cast<app::Clusters::DoorLock::OperatingModeEnum>(value));
return status == EMBER_ZCL_STATUS_SUCCESS;
}

jboolean DoorLockManager::SetSupportedOperatingModes(jint endpoint, jint value)
{
EmberAfStatus status = app::Clusters::DoorLock::Attributes::SupportedOperatingModes::Set(
static_cast<chip::EndpointId>(endpoint), static_cast<app::Clusters::DoorLock::DlSupportedOperatingModes>(value));
return status == EMBER_ZCL_STATUS_SUCCESS;
}

jboolean DoorLockManager::SendLockAlarmEvent(jint endpoint)
{
return DoorLockServer::Instance().SendLockAlarmEvent(static_cast<chip::EndpointId>(endpoint), AlarmCodeEnum::kDoorForcedOpen);
}

void DoorLockManager::PostLockStateChanged(chip::EndpointId endpoint, int value)
{
ChipLogProgress(Zcl, "Device App: DoorLockManager::PostLockStateChanged:%d", value);
DoorLockManager * mgr = GetDoorLockManager(endpoint);
VerifyOrReturn(mgr != nullptr, ChipLogError(Zcl, "DoorLockManager null"));

mgr->HandleLockStateChanged(static_cast<int>(endpoint), value);
}

CHIP_ERROR DoorLockManager::InitializeWithObjects(jobject managerObject)
{
JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread();
VerifyOrReturnLogError(env != nullptr, CHIP_ERROR_INCORRECT_STATE);

mDoorLockManagerObject = env->NewGlobalRef(managerObject);
VerifyOrReturnLogError(mDoorLockManagerObject != nullptr, CHIP_ERROR_INVALID_ARGUMENT);

jclass DoorLockManagerClass = env->GetObjectClass(managerObject);
VerifyOrReturnLogError(DoorLockManagerClass != nullptr, CHIP_ERROR_INVALID_ARGUMENT);

mHandleLockStateChangedMethod = env->GetMethodID(DoorLockManagerClass, "handleLockStateChanged", "(I)V");
if (mHandleLockStateChangedMethod == nullptr)
{
ChipLogError(Zcl, "Failed to access DoorLockManager 'handleLockStateChanged' method");
env->ExceptionClear();
return CHIP_ERROR_INVALID_ARGUMENT;
}

return CHIP_NO_ERROR;
}

void DoorLockManager::HandleLockStateChanged(jint endpoint, jint value)
{
ChipLogProgress(Zcl, "DoorLockManager::HandleLockStateChanged:%d", value);

JNIEnv * env = JniReferences::GetInstance().GetEnvForCurrentThread();
VerifyOrReturn(env != NULL, ChipLogProgress(Zcl, "env null"));
VerifyOrReturn(mDoorLockManagerObject != nullptr, ChipLogProgress(Zcl, "mDoorLockManagerObject null"));
VerifyOrReturn(mHandleLockStateChangedMethod != nullptr, ChipLogProgress(Zcl, "mHandleLockStateChangedMethod null"));

env->ExceptionClear();
env->CallVoidMethod(mDoorLockManagerObject, mHandleLockStateChangedMethod, value);
if (env->ExceptionCheck())
{
ChipLogError(AppServer, "Java exception in DoorLockManager::HandleLockStateChanged");
env->ExceptionDescribe();
env->ExceptionClear();
}
}
Loading

0 comments on commit 270d8e2

Please sign in to comment.