blob: 73c06996717139015fc3080656da8c2fdbd68887 [file] [log] [blame]
/*
*
* Copyright (c) 2020 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.
*/
/****************************************************************************
* @file
* @brief Implementation for the Binding Server Cluster
***************************************************************************/
#include <app/util/af.h>
#include <app-common/zap-generated/cluster-objects.h>
#include <app/CommandHandler.h>
#include <app/ConcreteCommandPath.h>
#include <app/util/binding-table.h>
#include <lib/support/logging/CHIPLogging.h>
using namespace chip;
using namespace chip::app::Clusters::Binding;
EmberStatus prepareBinding(EmberBindingTableEntry & binding, NodeId nodeId, GroupId groupId, EndpointId endpointId,
ClusterId clusterId)
{
if (groupId && nodeId)
{
return EMBER_BAD_ARGUMENT;
}
binding.clusterId = clusterId;
binding.local = emberAfCurrentCommand()->apsFrame->destinationEndpoint;
binding.networkIndex = 0;
if (groupId)
{
binding.type = EMBER_MULTICAST_BINDING;
binding.groupId = groupId;
binding.remote = 0;
}
else
{
binding.type = EMBER_UNICAST_BINDING;
binding.nodeId = nodeId;
binding.remote = endpointId;
}
return EMBER_SUCCESS;
}
EmberStatus getBindingIndex(EmberBindingTableEntry & newEntry, uint8_t * bindingIndex)
{
EmberBindingTableEntry currentEntry;
for (uint8_t i = 0; i < EMBER_BINDING_TABLE_SIZE; i++)
{
emberGetBinding(i, &currentEntry);
if (currentEntry.type != EMBER_UNUSED_BINDING && currentEntry == newEntry)
{
*bindingIndex = i;
return EMBER_SUCCESS;
}
}
return EMBER_NOT_FOUND;
}
EmberStatus getUnusedBindingIndex(uint8_t * bindingIndex)
{
EmberBindingTableEntry currentEntry;
for (uint8_t i = 0; i < EMBER_BINDING_TABLE_SIZE; i++)
{
emberGetBinding(i, &currentEntry);
if (currentEntry.type == EMBER_UNUSED_BINDING)
{
*bindingIndex = i;
return EMBER_SUCCESS;
}
}
return EMBER_NOT_FOUND;
}
bool emberAfBindingClusterBindCallback(app::CommandHandler * commandObj, const app::ConcreteCommandPath & commandPath,
const Commands::Bind::DecodableType & commandData)
{
auto & nodeId = commandData.nodeId;
auto & groupId = commandData.groupId;
auto & endpointId = commandData.endpointId;
auto & clusterId = commandData.clusterId;
ChipLogDetail(Zcl, "RX: BindCallback");
EmberBindingTableEntry bindingEntry;
if (prepareBinding(bindingEntry, nodeId, groupId, endpointId, clusterId) != EMBER_SUCCESS)
{
emberAfSendImmediateDefaultResponse(EMBER_ZCL_STATUS_MALFORMED_COMMAND);
return true;
}
uint8_t bindingIndex;
if (getBindingIndex(bindingEntry, &bindingIndex) != EMBER_NOT_FOUND)
{
emberAfSendImmediateDefaultResponse(EMBER_ZCL_STATUS_DUPLICATE_EXISTS);
return true;
}
if (getUnusedBindingIndex(&bindingIndex) != EMBER_SUCCESS)
{
emberAfSendImmediateDefaultResponse(EMBER_ZCL_STATUS_INSUFFICIENT_SPACE);
return true;
}
emberSetBinding(bindingIndex, &bindingEntry);
emberAfSendImmediateDefaultResponse(EMBER_ZCL_STATUS_SUCCESS);
return true;
}
bool emberAfBindingClusterUnbindCallback(app::CommandHandler * commandObj, const app::ConcreteCommandPath & commandPath,
const Commands::Unbind::DecodableType & commandData)
{
auto & nodeId = commandData.nodeId;
auto & groupId = commandData.groupId;
auto & endpointId = commandData.endpointId;
auto & clusterId = commandData.clusterId;
ChipLogDetail(Zcl, "RX: UnbindCallback");
EmberBindingTableEntry bindingEntry;
if (prepareBinding(bindingEntry, nodeId, groupId, endpointId, clusterId) != EMBER_SUCCESS)
{
emberAfSendImmediateDefaultResponse(EMBER_ZCL_STATUS_MALFORMED_COMMAND);
return true;
}
uint8_t bindingIndex;
if (getBindingIndex(bindingEntry, &bindingIndex) != EMBER_SUCCESS)
{
emberAfSendImmediateDefaultResponse(EMBER_ZCL_STATUS_NOT_FOUND);
return true;
}
emberDeleteBinding(bindingIndex);
emberAfSendImmediateDefaultResponse(EMBER_ZCL_STATUS_SUCCESS);
return true;
}
void MatterBindingPluginServerInitCallback() {}