Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Silabs] Add generic witch support to light-switch example #24642

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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