Skip to content

Commit

Permalink
Merge branch 'master' into remove_controller_clusters_zap
Browse files Browse the repository at this point in the history
  • Loading branch information
andreilitvin committed May 30, 2023
2 parents 4e188d3 + acbc6dd commit 049fbb9
Show file tree
Hide file tree
Showing 18 changed files with 480 additions and 160 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -528,5 +528,5 @@ jobs:
.environment/pigweed-venv/*.log
- name: Run Build Coverage
timeout-minutes: 20
timeout-minutes: 30
run: ./scripts/build_coverage.sh
2 changes: 1 addition & 1 deletion .github/workflows/examples-qpg.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ jobs:
.environment/pigweed-venv/*.log
- name: Build QPG6105 example apps
timeout-minutes: 20
timeout-minutes: 30
run: |
./scripts/run_in_build_env.sh \
"./scripts/build/build_examples.py \
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2857,6 +2857,10 @@ server cluster DoorLock = 257 {
nullable CredentialStruct credential = 0;
}

request struct UnboltDoorRequest {
optional OCTET_STRING PINCode = 0;
}

response struct GetUserResponse = 28 {
INT16U userIndex = 0;
nullable CHAR_STRING userName = 1;
Expand Down Expand Up @@ -2898,6 +2902,7 @@ server cluster DoorLock = 257 {
timed command access(invoke: administer) SetCredential(SetCredentialRequest): SetCredentialResponse = 34;
command access(invoke: administer) GetCredentialStatus(GetCredentialStatusRequest): GetCredentialStatusResponse = 36;
timed command access(invoke: administer) ClearCredential(ClearCredentialRequest): DefaultSuccess = 38;
timed command UnboltDoor(UnboltDoorRequest): DefaultSuccess = 39;
}

/** Provides an interface for controlling and adjusting automatic window coverings. */
Expand Down Expand Up @@ -5246,7 +5251,7 @@ endpoint 1 {
ram attribute wrongCodeEntryLimit default = 3;
ram attribute userCodeTemporaryDisableTime default = 10;
ram attribute requirePINforRemoteOperation default = 0;
ram attribute featureMap default = 0xD13;
ram attribute featureMap default = 0x1D13;
ram attribute clusterRevision default = 6;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13359,6 +13359,14 @@
"source": "client",
"incoming": 1,
"outgoing": 0
},
{
"name": "UnboltDoor",
"code": 39,
"mfgCode": null,
"source": "client",
"incoming": 1,
"outgoing": 0
}
],
"attributes": [
Expand Down Expand Up @@ -14048,7 +14056,7 @@
"storageOption": "RAM",
"singleton": 0,
"bounded": 0,
"defaultValue": "0xD13",
"defaultValue": "0x1D13",
"reportable": 1,
"minInterval": 1,
"maxInterval": 65534,
Expand Down
2 changes: 2 additions & 0 deletions examples/lock-app/cc13x2x7_26x2x7/src/LockManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -638,6 +638,8 @@ const char * LockManager::lockStateToString(DlLockState lockState) const
return "Locked";
case DlLockState::kUnlocked:
return "Unlocked";
case DlLockState::kUnlatched:
return "Unlatched";
case DlLockState::kUnknownEnumValue:
break;
default:
Expand Down
1 change: 1 addition & 0 deletions examples/lock-app/lock-common/include/LockEndpoint.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ class LockEndpoint

bool Lock(const Optional<chip::ByteSpan> & pin, OperationErrorEnum & err, OperationSourceEnum opSource);
bool Unlock(const Optional<chip::ByteSpan> & pin, OperationErrorEnum & err, OperationSourceEnum opSource);
bool Unbolt(const Optional<chip::ByteSpan> & pin, OperationErrorEnum & err, OperationSourceEnum opSource);

bool GetUser(uint16_t userIndex, EmberAfPluginDoorLockUserInfo & user) const;
bool SetUser(uint16_t userIndex, chip::FabricIndex creator, chip::FabricIndex modifier, const chip::CharSpan & userName,
Expand Down
2 changes: 2 additions & 0 deletions examples/lock-app/lock-common/include/LockManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ class LockManager
OperationSourceEnum opSource);
bool Unlock(chip::EndpointId endpointId, const Optional<chip::ByteSpan> & pin, OperationErrorEnum & err,
OperationSourceEnum opSource);
bool Unbolt(chip::EndpointId endpointId, const Optional<chip::ByteSpan> & pin, OperationErrorEnum & err,
OperationSourceEnum opSource);

bool GetUser(chip::EndpointId endpointId, uint16_t userIndex, EmberAfPluginDoorLockUserInfo & user);
bool SetUser(chip::EndpointId endpointId, uint16_t userIndex, chip::FabricIndex creator, chip::FabricIndex modifier,
Expand Down
7 changes: 6 additions & 1 deletion examples/lock-app/lock-common/lock-app.matter
Original file line number Diff line number Diff line change
Expand Up @@ -2154,6 +2154,10 @@ server cluster DoorLock = 257 {
nullable CredentialStruct credential = 0;
}

request struct UnboltDoorRequest {
optional OCTET_STRING PINCode = 0;
}

response struct GetWeekDayScheduleResponse = 12 {
INT8U weekDayIndex = 0;
INT16U userIndex = 1;
Expand Down Expand Up @@ -2226,6 +2230,7 @@ server cluster DoorLock = 257 {
timed command access(invoke: administer) SetCredential(SetCredentialRequest): SetCredentialResponse = 34;
command access(invoke: administer) GetCredentialStatus(GetCredentialStatusRequest): GetCredentialStatusResponse = 36;
timed command access(invoke: administer) ClearCredential(ClearCredentialRequest): DefaultSuccess = 38;
timed command UnboltDoor(UnboltDoorRequest): DefaultSuccess = 39;
}

endpoint 0 {
Expand Down Expand Up @@ -2595,7 +2600,7 @@ endpoint 1 {
ram attribute wrongCodeEntryLimit default = 3;
ram attribute userCodeTemporaryDisableTime default = 10;
ram attribute requirePINforRemoteOperation default = 0;
ram attribute featureMap default = 0xDB3;
ram attribute featureMap default = 0x1DB3;
ram attribute clusterRevision default = 6;
}
}
Expand Down
10 changes: 9 additions & 1 deletion examples/lock-app/lock-common/lock-app.zap
Original file line number Diff line number Diff line change
Expand Up @@ -7023,6 +7023,14 @@
"source": "client",
"incoming": 1,
"outgoing": 0
},
{
"name": "UnboltDoor",
"code": 39,
"mfgCode": null,
"source": "client",
"incoming": 1,
"outgoing": 0
}
],
"attributes": [
Expand Down Expand Up @@ -7736,7 +7744,7 @@
"storageOption": "RAM",
"singleton": 0,
"bounded": 0,
"defaultValue": "0xDB3",
"defaultValue": "0x1DB3",
"reportable": 1,
"minInterval": 1,
"maxInterval": 65534,
Expand Down
11 changes: 11 additions & 0 deletions examples/lock-app/lock-common/src/LockEndpoint.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,17 @@ bool LockEndpoint::Lock(const Optional<chip::ByteSpan> & pin, OperationErrorEnum
}

bool LockEndpoint::Unlock(const Optional<chip::ByteSpan> & pin, OperationErrorEnum & err, OperationSourceEnum opSource)
{
if (DoorLockServer::Instance().SupportsUnbolt(mEndpointId))
{
// If Unbolt is supported Unlock is supposed to pull the latch
setLockState(DlLockState::kUnlatched, pin, err, opSource);
}

return setLockState(DlLockState::kUnlocked, pin, err, opSource);
}

bool LockEndpoint::Unbolt(const Optional<chip::ByteSpan> & pin, OperationErrorEnum & err, OperationSourceEnum opSource)
{
return setLockState(DlLockState::kUnlocked, pin, err, opSource);
}
Expand Down
12 changes: 12 additions & 0 deletions examples/lock-app/lock-common/src/LockManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,18 @@ bool LockManager::Unlock(chip::EndpointId endpointId, const Optional<chip::ByteS
return lockEndpoint->Unlock(pin, err, opSource);
}

bool LockManager::Unbolt(chip::EndpointId endpointId, const Optional<chip::ByteSpan> & pin, OperationErrorEnum & err,
OperationSourceEnum opSource)
{
auto lockEndpoint = getEndpoint(endpointId);
if (nullptr == lockEndpoint)
{
ChipLogError(Zcl, "Unable to unbolt the door - endpoint does not exist or not initialized [endpointId=%d]", endpointId);
return false;
}
return lockEndpoint->Unbolt(pin, err, opSource);
}

bool LockManager::GetUser(chip::EndpointId endpointId, uint16_t userIndex, EmberAfPluginDoorLockUserInfo & user)
{
auto lockEndpoint = getEndpoint(endpointId);
Expand Down
6 changes: 6 additions & 0 deletions examples/lock-app/lock-common/src/ZCLDoorLockCallbacks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,12 @@ bool emberAfPluginDoorLockOnDoorUnlockCommand(chip::EndpointId endpointId, const
return LockManager::Instance().Unlock(endpointId, pinCode, err, OperationSourceEnum::kRemote);
}

bool emberAfPluginDoorLockOnDoorUnboltCommand(chip::EndpointId endpointId, const Optional<ByteSpan> & pinCode,
OperationErrorEnum & err)
{
return LockManager::Instance().Unbolt(endpointId, pinCode, err, OperationSourceEnum::kRemote);
}

bool emberAfPluginDoorLockGetUser(chip::EndpointId endpointId, uint16_t userIndex, EmberAfPluginDoorLockUserInfo & user)
{
return LockManager::Instance().GetUser(endpointId, userIndex, user);
Expand Down
1 change: 0 additions & 1 deletion examples/lock-app/silabs/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,6 @@ if (wifi_soc) {
if (chip_enable_ble_rs911x) {
# TODO efr32_sdk should not need a header from this location
include_dirs += [
"${src_plat_dir}/rs911x",
"${examples_plat_dir}/rs911x",
"${examples_plat_dir}/rs911x/hal",
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,13 @@ emberAfPluginDoorLockOnDoorUnlockCommand(chip::EndpointId endpointId, const Opti
return false;
}

bool __attribute__((weak))
emberAfPluginDoorLockOnDoorUnboltCommand(chip::EndpointId endpointId, const Optional<ByteSpan> & pinCode, OperationErrorEnum & err)
{
err = OperationErrorEnum::kUnspecified;
return false;
}

void __attribute__((weak)) emberAfPluginDoorLockOnAutoRelock(chip::EndpointId endpointId) {}

// =============================================================================
Expand Down
76 changes: 71 additions & 5 deletions src/app/clusters/door-lock-server/door-lock-server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -114,10 +114,21 @@ bool DoorLockServer::SetLockState(chip::EndpointId endpointId, DlLockState newLo
// DlLockState::kNotFullyLocked has no appropriate event to send. Also it is unclear whether
// it should schedule auto-relocking. So skip it here. Check for supported states explicitly
// to handle possible enum extending in future.
VerifyOrReturnError(DlLockState::kLocked == newLockState || DlLockState::kUnlocked == newLockState, success);
VerifyOrReturnError(DlLockState::kLocked == newLockState || DlLockState::kUnlocked == newLockState ||
DlLockState::kUnlatched == newLockState,
success);

// Send LockOperation event
auto opType = (DlLockState::kLocked == newLockState) ? LockOperationTypeEnum::kLock : LockOperationTypeEnum::kUnlock;
auto opType = LockOperationTypeEnum::kUnlock;

if (DlLockState::kLocked == newLockState)
{
opType = LockOperationTypeEnum::kLock;
}
else if (DlLockState::kUnlatched == newLockState)
{
opType = LockOperationTypeEnum::kUnlatch;
}

SendLockOperationEvent(endpointId, opType, opSource, OperationErrorEnum::kUnspecified, userIndex, Nullable<chip::FabricIndex>(),
Nullable<chip::NodeId>(), credentials, success);
Expand Down Expand Up @@ -3296,7 +3307,8 @@ bool DoorLockServer::HandleRemoteLockOperation(chip::app::CommandHandler * comma
const chip::app::ConcreteCommandPath & commandPath, LockOperationTypeEnum opType,
RemoteLockOpHandler opHandler, const Optional<ByteSpan> & pinCode)
{
VerifyOrDie(LockOperationTypeEnum::kLock == opType || LockOperationTypeEnum::kUnlock == opType);
VerifyOrDie(LockOperationTypeEnum::kLock == opType || LockOperationTypeEnum::kUnlock == opType ||
LockOperationTypeEnum::kUnlatch == opType);
VerifyOrDie(nullptr != opHandler);

EndpointId endpoint = commandPath.mEndpointId;
Expand Down Expand Up @@ -3421,9 +3433,27 @@ bool DoorLockServer::HandleRemoteLockOperation(chip::app::CommandHandler * comma
credentials.SetNonNull(foundCred);
}

// Failed Unlatch requests SHALL generate only a LockOperationError event with LockOperationType set to Unlock
if (LockOperationTypeEnum::kUnlatch == opType && !success)
{
opType = LockOperationTypeEnum::kUnlock;
}

SendLockOperationEvent(endpoint, opType, OperationSourceEnum::kRemote, reason, pinUserIdx,
Nullable<chip::FabricIndex>(getFabricIndex(commandObj)), Nullable<chip::NodeId>(getNodeId(commandObj)),
credentials, success);

// SHALL generate a LockOperation event with LockOperationType set to Unlatch when the unlatched state is reached and a
// LockOperation event with LockOperationType set to Unlock when the lock successfully completes the unlock. But as the current
// implementation here is sending LockOperation events immediately we're sending both events immediately.
// https://github.com/project-chip/connectedhomeip/issues/26925
if (LockOperationTypeEnum::kUnlatch == opType && success)
{
SendLockOperationEvent(endpoint, LockOperationTypeEnum::kUnlock, OperationSourceEnum::kRemote, reason, pinUserIdx,
Nullable<chip::FabricIndex>(getFabricIndex(commandObj)),
Nullable<chip::NodeId>(getNodeId(commandObj)), credentials, success);
}

return success;
}

Expand Down Expand Up @@ -3525,7 +3555,14 @@ bool emberAfDoorLockClusterUnlockDoorCallback(
{
emberAfDoorLockClusterPrintln("Received command: UnlockDoor");

if (DoorLockServer::Instance().HandleRemoteLockOperation(commandObj, commandPath, LockOperationTypeEnum::kUnlock,
LockOperationTypeEnum lockOp = LockOperationTypeEnum::kUnlock;

if (DoorLockServer::Instance().SupportsUnbolt(commandPath.mEndpointId))
{
lockOp = LockOperationTypeEnum::kUnlatch;
}

if (DoorLockServer::Instance().HandleRemoteLockOperation(commandObj, commandPath, lockOp,
emberAfPluginDoorLockOnDoorUnlockCommand, commandData.PINCode))
{
// appclusters.pdf 5.3.3.25:
Expand All @@ -3547,7 +3584,14 @@ bool emberAfDoorLockClusterUnlockWithTimeoutCallback(
{
emberAfDoorLockClusterPrintln("Received command: UnlockWithTimeout");

if (DoorLockServer::Instance().HandleRemoteLockOperation(commandObj, commandPath, LockOperationTypeEnum::kUnlock,
LockOperationTypeEnum lockOp = LockOperationTypeEnum::kUnlock;

if (DoorLockServer::Instance().SupportsUnbolt(commandPath.mEndpointId))
{
lockOp = LockOperationTypeEnum::kUnlatch;
}

if (DoorLockServer::Instance().HandleRemoteLockOperation(commandObj, commandPath, lockOp,
emberAfPluginDoorLockOnDoorUnlockCommand, commandData.PINCode))
{
// appclusters.pdf 5.3.4.3:
Expand All @@ -3563,6 +3607,28 @@ bool emberAfDoorLockClusterUnlockWithTimeoutCallback(
return true;
}

bool emberAfDoorLockClusterUnboltDoorCallback(
chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath,
const chip::app::Clusters::DoorLock::Commands::UnboltDoor::DecodableType & commandData)
{
emberAfDoorLockClusterPrintln("Received command: UnboltDoor");

if (DoorLockServer::Instance().HandleRemoteLockOperation(commandObj, commandPath, LockOperationTypeEnum::kUnlock,
emberAfPluginDoorLockOnDoorUnboltCommand, commandData.PINCode))
{
// appclusters.pdf 5.3.3.25:
// The number of seconds to wait after unlocking a lock before it automatically locks again. 0=disabled. If set, unlock
// operations from any source will be timed. For one time unlock with timeout use the specific command.
uint32_t autoRelockTime = 0;

VerifyOrReturnError(DoorLockServer::Instance().GetAutoRelockTime(commandPath.mEndpointId, autoRelockTime), true);
VerifyOrReturnError(0 != autoRelockTime, true);
DoorLockServer::Instance().ScheduleAutoRelock(commandPath.mEndpointId, autoRelockTime);
}

return true;
}

bool emberAfDoorLockClusterSetUserCallback(chip::app::CommandHandler * commandObj,
const chip::app::ConcreteCommandPath & commandPath,
const chip::app::Clusters::DoorLock::Commands::SetUser::DecodableType & commandData)
Expand Down
19 changes: 19 additions & 0 deletions src/app/clusters/door-lock-server/door-lock-server.h
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,8 @@ class DoorLockServer
return GetFeatures(endpointId).Has(Feature::kUser) && SupportsAnyCredential(endpointId);
}

inline bool SupportsUnbolt(chip::EndpointId endpointId) { return GetFeatures(endpointId).Has(Feature::kUnbolt); }

bool OnFabricRemoved(chip::EndpointId endpointId, chip::FabricIndex fabricIndex);

static void DoorLockOnAutoRelockCallback(chip::System::Layer *, void * callbackContext);
Expand Down Expand Up @@ -490,6 +492,10 @@ class DoorLockServer
chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath,
const chip::app::Clusters::DoorLock::Commands::UnlockWithTimeout::DecodableType & commandData);

friend bool emberAfDoorLockClusterUnboltDoorCallback(
chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath,
const chip::app::Clusters::DoorLock::Commands::UnboltDoor::DecodableType & commandData);

friend bool emberAfDoorLockClusterSetHolidayScheduleCallback(
chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath,
const chip::app::Clusters::DoorLock::Commands::SetHolidaySchedule::DecodableType & commandData);
Expand Down Expand Up @@ -910,6 +916,19 @@ bool emberAfPluginDoorLockOnDoorLockCommand(chip::EndpointId endpointId, const O
bool emberAfPluginDoorLockOnDoorUnlockCommand(chip::EndpointId endpointId, const Optional<chip::ByteSpan> & pinCode,
OperationErrorEnum & err);

/**
* @brief User handler for UnboltDoor command (server)
*
* @param endpointId endpoint for which UnboltDoor command is called
* @param pinCode PIN code (optional)
* @param err error code if door unbolting failed (set only if retval==false)
*
* @retval true on success
* @retval false if error happenned (err should be set to appropriate error code)
*/
bool emberAfPluginDoorLockOnDoorUnboltCommand(chip::EndpointId endpointId, const Optional<chip::ByteSpan> & pinCode,
OperationErrorEnum & err);

/**
* @brief This callback is called when the AutoRelock timer is expired.
*
Expand Down
Loading

0 comments on commit 049fbb9

Please sign in to comment.