Skip to content

Commit

Permalink
[Chef] Add 2 Generic Switch devices and RPC Actions for Testing (#33255)
Browse files Browse the repository at this point in the history
* Add RPC Event Service draft

* Commit the draft to add_event in post attr change

Commit the draft to add_event in post attribute change callback

* Add PreAttributeChangeCallback

* Support write events as string through RPC

* Revert Chef stubs.cpp to not using AttributeDelegate

* RPC can call delegate to SwitchManager/EventHandler

* Rmove ununsed RPC command delegate

* Rename RPC Event to RPC Actions

* Simplify RPC code by setting transparent subscribe

* Chef RPC Actions Draft done.

TBD:
        Debug
        Optimize
        Error code
        Confirm timer is ms

* Fix timer bug, remove unused comments

* Add Latching Switch taglist to Descriptor Cluster

* Cross platform built on ESP32/nRFConnect done

And also enable the ApplicationInit

* Update Generic Switch 1

* Add 2nd Generic Switch

* Add chef/common/chef-descriptor-namespace.h

* Remote printf

* Remove TODO

* Remove unused comments

* Restyled by whitespace

* Restyled by clang-format

* Fix according to PR comments

#33255

* Restyled by clang-format

* Fix compilation issues

* Remove unused debugging codes

---------

Co-authored-by: Restyled.io <commits@restyled.io>
  • Loading branch information
erwinpan1 and restyled-commits committed May 27, 2024
1 parent 3718e99 commit 42510ba
Show file tree
Hide file tree
Showing 29 changed files with 5,872 additions and 8 deletions.
51 changes: 51 additions & 0 deletions examples/chef/common/chef-descriptor-namespace.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
*
* Copyright (c) 2024 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.
*/

#pragma once

// Please refer to https://github.com/CHIP-Specifications/connectedhomeip-spec/blob/master/src/namespaces
constexpr const uint8_t kNamespaceCommonLevel = 5;
// Common Number Namespace: 5, tag 0 (Low)
constexpr const uint8_t kTagCommonLow = 0;
// Common Number Namespace: 5, tag 1 (Medium)
constexpr const uint8_t kTagCommonMedium = 1;
// Common Number Namespace: 5, tag 2 (High)
constexpr const uint8_t kTagCommonHigh = 2;

constexpr const uint8_t kNamespaceCommonNumber = 7;
// Common Number Namespace: 7, tag 0 (Zero)
constexpr const uint8_t kTagCommonZero = 0;
// Common Number Namespace: 7, tag 1 (One)
constexpr const uint8_t kTagCommonOne = 1;
// Common Number Namespace: 7, tag 2 (Two)
constexpr const uint8_t kTagCommonTwo = 2;

constexpr const uint8_t kNamespacePosition = 8;
// Common Position Namespace: 8, tag: 0 (Left)
constexpr const uint8_t kTagPositionLeft = 0;
// Common Position Namespace: 8, tag: 1 (Right)
constexpr const uint8_t kTagPositionRight = 1;
// Common Position Namespace: 8, tag: 2 (Top)
constexpr const uint8_t kTagPositionTop = 2;
// Common Position Namespace: 8, tag: 3 (Bottom)
constexpr const uint8_t kTagPositionBottom = 3;
// Common Position Namespace: 8, tag: 4 (Middle)
constexpr const uint8_t kTagPositionMiddle = 4;
// Common Position Namespace: 8, tag: 5 (Row)
constexpr const uint8_t kTagPositionRow = 5;
// Common Position Namespace: 8, tag: 6 (Column)
constexpr const uint8_t kTagPositionColumn = 6;
158 changes: 158 additions & 0 deletions examples/chef/common/chef-rpc-actions-worker.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
/*
*
* 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()
{
chip::rpc::SubscribeActions(ChefRpcActionsCallback);
}

static ChefRpcActionsWorker instance;

ChefRpcActionsWorker & ChefRpcActionsWorker::Instance()
{
return instance;
}
79 changes: 79 additions & 0 deletions examples/chef/common/chef-rpc-actions-worker.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
/*
*
* 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.
*/

#pragma once

#include <app/clusters/mode-base-server/mode-base-server.h>
#include <app/util/config.h>
#include <cstring>
#include <queue>
#include <utility>
#include <vector>

#include "Rpc.h"

namespace chip {
namespace app {

class ActionsDelegate
{
public:
ActionsDelegate(ClusterId clusterId) : mClusterId(clusterId){};

virtual ~ActionsDelegate() = default;

virtual void AttributeWriteHandler(chip::EndpointId endpointId, chip::AttributeId attributeId, std::vector<uint32_t> args) = 0;
virtual void CommandHandler(chip::EndpointId endpointId, chip::CommandId commandId, std::vector<uint32_t> args) = 0;
virtual void EventHandler(chip::EndpointId endpointId, chip::EventId eventId, std::vector<uint32_t> args) = 0;

protected:
ClusterId mClusterId;
};

struct ActionTask
{
chip::EndpointId endpointId;
chip::ClusterId clusterId;
chip::rpc::ActionType type; // Aligned with Storage buf
uint32_t delayMs;
uint32_t actionId;
std::vector<uint32_t> args;
ActionTask(chip::EndpointId endpoint, chip::ClusterId cluster, chip::rpc::ActionType actionType, uint32_t delay, uint32_t id,
std::vector<uint32_t> arg) :
endpointId(endpoint),
clusterId(cluster), type(actionType), delayMs(delay), actionId(id), args(arg){};
~ActionTask(){};
};

class ChefRpcActionsWorker
{
public:
static ChefRpcActionsWorker & Instance();

ChefRpcActionsWorker();

bool EnqueueAction(ActionTask task);
void ProcessActionQueue();
void RegisterRpcActionsDelegate(ClusterId clusterId, ActionsDelegate * delegate);

private:
std::queue<ActionTask> queue;
};

} // namespace app
} // namespace chip
82 changes: 82 additions & 0 deletions examples/chef/common/clusters/switch/SwitchEventHandler.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/*
*
* Copyright (c) 2022 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 <app-common/zap-generated/attributes/Accessors.h>
#ifdef MATTER_DM_PLUGIN_SWITCH_SERVER
#include <app/clusters/switch-server/switch-server.h>
#include <app/server/Server.h>
#include <app/util/att-storage.h>
#include <platform/PlatformManager.h>

#include "SwitchEventHandler.h"

using namespace chip;
using namespace chip::app;
using namespace chip::app::Clusters;
using namespace chip::app::Clusters::Switch;
using namespace chip::DeviceLayer;

void SwitchEventHandler::OnSwitchLatched(EndpointId endpointId, uint8_t newPosition)
{
ChipLogDetail(NotSpecified, "%s: endpointId=%d, newPosition=%d", __func__, endpointId, newPosition);

Clusters::SwitchServer::Instance().OnSwitchLatch(endpointId, newPosition);
}

void SwitchEventHandler::OnInitialPress(EndpointId endpointId, uint8_t newPosition)
{
ChipLogDetail(NotSpecified, "%s: endpointId=%d, newPosition=%d", __func__, endpointId, newPosition);

Clusters::SwitchServer::Instance().OnInitialPress(endpointId, newPosition);
}

void SwitchEventHandler::OnLongPress(EndpointId endpointId, uint8_t newPosition)
{
ChipLogDetail(NotSpecified, "%s: endpointId=%d, newPosition=%d", __func__, endpointId, newPosition);

Clusters::SwitchServer::Instance().OnLongPress(endpointId, newPosition);
}

void SwitchEventHandler::OnShortRelease(EndpointId endpointId, uint8_t previousPosition)
{
ChipLogDetail(NotSpecified, "%s: endpointId=%d, previousPosition=%d", __func__, endpointId, previousPosition);

Clusters::SwitchServer::Instance().OnShortRelease(endpointId, previousPosition);
}

void SwitchEventHandler::OnLongRelease(EndpointId endpointId, uint8_t previousPosition)
{
ChipLogDetail(NotSpecified, "%s: endpointId=%d, previousPosition=%d", __func__, endpointId, previousPosition);

Clusters::SwitchServer::Instance().OnLongRelease(endpointId, previousPosition);
}

void SwitchEventHandler::OnMultiPressOngoing(EndpointId endpointId, uint8_t newPosition, uint8_t count)
{
ChipLogDetail(NotSpecified, "%s: endpointId=%d, newPosition=%d, count=%d", __func__, endpointId, newPosition, count);

Clusters::SwitchServer::Instance().OnMultiPressOngoing(endpointId, newPosition, count);
}

void SwitchEventHandler::OnMultiPressComplete(EndpointId endpointId, uint8_t previousPosition, uint8_t count)
{
ChipLogDetail(NotSpecified, "%s: endpointId=%d, previousPosition=%d, count=%d", __func__, endpointId, previousPosition, count);

Clusters::SwitchServer::Instance().OnMultiPressComplete(endpointId, previousPosition, count);
}
#endif // MATTER_DM_PLUGIN_SWITCH_SERVER
Loading

0 comments on commit 42510ba

Please sign in to comment.