Skip to content

Commit

Permalink
Add a way to trigger lock/unlock in linux lock-app by writing JSON to…
Browse files Browse the repository at this point in the history
… the FIFO. (#29919)

Adds support for lock/unlock, with or without PIN.  PIN can specified as either
hex or ASCII digits.
  • Loading branch information
bzbarsky-apple authored and pull[bot] committed Jan 16, 2024
1 parent 0d1b789 commit 1441276
Showing 1 changed file with 94 additions and 0 deletions.
94 changes: 94 additions & 0 deletions examples/lock-app/linux/src/LockAppCommandDelegate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
*/

#include "LockAppCommandDelegate.h"
#include <lib/support/BytesToHex.h>
#include <platform/PlatformManager.h>

#include <LockManager.h>
Expand All @@ -36,6 +37,10 @@ class LockAppCommandHandler
{}

private:
// aCommand should be "lock" or "unlock".
static CHIP_ERROR ExtractPINFromParams(const char * aCommand, const Json::Value & aParams, Optional<chip::ByteSpan> & aPIN,
chip::Platform::ScopedMemoryBuffer<uint8_t> & aPINBuffer);

std::string mCommandName;
Json::Value mCommandParameters;
};
Expand Down Expand Up @@ -84,6 +89,7 @@ void LockAppCommandHandler::HandleCommand(intptr_t context)
const auto & params = self->mCommandParameters;
// Determine the endpoint ID from the parameters JSON. If it is missing, use the default endpoint defined in the
// door-lock-server.h
CHIP_ERROR err = CHIP_NO_ERROR;
chip::EndpointId endpointId = DOOR_LOCK_SERVER_ENDPOINT;
if (params.isMember("EndpointId"))
{
Expand Down Expand Up @@ -131,15 +137,103 @@ void LockAppCommandHandler::HandleCommand(intptr_t context)
alarmCode));
LockManager::Instance().SendLockAlarm(endpointId, static_cast<AlarmCodeEnum>(alarmCode));
}
else if (self->mCommandName == "Lock")
{

VerifyOrExit(params["OperationSource"].isUInt(),
ChipLogError(NotSpecified, "Lock App: Unable to execute command to lock: invalid type for OperationSource"));

auto operationSource = params["OperationSource"].asUInt();

Optional<chip::ByteSpan> pin;
chip::Platform::ScopedMemoryBuffer<uint8_t> pinBuffer;
SuccessOrExit(err = ExtractPINFromParams("lock", params, pin, pinBuffer));

OperationErrorEnum error = OperationErrorEnum::kUnspecified;
LockManager::Instance().Lock(endpointId, NullNullable, NullNullable, pin, error, OperationSourceEnum(operationSource));
VerifyOrExit(error == OperationErrorEnum::kUnspecified,
ChipLogError(NotSpecified, "Lock App: Lock error received: %u", to_underlying(error)));
}
else if (self->mCommandName == "Unlock")
{
VerifyOrExit(params["OperationSource"].isUInt(),
ChipLogError(NotSpecified, "Lock App: Unable to execute command to unlock: invalid type for OperationSource"));

auto operationSource = params["OperationSource"].asUInt();

Optional<chip::ByteSpan> pin;
chip::Platform::ScopedMemoryBuffer<uint8_t> pinBuffer;
SuccessOrExit(err = ExtractPINFromParams("unlock", params, pin, pinBuffer));

OperationErrorEnum error = OperationErrorEnum::kUnspecified;
LockManager::Instance().Unlock(endpointId, NullNullable, NullNullable, pin, error, OperationSourceEnum(operationSource));
VerifyOrExit(error == OperationErrorEnum::kUnspecified,
ChipLogError(NotSpecified, "Lock App: Unlock error received: %u", to_underlying(error)));
}
else
{
ChipLogError(NotSpecified, "Lock App: Unable to execute command \"%s\": command not supported", self->mCommandName.c_str());
}

exit:
if (err != CHIP_NO_ERROR)
{
ChipLogError(NotSpecified, "Lock App: Failed executing command \"%s\": %" CHIP_ERROR_FORMAT, self->mCommandName.c_str(),
err.Format());
}
chip::Platform::Delete(self);
}

CHIP_ERROR LockAppCommandHandler::ExtractPINFromParams(const char * aCommand, const Json::Value & aParams,
Optional<chip::ByteSpan> & aPIN,
chip::Platform::ScopedMemoryBuffer<uint8_t> & aPINBuffer)
{
if (aParams.isMember("PINAsHex"))
{
// Hex-encoded PIN bytes. So a PIN consisting of the numbers 123 gets encoded as the string "313233"
VerifyOrReturnError(
aParams["PINAsHex"].isString(), CHIP_ERROR_INVALID_ARGUMENT,
ChipLogError(NotSpecified, "Lock App: Unable to execute command to %s: invalid type for PIN", aCommand));

auto pinAsHex = aParams["PINAsHex"].asString();
size_t size = pinAsHex.length();
VerifyOrReturnError(size % 2 == 0, CHIP_ERROR_INVALID_STRING_LENGTH);

size_t bufferSize = size / 2;

VerifyOrReturnError(aPINBuffer.Calloc(bufferSize), CHIP_ERROR_NO_MEMORY);
size_t octetCount = chip::Encoding::HexToBytes(pinAsHex.c_str(), size, aPINBuffer.Get(), bufferSize);
VerifyOrReturnError(
octetCount != 0 || size == 0, CHIP_ERROR_INVALID_ARGUMENT,
ChipLogError(NotSpecified, "Lock app: Unable to execute command to %s: invalid hex value for PIN", aCommand));

aPIN.Emplace(aPINBuffer.Get(), octetCount);
ChipLogProgress(NotSpecified, "Lock App: Received command to %s with hex PIN: %s", aCommand, pinAsHex.c_str());
}
else if (aParams.isMember("PINAsString"))
{
// ASCII-encoded PIN bytes. So a PIN consisting of the numbers 123 gets encoded as the string "123"
VerifyOrReturnError(
aParams["PINAsString"].isString(), CHIP_ERROR_INVALID_ARGUMENT,
ChipLogError(NotSpecified, "Lock App: Unable to execute command to %s: invalid type for PIN", aCommand));

auto pinAsString = aParams["PINAsString"].asString();
size_t bufferSize = pinAsString.length();

VerifyOrReturnError(aPINBuffer.Calloc(bufferSize), CHIP_ERROR_NO_MEMORY);
memcpy(aPINBuffer.Get(), pinAsString.c_str(), bufferSize);
aPIN.Emplace(aPINBuffer.Get(), bufferSize);

ChipLogProgress(NotSpecified, "Lock App: Received command to %s with string PIN: %s", aCommand, pinAsString.c_str());
}
else
{
aPIN.ClearValue();
}

return CHIP_NO_ERROR;
}

void LockAppCommandDelegate::OnEventCommandReceived(const char * json)
{
auto handler = LockAppCommandHandler::FromJSON(json);
Expand Down

0 comments on commit 1441276

Please sign in to comment.