Skip to content

Commit

Permalink
Feature/door lock cluster phase 1 (#12989)
Browse files Browse the repository at this point in the history
* Added support for all server-side attributes except those marked as 'nice-to-have'.
1. ZAP generator extended to generate pre attribute change callback for Door Lock cluster.
2. Door Lock cluster defines list of attribute change callbacks to be implemented by user and proxies pre attribute change request to the user app.

* Added pre-change trap for all unhandled cluster attributes

* Update autogenerated files

* Fixed restyled-io notes

* Fixed CR note (invalid usage of language attribute string)

* Fixed CR notes

* Fixed return values for pre-attribute change callbacks to make Darwin tests pass.

* 1. Fixed bug in DoorLockServer methods: wrong type was used for processing attribute setters' retcode.
2. Implemented empty DoorLockServer methods to set appropriate attributes in the same manner.

* Fixed build issue on Infineon: substituted printf type modificators on portable ones from inttypes.h (to prevent printf size mismatch on different platforms)

* Fixed arguments in DoorState and LockState accessors

* Used chip::to_underlying instead of static_cast for Door Lock enum parameters

* Fix CR note: added size sanity checks for all cluster attributes
  • Loading branch information
truebiker authored Dec 28, 2021
1 parent 83b2f46 commit 17520c3
Show file tree
Hide file tree
Showing 5 changed files with 347 additions and 31 deletions.
260 changes: 233 additions & 27 deletions src/app/clusters/door-lock-server/door-lock-server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#include <app/util/af-event.h>
#include <app/util/af.h>
#include <app/util/time-util.h>
#include <inttypes.h>

#include <app/CommandHandler.h>
#include <app/ConcreteAttributePath.h>
Expand Down Expand Up @@ -61,77 +62,123 @@ DoorLockServer & DoorLockServer::Instance()
*/
void DoorLockServer::InitServer(chip::EndpointId endpointId)
{
emberAfDoorLockClusterPrintln("Door Lock cluster initialized at %d", endpointId);
emberAfDoorLockClusterPrintln("Door Lock cluster initialized at endpoint #%" PRIu16, endpointId);
}

bool DoorLockServer::SetLockState(chip::EndpointId endpointId, DlLockState newLockState)
{
auto lockState = static_cast<uint8_t>(newLockState);
auto lockState = chip::to_underlying(newLockState);

emberAfDoorLockClusterPrintln("Setting Lock State to '%hhu'", lockState);
emberAfDoorLockClusterPrintln("Setting LockState to '%" PRIu8 "'", lockState);
EmberAfStatus status = Attributes::LockState::Set(endpointId, newLockState);

bool status = (Attributes::LockState::Set(endpointId, newLockState) == EMBER_ZCL_STATUS_SUCCESS);
if (!status)
if (EMBER_ZCL_STATUS_SUCCESS != status)
{
ChipLogError(Zcl, "Unable to set the Lock State to %hhu: internal error", lockState);
ChipLogError(Zcl, "Unable to set LockState attribute: status=0x%" PRIx8, status);
}

return status;
return (EMBER_ZCL_STATUS_SUCCESS == status);
}

bool DoorLockServer::SetActuatorEnabled(chip::EndpointId endpointId, bool newActuatorState)
{
auto actuatorState = static_cast<uint8_t>(newActuatorState);

emberAfDoorLockClusterPrintln("Setting Actuator State to '%hhu'", actuatorState);
emberAfDoorLockClusterPrintln("Setting ActuatorEnabled to '%" PRIu8 "'", actuatorState);
EmberAfStatus status = Attributes::ActuatorEnabled::Set(endpointId, newActuatorState);

bool status = (Attributes::ActuatorEnabled::Set(endpointId, newActuatorState) == EMBER_ZCL_STATUS_SUCCESS);
if (!status)
if (EMBER_ZCL_STATUS_SUCCESS != status)
{
ChipLogError(Zcl, "Unable to set the Actuator State to %hhu: internal error", actuatorState);
ChipLogError(Zcl, "Unable to set ActuatorEnabled attribute: status=0x%" PRIx8, status);
}

return false;
return (EMBER_ZCL_STATUS_SUCCESS == status);
}

bool DoorLockServer::SetDoorState(chip::EndpointId endpointId, DlDoorState newDoorState)
{
auto doorState = static_cast<uint8_t>(newDoorState);
auto doorState = chip::to_underlying(newDoorState);

emberAfDoorLockClusterPrintln("Setting Door State to '%hhu'", doorState);
bool status = (Attributes::DoorState::Set(endpointId, newDoorState) == EMBER_ZCL_STATUS_SUCCESS);
emberAfDoorLockClusterPrintln("Setting DoorState to '%" PRIu8 "'", doorState);
EmberAfStatus status = Attributes::DoorState::Set(endpointId, newDoorState);

if (!status)
if (EMBER_ZCL_STATUS_SUCCESS != status)
{
ChipLogError(Zcl, "Unable to set the Door State to %hhu: internal error", doorState);
ChipLogError(Zcl, "Unable to set DoorState attribute: status=0x%" PRIx8, status);
}

return false;
return (EMBER_ZCL_STATUS_SUCCESS == status);
}

bool DoorLockServer::SetLanguage(chip::EndpointId endpointId, const char * newLanguage)
{
return true;
auto lang = chip::CharSpan(newLanguage, strlen(newLanguage));

emberAfDoorLockClusterPrintln("Setting Language to '%s'", newLanguage);
EmberAfStatus status = Attributes::Language::Set(endpointId, lang);

if (EMBER_ZCL_STATUS_SUCCESS != status)
{
ChipLogError(Zcl, "Unable to set Language attribute: status=0x%" PRIx8, status);
}

return (EMBER_ZCL_STATUS_SUCCESS == status);
}

bool DoorLockServer::SetAutoRelockTime(chip::EndpointId, uint32_t newAutoRelockTimeSec)
bool DoorLockServer::SetAutoRelockTime(chip::EndpointId endpointId, uint32_t newAutoRelockTimeSec)
{
return true;
emberAfDoorLockClusterPrintln("Setting AutoRelockTime to '%" PRIu32 "'", newAutoRelockTimeSec);
EmberAfStatus status = Attributes::AutoRelockTime::Set(endpointId, newAutoRelockTimeSec);

if (EMBER_ZCL_STATUS_SUCCESS != status)
{
ChipLogError(Zcl, "Unable to set AutoRelockTime attribute: status=0x%" PRIx8, status);
}

return (EMBER_ZCL_STATUS_SUCCESS == status);
}

bool DoorLockServer::SetSoundVolume(chip::EndpointId endpointId, uint8_t newSoundVolume)
{
return true;
emberAfDoorLockClusterPrintln("Setting SoundVolume to '%" PRIu8 "'", newSoundVolume);
EmberAfStatus status = Attributes::SoundVolume::Set(endpointId, newSoundVolume);

if (EMBER_ZCL_STATUS_SUCCESS != status)
{
ChipLogError(Zcl, "Unable to set SoundVolume attribute: status=0x%" PRIx8, status);
}

return (EMBER_ZCL_STATUS_SUCCESS == status);
}

bool DoorLockServer::SetOneTouchLocking(chip::EndpointId endpointId, bool isEnabled)
{
return true;
auto enable = static_cast<uint8_t>(isEnabled);

emberAfDoorLockClusterPrintln("Setting EnableOneTouchLocking to '%" PRIu8 "'", enable);
EmberAfStatus status = Attributes::EnableOneTouchLocking::Set(endpointId, isEnabled);

if (EMBER_ZCL_STATUS_SUCCESS != status)
{
ChipLogError(Zcl, "Unable to set EnableOneTouchLocking attribute: status=0x%" PRIx8, status);
}

return (EMBER_ZCL_STATUS_SUCCESS == status);
}

bool DoorLockServer::SetPrivacyModeButton(chip::EndpointId endpointId, bool isEnabled)
{
return true;
auto enable = static_cast<uint8_t>(isEnabled);

emberAfDoorLockClusterPrintln("Setting EnablePrivacyModeButton to '%" PRIu8 "'", enable);
EmberAfStatus status = Attributes::EnablePrivacyModeButton::Set(endpointId, isEnabled);

if (EMBER_ZCL_STATUS_SUCCESS != status)
{
ChipLogError(Zcl, "Unable to set EnablePrivacyModeButton attribute: status=0x%" PRIx8, status);
}

return (EMBER_ZCL_STATUS_SUCCESS == status);
}

// =======================================================
Expand All @@ -143,7 +190,6 @@ bool emberAfDoorLockClusterLockDoorCallback(chip::app::CommandHandler * commandO
emberAfDoorLockClusterPrintln("Received Lock Door command (not implemented)");

// TODO: Implement door locking by calling emberAfPluginDoorLockOnDoorLockCommand

emberAfSendImmediateDefaultResponse(EMBER_ZCL_STATUS_SUCCESS);
return true;
}
Expand Down Expand Up @@ -229,8 +275,109 @@ chip::Protocols::InteractionModel::Status
MatterDoorLockClusterServerPreAttributeChangedCallback(const chip::app::ConcreteAttributePath & attributePath,
EmberAfAttributeType attributeType, uint16_t size, uint8_t * value)
{
// TODO: Implement attribute changes
return chip::Protocols::InteractionModel::Status::Success;
chip::Protocols::InteractionModel::Status res;

switch (attributePath.mAttributeId)
{
case chip::app::Clusters::DoorLock::Attributes::Language::Id:
if (value[0] <= 3)
{
char lang[3 + 1] = { 0 };
memcpy(lang, &value[1], value[0]);
res = emberAfPluginDoorLockOnLanguageChange(attributePath.mEndpointId, lang);
}
else
{
res = chip::Protocols::InteractionModel::Status::InvalidValue;
}
break;

case chip::app::Clusters::DoorLock::Attributes::AutoRelockTime::Id:
if (sizeof(uint32_t) == size)
{
uint32_t newRelockTime = *(reinterpret_cast<uint32_t *>(value));
res = emberAfPluginDoorLockOnAutoRelockTimeChange(attributePath.mEndpointId, newRelockTime);
}
else
{
res = chip::Protocols::InteractionModel::Status::InvalidValue;
}
break;

case chip::app::Clusters::DoorLock::Attributes::SoundVolume::Id:
if (sizeof(uint8_t) == size)
{
res = emberAfPluginDoorLockOnSoundVolumeChange(attributePath.mEndpointId, *value);
}
else
{
res = chip::Protocols::InteractionModel::Status::InvalidValue;
}
break;

case chip::app::Clusters::DoorLock::Attributes::OperatingMode::Id:
if (sizeof(uint8_t) == size)
{
res = emberAfPluginDoorLockOnOperatingModeChange(attributePath.mEndpointId, *value);
}
else
{
res = chip::Protocols::InteractionModel::Status::InvalidValue;
}
break;

case chip::app::Clusters::DoorLock::Attributes::EnableOneTouchLocking::Id:
if (sizeof(bool) == size)
{
bool enable = *reinterpret_cast<bool *>(value);
res = emberAfPluginDoorLockOnEnableOneTouchLockingChange(attributePath.mEndpointId, enable);
}
else
{
res = chip::Protocols::InteractionModel::Status::InvalidValue;
}
break;

case chip::app::Clusters::DoorLock::Attributes::EnablePrivacyModeButton::Id:
if (sizeof(bool) == size)
{
bool enable = *reinterpret_cast<bool *>(value);
res = emberAfPluginDoorLockOnEnablePrivacyModeButtonChange(attributePath.mEndpointId, enable);
}
else
{
res = chip::Protocols::InteractionModel::Status::InvalidValue;
}
break;

case chip::app::Clusters::DoorLock::Attributes::WrongCodeEntryLimit::Id:
if (sizeof(uint8_t) == size)
{
res = emberAfPluginDoorLockOnWrongCodeEntryLimitChange(attributePath.mEndpointId, *value);
}
else
{
res = chip::Protocols::InteractionModel::Status::InvalidValue;
}
break;

case chip::app::Clusters::DoorLock::Attributes::UserCodeTemporaryDisableTime::Id:
if (sizeof(uint8_t) == size)
{
res = emberAfPluginDoorLockOnUserCodeTemporaryDisableTimeChange(attributePath.mEndpointId, *value);
}
else
{
res = chip::Protocols::InteractionModel::Status::InvalidValue;
}
break;

default:
res = emberAfPluginDoorLockOnUnhandledAttributeChange(attributePath.mEndpointId, attributeType, size, value);
break;
}

return res;
}

void emberAfPluginDoorLockServerLockoutEventHandler(void) {}
Expand All @@ -243,3 +390,62 @@ void MatterDoorLockPluginServerInitCallback()
}

void MatterDoorLockClusterServerAttributeChangedCallback(const app::ConcreteAttributePath & attributePath) {}

// =============================================================================
// Pre-change callbacks for cluster attributes
// =============================================================================

chip::Protocols::InteractionModel::Status __attribute__((weak))
emberAfPluginDoorLockOnLanguageChange(chip::EndpointId EndpointId, const char * newLanguage)
{
return chip::Protocols::InteractionModel::Status::Success;
}

chip::Protocols::InteractionModel::Status __attribute__((weak))
emberAfPluginDoorLockOnAutoRelockTimeChange(chip::EndpointId EndpointId, uint32_t newTime)
{
return chip::Protocols::InteractionModel::Status::Success;
}

chip::Protocols::InteractionModel::Status __attribute__((weak))
emberAfPluginDoorLockOnSoundVolumeChange(chip::EndpointId EndpointId, uint8_t newVolume)
{
return chip::Protocols::InteractionModel::Status::Success;
}

chip::Protocols::InteractionModel::Status __attribute__((weak))
emberAfPluginDoorLockOnOperatingModeChange(chip::EndpointId EndpointId, uint8_t newMode)
{
return chip::Protocols::InteractionModel::Status::Success;
}

chip::Protocols::InteractionModel::Status __attribute__((weak))
emberAfPluginDoorLockOnEnableOneTouchLockingChange(chip::EndpointId EndpointId, bool enable)
{
return chip::Protocols::InteractionModel::Status::Success;
}

chip::Protocols::InteractionModel::Status __attribute__((weak))
emberAfPluginDoorLockOnEnablePrivacyModeButtonChange(chip::EndpointId EndpointId, bool enable)
{
return chip::Protocols::InteractionModel::Status::Success;
}

chip::Protocols::InteractionModel::Status __attribute__((weak))
emberAfPluginDoorLockOnWrongCodeEntryLimitChange(chip::EndpointId EndpointId, uint8_t newLimit)
{
return chip::Protocols::InteractionModel::Status::Success;
}

chip::Protocols::InteractionModel::Status __attribute__((weak))
emberAfPluginDoorLockOnUserCodeTemporaryDisableTimeChange(chip::EndpointId EndpointId, uint8_t newTime)
{
return chip::Protocols::InteractionModel::Status::Success;
}

chip::Protocols::InteractionModel::Status __attribute__((weak))
emberAfPluginDoorLockOnUnhandledAttributeChange(chip::EndpointId EndpointId, EmberAfAttributeType attrType, uint16_t attrSize,
uint8_t * attrValue)
{
return chip::Protocols::InteractionModel::Status::Success;
}
Loading

0 comments on commit 17520c3

Please sign in to comment.