blob: 28413f098b6bcc54886498280770bf568676decf [file] [log] [blame]
/*
*
* Copyright (c) 2024 Project CHIP Authors
* All rights reserved.
*
* 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 "chef-rpc-actions-worker.h"
#include <app-common/zap-generated/attributes/Accessors.h>
#include <app-common/zap-generated/callback.h>
#include <app/data-model/Nullable.h>
#include <app/util/config.h>
#include <lib/core/DataModelTypes.h>
#include <map>
#include <platform/CHIPDeviceLayer.h>
using chip::app::DataModel::Nullable;
using namespace chip;
using namespace chip::app;
using namespace chip::app::Clusters;
using namespace chip::rpc;
static std::map<ClusterId, ActionsDelegate *> gActionsDelegateMap{};
ActionsDelegate * RpcFindActionsDelegate(ClusterId clusterId)
{
if (gActionsDelegateMap.find(clusterId) != gActionsDelegateMap.end())
{
return gActionsDelegateMap[clusterId];
}
return nullptr;
}
static void RpcActionsTaskCallback(System::Layer * systemLayer, void * data)
{
ChefRpcActionsWorker * worker = (ChefRpcActionsWorker *) data;
worker->ProcessActionQueue();
}
bool ChefRpcActionsCallback(EndpointId endpointId, ClusterId clusterId, uint8_t type, uint32_t delayMs, uint32_t actionId,
std::vector<uint32_t> args)
{
ActionTask task(endpointId, clusterId, static_cast<ActionType>(type), delayMs, actionId, args);
return ChefRpcActionsWorker::Instance().EnqueueAction(task);
}
bool ChefRpcActionsWorker::EnqueueAction(ActionTask task)
{
bool kickTimer = false;
if (queue.empty())
{
kickTimer = true; // kick timer when the first task is adding to the queue
}
queue.push(task);
if (kickTimer)
{
(void) DeviceLayer::SystemLayer().StartTimer(System::Clock::Milliseconds32(task.delayMs), RpcActionsTaskCallback, this);
}
return true;
}
void ChefRpcActionsWorker::ProcessActionQueue()
{
// Dequeue the first item
ActionTask task = queue.front();
queue.pop();
ActionsDelegate * delegate = RpcFindActionsDelegate(task.clusterId);
if (nullptr == delegate)
{
ChipLogError(NotSpecified,
"Cannot run action due to not finding delegate: endpointId=%d, clusterId=%04lx, attributeId=%04lx",
task.endpointId, static_cast<unsigned long>(task.clusterId), static_cast<unsigned long>(task.actionId));
return;
}
ActionType type = static_cast<ActionType>(task.type);
switch (type)
{
case ActionType::WRITE_ATTRIBUTE: {
ChipLogProgress(NotSpecified, "Writing Attribute: endpointId=%d, clusterId=%04lx, attributeId=%04lx, args.size=%lu",
task.endpointId, static_cast<unsigned long>(task.clusterId), static_cast<unsigned long>(task.actionId),
static_cast<unsigned long>(task.args.size()));
delegate->AttributeWriteHandler(task.endpointId, static_cast<chip::AttributeId>(task.actionId), task.args);
}
break;
case ActionType::RUN_COMMAND: {
ChipLogProgress(NotSpecified, "Running Command: endpointId=%d, clusterId=%04lx, commandId=%04lx, args.size=%lu",
task.endpointId, static_cast<unsigned long>(task.clusterId), static_cast<unsigned long>(task.actionId),
static_cast<unsigned long>(task.args.size()));
delegate->CommandHandler(task.endpointId, static_cast<chip::CommandId>(task.actionId), task.args);
}
break;
case ActionType::EMIT_EVENT: {
ChipLogProgress(NotSpecified, "Emitting Event: endpointId=%d, clusterId=%04lx, eventIdId=%04lx, args.size=%lu",
task.endpointId, static_cast<unsigned long>(task.clusterId), static_cast<unsigned long>(task.actionId),
static_cast<unsigned long>(task.args.size()));
delegate->EventHandler(task.endpointId, static_cast<chip::EventId>(task.actionId), task.args);
}
break;
default:
break;
}
if (queue.empty())
{
// Return due to no more actions in queue
return;
}
// Run next action
task = queue.front();
ChipLogProgress(NotSpecified, "StartTimer: endpointId=%d, clusterId=%04lx, eventIdId=%04lx, task.delyMs=%lu", task.endpointId,
static_cast<unsigned long>(task.clusterId), static_cast<unsigned long>(task.actionId),
static_cast<unsigned long>(task.delayMs));
(void) DeviceLayer::SystemLayer().StartTimer(System::Clock::Milliseconds32(task.delayMs), RpcActionsTaskCallback, this);
}
void ChefRpcActionsWorker::RegisterRpcActionsDelegate(ClusterId clusterId, ActionsDelegate * delegate)
{
// Register by cluster
if (nullptr == RpcFindActionsDelegate(clusterId))
{
gActionsDelegateMap[clusterId] = delegate;
return;
}
}
ChefRpcActionsWorker::ChefRpcActionsWorker()
{
#if CONFIG_ENABLE_PW_RPC
chip::rpc::SubscribeActions(ChefRpcActionsCallback);
#endif
}
static ChefRpcActionsWorker instance;
ChefRpcActionsWorker & ChefRpcActionsWorker::Instance()
{
return instance;
}