Skip to content

Commit 48c60d5

Browse files
[Silabs] Add generic witch support to light-switch example (#24642)
* Add generic witch support to light-switch example * restyle * move shell init to light-switch-mgr --------- Co-authored-by: Andrei Litvin <andy314@gmail.com>
1 parent cdaa392 commit 48c60d5

11 files changed

+484
-650
lines changed

examples/light-switch-app/silabs/SiWx917/BUILD.gn

+9-1
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,7 @@ efr32_sdk("sdk") {
147147
]
148148

149149
include_dirs = [
150+
"${chip_root}/examples/light-switch-app/silabs/common",
150151
"${chip_root}/src/platform/silabs/SiWx917",
151152
"${efr32_project_dir}/include",
152153
"${examples_plat_dir}",
@@ -200,14 +201,15 @@ efr32_executable("light_switch_app") {
200201
defines = []
201202

202203
sources = [
204+
"${chip_root}/examples/light-switch-app/silabs/common/BindingHandler.cpp",
205+
"${chip_root}/examples/light-switch-app/silabs/common/LightSwitchMgr.cpp",
203206
"${examples_common_plat_dir}/heap_4_silabs.c",
204207
"${examples_plat_dir}/BaseApplication.cpp",
205208
"${examples_plat_dir}/init_ccpPlatform.cpp",
206209
"${examples_plat_dir}/matter_config.cpp",
207210
"${examples_plat_dir}/siwx917_utils.cpp",
208211
"src/AppTask.cpp",
209212
"src/ZclCallbacks.cpp",
210-
"src/binding-handler.cpp",
211213
"src/main.cpp",
212214
]
213215

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

233+
if (chip_build_libshell) {
234+
sources += [
235+
"${chip_root}/examples/light-switch-app/silabs/common/ShellCommands.cpp",
236+
]
237+
}
238+
231239
# Attestation Credentials
232240
if (chip_build_platform_attestation_credentials_provider) {
233241
deps += [ "${examples_plat_dir}:siwx917-attestation-credentials" ]

examples/light-switch-app/silabs/SiWx917/src/AppTask.cpp

+35-25
Original file line numberDiff line numberDiff line change
@@ -24,19 +24,25 @@
2424
#include "AppTask.h"
2525
#include "AppConfig.h"
2626
#include "AppEvent.h"
27-
#include "binding-handler.h"
27+
#include "BindingHandler.h"
2828

2929
#ifdef ENABLE_WSTK_LEDS
3030
#include "LEDWidget.h"
3131
#endif // ENABLE_WSTK_LEDS
3232

33+
#include "LightSwitchMgr.h"
34+
3335
#ifdef DISPLAY_ENABLED
3436
#include "lcd.h"
3537
#ifdef QR_CODE_ENABLED
3638
#include "qrcodegen.h"
3739
#endif // QR_CODE_ENABLED
3840
#endif // DISPLAY_ENABLED
3941

42+
#if defined(ENABLE_CHIP_SHELL)
43+
#include "ShellCommands.h"
44+
#endif // defined(ENABLE_CHIP_SHELL)
45+
4046
#include <app-common/zap-generated/attribute-id.h>
4147
#include <app-common/zap-generated/attribute-type.h>
4248
#include <app/server/OnboardingCodesUtil.h>
@@ -59,6 +65,13 @@
5965
#define APP_FUNCTION_BUTTON &sl_button_btn0
6066
#define APP_LIGHT_SWITCH &sl_button_btn1
6167

68+
namespace {
69+
70+
constexpr chip::EndpointId kLightSwitchEndpoint = 1;
71+
constexpr chip::EndpointId kGenericSwitchEndpoint = 2;
72+
73+
} // namespace
74+
6275
using namespace chip;
6376
using namespace ::chip::DeviceLayer;
6477

@@ -70,8 +83,6 @@ namespace {
7083

7184
EmberAfIdentifyEffectIdentifier sIdentifyEffect = EMBER_ZCL_IDENTIFY_EFFECT_IDENTIFIER_STOP_EFFECT;
7285

73-
bool mCurrentButtonState = false;
74-
7586
/**********************************************************
7687
* Identify Callbacks
7788
*********************************************************/
@@ -159,14 +170,17 @@ CHIP_ERROR AppTask::Init()
159170
appError(err);
160171
}
161172

162-
// Configure Bindings - TODO ERROR PROCESSING
163-
err = InitBindingHandler();
173+
err = LightSwitchMgr::GetInstance().Init(kLightSwitchEndpoint, kGenericSwitchEndpoint);
164174
if (err != CHIP_NO_ERROR)
165175
{
166-
SILABS_LOG("InitBindingHandler() failed");
176+
SILABS_LOG("LightSwitchMgr Init failed!");
167177
appError(err);
168178
}
169179

180+
#if defined(ENABLE_CHIP_SHELL)
181+
LightSwtichCommands::RegisterSwitchCommands();
182+
#endif // defined(ENABLE_CHIP_SHELL)
183+
170184
return err;
171185
}
172186

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

224238
void AppTask::SwitchActionEventHandler(AppEvent * aEvent)
225239
{
226-
if (aEvent->Type == AppEvent::kEventType_Button)
240+
VerifyOrReturn(aEvent->Type == AppEvent::kEventType_Button);
241+
242+
static bool mCurrentButtonState = false;
243+
244+
if (aEvent->ButtonEvent.Action == SL_SIMPLE_BUTTON_PRESSED)
227245
{
228-
BindingCommandData * data = Platform::New<BindingCommandData>();
229-
data->clusterId = chip::app::Clusters::OnOff::Id;
246+
mCurrentButtonState = !mCurrentButtonState;
247+
LightSwitchMgr::LightSwitchAction action =
248+
mCurrentButtonState ? LightSwitchMgr::LightSwitchAction::On : LightSwitchMgr::LightSwitchAction::Off;
230249

231-
if (mCurrentButtonState)
232-
{
233-
mCurrentButtonState = false;
234-
data->commandId = chip::app::Clusters::OnOff::Commands::Off::Id;
235-
}
236-
else
237-
{
238-
data->commandId = chip::app::Clusters::OnOff::Commands::On::Id;
239-
mCurrentButtonState = true;
240-
}
250+
LightSwitchMgr::GetInstance().TriggerLightSwitchAction(action);
251+
LightSwitchMgr::GetInstance().GenericSwitchOnInitialPress();
241252

242253
#ifdef DISPLAY_ENABLED
243254
sAppTask.GetLCD().WriteDemoUI(mCurrentButtonState);
244255
#endif
245-
246-
DeviceLayer::PlatformMgr().ScheduleWork(SwitchWorkerFunction, reinterpret_cast<intptr_t>(data));
256+
}
257+
else if (aEvent->ButtonEvent.Action == SL_SIMPLE_BUTTON_RELEASED)
258+
{
259+
LightSwitchMgr::GetInstance().GenericSwitchOnShortRelease();
247260
}
248261
}
249262

250263
void AppTask::ButtonEventHandler(const sl_button_t * buttonHandle, uint8_t btnAction)
251264
{
252-
if (buttonHandle == NULL)
253-
{
254-
return;
255-
}
265+
VerifyOrReturn(buttonHandle != NULL);
256266

257267
AppEvent button_event = {};
258268
button_event.Type = AppEvent::kEventType_Button;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
/*
2+
*
3+
* Copyright (c) 2020 Project CHIP Authors
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
#include "BindingHandler.h"
19+
20+
#include "AppConfig.h"
21+
#include "app/CommandSender.h"
22+
#include "app/clusters/bindings/BindingManager.h"
23+
#include "app/server/Server.h"
24+
#include "controller/InvokeInteraction.h"
25+
#include "platform/CHIPDeviceLayer.h"
26+
#include <app/clusters/bindings/bindings.h>
27+
#include <lib/support/CodeUtils.h>
28+
29+
using namespace chip;
30+
using namespace chip::app;
31+
32+
namespace {
33+
34+
void ProcessOnOffUnicastBindingCommand(CommandId commandId, const EmberBindingTableEntry & binding,
35+
Messaging::ExchangeManager * exchangeMgr, const SessionHandle & sessionHandle)
36+
{
37+
auto onSuccess = [](const ConcreteCommandPath & commandPath, const StatusIB & status, const auto & dataResponse) {
38+
ChipLogProgress(NotSpecified, "OnOff command succeeds");
39+
};
40+
41+
auto onFailure = [](CHIP_ERROR error) {
42+
ChipLogError(NotSpecified, "OnOff command failed: %" CHIP_ERROR_FORMAT, error.Format());
43+
};
44+
45+
switch (commandId)
46+
{
47+
case Clusters::OnOff::Commands::Toggle::Id:
48+
Clusters::OnOff::Commands::Toggle::Type toggleCommand;
49+
Controller::InvokeCommandRequest(exchangeMgr, sessionHandle, binding.remote, toggleCommand, onSuccess, onFailure);
50+
break;
51+
52+
case Clusters::OnOff::Commands::On::Id:
53+
Clusters::OnOff::Commands::On::Type onCommand;
54+
Controller::InvokeCommandRequest(exchangeMgr, sessionHandle, binding.remote, onCommand, onSuccess, onFailure);
55+
break;
56+
57+
case Clusters::OnOff::Commands::Off::Id:
58+
Clusters::OnOff::Commands::Off::Type offCommand;
59+
Controller::InvokeCommandRequest(exchangeMgr, sessionHandle, binding.remote, offCommand, onSuccess, onFailure);
60+
break;
61+
}
62+
}
63+
64+
void ProcessOnOffGroupBindingCommand(CommandId commandId, const EmberBindingTableEntry & binding)
65+
{
66+
Messaging::ExchangeManager & exchangeMgr = Server::GetInstance().GetExchangeManager();
67+
68+
switch (commandId)
69+
{
70+
case Clusters::OnOff::Commands::Toggle::Id:
71+
Clusters::OnOff::Commands::Toggle::Type toggleCommand;
72+
Controller::InvokeGroupCommandRequest(&exchangeMgr, binding.fabricIndex, binding.groupId, toggleCommand);
73+
break;
74+
75+
case Clusters::OnOff::Commands::On::Id:
76+
Clusters::OnOff::Commands::On::Type onCommand;
77+
Controller::InvokeGroupCommandRequest(&exchangeMgr, binding.fabricIndex, binding.groupId, onCommand);
78+
79+
break;
80+
81+
case Clusters::OnOff::Commands::Off::Id:
82+
Clusters::OnOff::Commands::Off::Type offCommand;
83+
Controller::InvokeGroupCommandRequest(&exchangeMgr, binding.fabricIndex, binding.groupId, offCommand);
84+
break;
85+
}
86+
}
87+
88+
void LightSwitchChangedHandler(const EmberBindingTableEntry & binding, OperationalDeviceProxy * peer_device, void * context)
89+
{
90+
VerifyOrReturn(context != nullptr, ChipLogError(NotSpecified, "OnDeviceConnectedFn: context is null"));
91+
BindingCommandData * data = static_cast<BindingCommandData *>(context);
92+
93+
if (binding.type == EMBER_MULTICAST_BINDING && data->isGroup)
94+
{
95+
switch (data->clusterId)
96+
{
97+
case Clusters::OnOff::Id:
98+
ProcessOnOffGroupBindingCommand(data->commandId, binding);
99+
break;
100+
}
101+
}
102+
else if (binding.type == EMBER_UNICAST_BINDING && !data->isGroup)
103+
{
104+
switch (data->clusterId)
105+
{
106+
case Clusters::OnOff::Id:
107+
VerifyOrDie(peer_device != nullptr && peer_device->ConnectionReady());
108+
ProcessOnOffUnicastBindingCommand(data->commandId, binding, peer_device->GetExchangeManager(),
109+
peer_device->GetSecureSession().Value());
110+
break;
111+
}
112+
}
113+
}
114+
115+
void LightSwitchContextReleaseHandler(void * context)
116+
{
117+
VerifyOrReturn(context != nullptr, ChipLogError(NotSpecified, "LightSwitchContextReleaseHandler: context is null"));
118+
Platform::Delete(static_cast<BindingCommandData *>(context));
119+
}
120+
121+
void InitBindingHandlerInternal(intptr_t arg)
122+
{
123+
auto & server = chip::Server::GetInstance();
124+
chip::BindingManager::GetInstance().Init(
125+
{ &server.GetFabricTable(), server.GetCASESessionManager(), &server.GetPersistentStorage() });
126+
chip::BindingManager::GetInstance().RegisterBoundDeviceChangedHandler(LightSwitchChangedHandler);
127+
chip::BindingManager::GetInstance().RegisterBoundDeviceContextReleaseHandler(LightSwitchContextReleaseHandler);
128+
}
129+
130+
} // namespace
131+
132+
/********************************************************
133+
* Switch functions
134+
*********************************************************/
135+
136+
void SwitchWorkerFunction(intptr_t context)
137+
{
138+
VerifyOrReturn(context != 0, ChipLogError(NotSpecified, "SwitchWorkerFunction - Invalid work data"));
139+
140+
BindingCommandData * data = reinterpret_cast<BindingCommandData *>(context);
141+
BindingManager::GetInstance().NotifyBoundClusterChanged(data->localEndpointId, data->clusterId, static_cast<void *>(data));
142+
}
143+
144+
void BindingWorkerFunction(intptr_t context)
145+
{
146+
VerifyOrReturn(context != 0, ChipLogError(NotSpecified, "BindingWorkerFunction - Invalid work data"));
147+
148+
EmberBindingTableEntry * entry = reinterpret_cast<EmberBindingTableEntry *>(context);
149+
AddBindingEntry(*entry);
150+
151+
Platform::Delete(entry);
152+
}
153+
154+
CHIP_ERROR InitBindingHandler()
155+
{
156+
// The initialization of binding manager will try establishing connection with unicast peers
157+
// so it requires the Server instance to be correctly initialized. Post the init function to
158+
// the event queue so that everything is ready when initialization is conducted.
159+
chip::DeviceLayer::PlatformMgr().ScheduleWork(InitBindingHandlerInternal);
160+
return CHIP_NO_ERROR;
161+
}

0 commit comments

Comments
 (0)