Skip to content

Commit

Permalink
[Silabs] Add generic witch support to light-switch example (#24642)
Browse files Browse the repository at this point in the history
* Add generic witch support to light-switch example

* restyle

* move shell init to light-switch-mgr

---------

Co-authored-by: Andrei Litvin <[email protected]>
  • Loading branch information
2 people authored and pull[bot] committed Jul 19, 2023
1 parent 3534329 commit 3646581
Show file tree
Hide file tree
Showing 11 changed files with 484 additions and 650 deletions.
10 changes: 9 additions & 1 deletion examples/light-switch-app/silabs/SiWx917/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ efr32_sdk("sdk") {
]

include_dirs = [
"${chip_root}/examples/light-switch-app/silabs/common",
"${chip_root}/src/platform/silabs/SiWx917",
"${efr32_project_dir}/include",
"${examples_plat_dir}",
Expand Down Expand Up @@ -200,14 +201,15 @@ efr32_executable("light_switch_app") {
defines = []

sources = [
"${chip_root}/examples/light-switch-app/silabs/common/BindingHandler.cpp",
"${chip_root}/examples/light-switch-app/silabs/common/LightSwitchMgr.cpp",
"${examples_common_plat_dir}/heap_4_silabs.c",
"${examples_plat_dir}/BaseApplication.cpp",
"${examples_plat_dir}/init_ccpPlatform.cpp",
"${examples_plat_dir}/matter_config.cpp",
"${examples_plat_dir}/siwx917_utils.cpp",
"src/AppTask.cpp",
"src/ZclCallbacks.cpp",
"src/binding-handler.cpp",
"src/main.cpp",
]

Expand All @@ -228,6 +230,12 @@ efr32_executable("light_switch_app") {
"${chip_root}/src/setup_payload",
]

if (chip_build_libshell) {
sources += [
"${chip_root}/examples/light-switch-app/silabs/common/ShellCommands.cpp",
]
}

# Attestation Credentials
if (chip_build_platform_attestation_credentials_provider) {
deps += [ "${examples_plat_dir}:siwx917-attestation-credentials" ]
Expand Down
60 changes: 35 additions & 25 deletions examples/light-switch-app/silabs/SiWx917/src/AppTask.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,25 @@
#include "AppTask.h"
#include "AppConfig.h"
#include "AppEvent.h"
#include "binding-handler.h"
#include "BindingHandler.h"

#ifdef ENABLE_WSTK_LEDS
#include "LEDWidget.h"
#endif // ENABLE_WSTK_LEDS

#include "LightSwitchMgr.h"

#ifdef DISPLAY_ENABLED
#include "lcd.h"
#ifdef QR_CODE_ENABLED
#include "qrcodegen.h"
#endif // QR_CODE_ENABLED
#endif // DISPLAY_ENABLED

#if defined(ENABLE_CHIP_SHELL)
#include "ShellCommands.h"
#endif // defined(ENABLE_CHIP_SHELL)

#include <app-common/zap-generated/attribute-id.h>
#include <app-common/zap-generated/attribute-type.h>
#include <app/server/OnboardingCodesUtil.h>
Expand All @@ -59,6 +65,13 @@
#define APP_FUNCTION_BUTTON &sl_button_btn0
#define APP_LIGHT_SWITCH &sl_button_btn1

namespace {

constexpr chip::EndpointId kLightSwitchEndpoint = 1;
constexpr chip::EndpointId kGenericSwitchEndpoint = 2;

} // namespace

using namespace chip;
using namespace ::chip::DeviceLayer;

Expand All @@ -70,8 +83,6 @@ namespace {

EmberAfIdentifyEffectIdentifier sIdentifyEffect = EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_STOP_EFFECT;

bool mCurrentButtonState = false;

/**********************************************************
* Identify Callbacks
*********************************************************/
Expand Down Expand Up @@ -159,14 +170,17 @@ CHIP_ERROR AppTask::Init()
appError(err);
}

// Configure Bindings - TODO ERROR PROCESSING
err = InitBindingHandler();
err = LightSwitchMgr::GetInstance().Init(kLightSwitchEndpoint, kGenericSwitchEndpoint);
if (err != CHIP_NO_ERROR)
{
SILABS_LOG("InitBindingHandler() failed");
SILABS_LOG("LightSwitchMgr Init failed!");
appError(err);
}

#if defined(ENABLE_CHIP_SHELL)
LightSwtichCommands::RegisterSwitchCommands();
#endif // defined(ENABLE_CHIP_SHELL)

return err;
}

Expand Down Expand Up @@ -223,36 +237,32 @@ void AppTask::OnIdentifyStop(Identify * identify)

void AppTask::SwitchActionEventHandler(AppEvent * aEvent)
{
if (aEvent->Type == AppEvent::kEventType_Button)
VerifyOrReturn(aEvent->Type == AppEvent::kEventType_Button);

static bool mCurrentButtonState = false;

if (aEvent->ButtonEvent.Action == SL_SIMPLE_BUTTON_PRESSED)
{
BindingCommandData * data = Platform::New<BindingCommandData>();
data->clusterId = chip::app::Clusters::OnOff::Id;
mCurrentButtonState = !mCurrentButtonState;
LightSwitchMgr::LightSwitchAction action =
mCurrentButtonState ? LightSwitchMgr::LightSwitchAction::On : LightSwitchMgr::LightSwitchAction::Off;

if (mCurrentButtonState)
{
mCurrentButtonState = false;
data->commandId = chip::app::Clusters::OnOff::Commands::Off::Id;
}
else
{
data->commandId = chip::app::Clusters::OnOff::Commands::On::Id;
mCurrentButtonState = true;
}
LightSwitchMgr::GetInstance().TriggerLightSwitchAction(action);
LightSwitchMgr::GetInstance().GenericSwitchOnInitialPress();

#ifdef DISPLAY_ENABLED
sAppTask.GetLCD().WriteDemoUI(mCurrentButtonState);
#endif

DeviceLayer::PlatformMgr().ScheduleWork(SwitchWorkerFunction, reinterpret_cast<intptr_t>(data));
}
else if (aEvent->ButtonEvent.Action == SL_SIMPLE_BUTTON_RELEASED)
{
LightSwitchMgr::GetInstance().GenericSwitchOnShortRelease();
}
}

void AppTask::ButtonEventHandler(const sl_button_t * buttonHandle, uint8_t btnAction)
{
if (buttonHandle == NULL)
{
return;
}
VerifyOrReturn(buttonHandle != NULL);

AppEvent button_event = {};
button_event.Type = AppEvent::kEventType_Button;
Expand Down
161 changes: 161 additions & 0 deletions examples/light-switch-app/silabs/common/BindingHandler.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
/*
*
* 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.
*/

#include "BindingHandler.h"

#include "AppConfig.h"
#include "app/CommandSender.h"
#include "app/clusters/bindings/BindingManager.h"
#include "app/server/Server.h"
#include "controller/InvokeInteraction.h"
#include "platform/CHIPDeviceLayer.h"
#include <app/clusters/bindings/bindings.h>
#include <lib/support/CodeUtils.h>

using namespace chip;
using namespace chip::app;

namespace {

void ProcessOnOffUnicastBindingCommand(CommandId commandId, const EmberBindingTableEntry & binding,
Messaging::ExchangeManager * exchangeMgr, const SessionHandle & sessionHandle)
{
auto onSuccess = [](const ConcreteCommandPath & commandPath, const StatusIB & status, const auto & dataResponse) {
ChipLogProgress(NotSpecified, "OnOff command succeeds");
};

auto onFailure = [](CHIP_ERROR error) {
ChipLogError(NotSpecified, "OnOff command failed: %" CHIP_ERROR_FORMAT, error.Format());
};

switch (commandId)
{
case Clusters::OnOff::Commands::Toggle::Id:
Clusters::OnOff::Commands::Toggle::Type toggleCommand;
Controller::InvokeCommandRequest(exchangeMgr, sessionHandle, binding.remote, toggleCommand, onSuccess, onFailure);
break;

case Clusters::OnOff::Commands::On::Id:
Clusters::OnOff::Commands::On::Type onCommand;
Controller::InvokeCommandRequest(exchangeMgr, sessionHandle, binding.remote, onCommand, onSuccess, onFailure);
break;

case Clusters::OnOff::Commands::Off::Id:
Clusters::OnOff::Commands::Off::Type offCommand;
Controller::InvokeCommandRequest(exchangeMgr, sessionHandle, binding.remote, offCommand, onSuccess, onFailure);
break;
}
}

void ProcessOnOffGroupBindingCommand(CommandId commandId, const EmberBindingTableEntry & binding)
{
Messaging::ExchangeManager & exchangeMgr = Server::GetInstance().GetExchangeManager();

switch (commandId)
{
case Clusters::OnOff::Commands::Toggle::Id:
Clusters::OnOff::Commands::Toggle::Type toggleCommand;
Controller::InvokeGroupCommandRequest(&exchangeMgr, binding.fabricIndex, binding.groupId, toggleCommand);
break;

case Clusters::OnOff::Commands::On::Id:
Clusters::OnOff::Commands::On::Type onCommand;
Controller::InvokeGroupCommandRequest(&exchangeMgr, binding.fabricIndex, binding.groupId, onCommand);

break;

case Clusters::OnOff::Commands::Off::Id:
Clusters::OnOff::Commands::Off::Type offCommand;
Controller::InvokeGroupCommandRequest(&exchangeMgr, binding.fabricIndex, binding.groupId, offCommand);
break;
}
}

void LightSwitchChangedHandler(const EmberBindingTableEntry & binding, OperationalDeviceProxy * peer_device, void * context)
{
VerifyOrReturn(context != nullptr, ChipLogError(NotSpecified, "OnDeviceConnectedFn: context is null"));
BindingCommandData * data = static_cast<BindingCommandData *>(context);

if (binding.type == EMBER_MULTICAST_BINDING && data->isGroup)
{
switch (data->clusterId)
{
case Clusters::OnOff::Id:
ProcessOnOffGroupBindingCommand(data->commandId, binding);
break;
}
}
else if (binding.type == EMBER_UNICAST_BINDING && !data->isGroup)
{
switch (data->clusterId)
{
case Clusters::OnOff::Id:
VerifyOrDie(peer_device != nullptr && peer_device->ConnectionReady());
ProcessOnOffUnicastBindingCommand(data->commandId, binding, peer_device->GetExchangeManager(),
peer_device->GetSecureSession().Value());
break;
}
}
}

void LightSwitchContextReleaseHandler(void * context)
{
VerifyOrReturn(context != nullptr, ChipLogError(NotSpecified, "LightSwitchContextReleaseHandler: context is null"));
Platform::Delete(static_cast<BindingCommandData *>(context));
}

void InitBindingHandlerInternal(intptr_t arg)
{
auto & server = chip::Server::GetInstance();
chip::BindingManager::GetInstance().Init(
{ &server.GetFabricTable(), server.GetCASESessionManager(), &server.GetPersistentStorage() });
chip::BindingManager::GetInstance().RegisterBoundDeviceChangedHandler(LightSwitchChangedHandler);
chip::BindingManager::GetInstance().RegisterBoundDeviceContextReleaseHandler(LightSwitchContextReleaseHandler);
}

} // namespace

/********************************************************
* Switch functions
*********************************************************/

void SwitchWorkerFunction(intptr_t context)
{
VerifyOrReturn(context != 0, ChipLogError(NotSpecified, "SwitchWorkerFunction - Invalid work data"));

BindingCommandData * data = reinterpret_cast<BindingCommandData *>(context);
BindingManager::GetInstance().NotifyBoundClusterChanged(data->localEndpointId, data->clusterId, static_cast<void *>(data));
}

void BindingWorkerFunction(intptr_t context)
{
VerifyOrReturn(context != 0, ChipLogError(NotSpecified, "BindingWorkerFunction - Invalid work data"));

EmberBindingTableEntry * entry = reinterpret_cast<EmberBindingTableEntry *>(context);
AddBindingEntry(*entry);

Platform::Delete(entry);
}

CHIP_ERROR InitBindingHandler()
{
// The initialization of binding manager will try establishing connection with unicast peers
// so it requires the Server instance to be correctly initialized. Post the init function to
// the event queue so that everything is ready when initialization is conducted.
chip::DeviceLayer::PlatformMgr().ScheduleWork(InitBindingHandlerInternal);
return CHIP_NO_ERROR;
}
Loading

0 comments on commit 3646581

Please sign in to comment.