blob: 9be05feafe4ea6eb622f040ec29c9acd61181a19 [file] [log] [blame]
/*
*
* Copyright (c) 2021 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.h>
#include <AppShellCommands.h>
#include <BindingHandler.h>
#include <LEDWidget.h>
#include <LightSwitch.h>
#include <cycfg.h>
#include <lib/shell/Engine.h>
#include <lib/shell/commands/Help.h>
#include <platform/CHIPDeviceLayer.h>
using namespace chip;
using namespace chip::app;
using namespace chip::Shell;
using Shell::Engine;
using Shell::shell_command_t;
using Shell::streamer_get;
using Shell::streamer_printf;
static Engine AppCmdSubCommands;
static Engine AppCmdLocalSubCommands;
static Engine AppCmdOnOffSubCommands;
static Engine AppCmdGroupsSubCommands;
static Engine AppCmdGroupsOnOffSubCommands;
static Engine AppCmdDebugSubCommands;
static Engine AppCmdIdentifySubCommands;
static Engine AppCmdIdentifyReadSubCommands;
static CHIP_ERROR AppCmdHelpHandler(int argc, char ** argv)
{
AppCmdSubCommands.ForEachCommand(Shell::PrintCommandHelp, nullptr);
return CHIP_NO_ERROR;
}
static CHIP_ERROR AppCmdCommandHandler(int argc, char ** argv)
{
if (argc == 0)
{
return AppCmdHelpHandler(argc, argv);
}
return AppCmdSubCommands.ExecCommand(argc, argv);
}
namespace Local {
static CHIP_ERROR OnOffHelpHandler(int argc, char ** argv)
{
AppCmdLocalSubCommands.ForEachCommand(Shell::PrintCommandHelp, nullptr);
return CHIP_NO_ERROR;
}
static CHIP_ERROR AppCommandHandler(int argc, char ** argv)
{
if (argc == 0)
{
return OnOffHelpHandler(argc, argv);
}
return AppCmdLocalSubCommands.ExecCommand(argc, argv);
}
CHIP_ERROR OnCommandHandler(int argc, char ** argv)
{
streamer_printf(streamer_get(), "Turning the light on ...\n");
LEDWid().Set(true, PLATFORM_LED_RED);
return CHIP_NO_ERROR;
}
CHIP_ERROR OffCommandHandler(int argc, char ** argv)
{
streamer_printf(streamer_get(), "Turning the light off ...\n");
LEDWid().Set(false, PLATFORM_LED_RED);
return CHIP_NO_ERROR;
}
CHIP_ERROR ToggleCommandHandler(int argc, char ** argv)
{
streamer_printf(streamer_get(), "Toggling the light ...\n");
if (LEDWid().IsLEDOn())
{
LEDWid().Set(false, PLATFORM_LED_RED);
}
else
{
LEDWid().Set(true, PLATFORM_LED_RED);
}
return CHIP_NO_ERROR;
}
} // namespace Local
CHIP_ERROR AssignUnicastData(LightSwitch::Status mStatus)
{
BindingHandler::BindingData * data = Platform::New<BindingHandler::BindingData>();
data->EndpointId = LightSwitch::GetInstance().GetLightSwitchEndpointId();
switch (mStatus)
{
case LightSwitch::Status::Toggle:
data->CommandId = Clusters::OnOff::Commands::Toggle::Id;
break;
case LightSwitch::Status::On:
data->CommandId = Clusters::OnOff::Commands::On::Id;
break;
case LightSwitch::Status::Off:
data->CommandId = Clusters::OnOff::Commands::Off::Id;
break;
default:
data->CommandId = Clusters::OnOff::Commands::Off::Id;
printf("[unicast] default -> Clusters::OnOff::Commands::Off\n");
break;
}
data->ClusterId = Clusters::OnOff::Id;
DeviceLayer::PlatformMgr().ScheduleWork(BindingHandler::SwitchWorkerHandler, reinterpret_cast<intptr_t>(data));
return CHIP_NO_ERROR;
}
namespace Unicast {
static CHIP_ERROR OnOffHelpHandler(int argc, char ** argv)
{
AppCmdOnOffSubCommands.ForEachCommand(Shell::PrintCommandHelp, nullptr);
return CHIP_NO_ERROR;
}
static CHIP_ERROR AppCommandHandler(int argc, char ** argv)
{
if (argc == 0)
{
return OnOffHelpHandler(argc, argv);
}
return AppCmdOnOffSubCommands.ExecCommand(argc, argv);
}
CHIP_ERROR OnCommandHandler(int argc, char ** argv)
{
return AssignUnicastData(LightSwitch::Status::On);
}
CHIP_ERROR OffCommandHandler(int argc, char ** argv)
{
return AssignUnicastData(LightSwitch::Status::Off);
}
CHIP_ERROR ToggleCommandHandler(int argc, char ** argv)
{
return AssignUnicastData(LightSwitch::Status::Toggle);
}
} // namespace Unicast
CHIP_ERROR AssignGroupData(LightSwitch::Status mStatus)
{
BindingHandler::BindingData * data = Platform::New<BindingHandler::BindingData>();
data->EndpointId = LightSwitch::GetInstance().GetLightSwitchEndpointId();
switch (mStatus)
{
case LightSwitch::Status::Toggle:
data->CommandId = Clusters::OnOff::Commands::Toggle::Id;
break;
case LightSwitch::Status::On:
data->CommandId = Clusters::OnOff::Commands::On::Id;
break;
case LightSwitch::Status::Off:
data->CommandId = Clusters::OnOff::Commands::Off::Id;
break;
default:
data->CommandId = Clusters::OnOff::Commands::Off::Id;
printf("[group] default -> Clusters::OnOff::Commands::Off\n");
break;
}
data->ClusterId = Clusters::OnOff::Id;
data->IsGroup = true;
DeviceLayer::PlatformMgr().ScheduleWork(BindingHandler::SwitchWorkerHandler, reinterpret_cast<intptr_t>(data));
return CHIP_NO_ERROR;
}
namespace Group {
static CHIP_ERROR AppSwitchHelpHandler(int argc, char ** argv)
{
AppCmdGroupsSubCommands.ForEachCommand(Shell::PrintCommandHelp, nullptr);
return CHIP_NO_ERROR;
}
static CHIP_ERROR AppCommandHandler(int argc, char ** argv)
{
if (argc == 0)
{
return AppSwitchHelpHandler(argc, argv);
}
return AppCmdGroupsSubCommands.ExecCommand(argc, argv);
}
static CHIP_ERROR OnOffHelpHandler(int argc, char ** argv)
{
AppCmdGroupsOnOffSubCommands.ForEachCommand(Shell::PrintCommandHelp, nullptr);
return CHIP_NO_ERROR;
}
static CHIP_ERROR OnOffCommandHandler(int argc, char ** argv)
{
if (argc == 0)
{
return OnOffHelpHandler(argc, argv);
}
return AppCmdGroupsOnOffSubCommands.ExecCommand(argc, argv);
}
CHIP_ERROR OnCommandHandler(int argc, char ** argv)
{
return AssignGroupData(LightSwitch::Status::On);
}
CHIP_ERROR OffCommandHandler(int argc, char ** argv)
{
return AssignGroupData(LightSwitch::Status::Off);
}
CHIP_ERROR ToggleCommandHandler(int argc, char ** argv)
{
return AssignGroupData(LightSwitch::Status::Toggle);
}
} // namespace Group
namespace Identify {
CHIP_ERROR IdentifyHelpHandler(int argc, char ** argv)
{
AppCmdIdentifySubCommands.ForEachCommand(Shell::PrintCommandHelp, nullptr);
return CHIP_NO_ERROR;
}
CHIP_ERROR AppCommandHandler(int argc, char ** argv)
{
if (argc == 0)
{
return IdentifyHelpHandler(argc, argv);
}
return AppCmdIdentifySubCommands.ExecCommand(argc, argv);
}
CHIP_ERROR ReadHelpHandler(int argc, char ** argv)
{
AppCmdIdentifyReadSubCommands.ForEachCommand(Shell::PrintCommandHelp, nullptr);
return CHIP_NO_ERROR;
}
CHIP_ERROR Read(int argc, char ** argv)
{
if (argc == 0)
{
return ReadHelpHandler(argc, argv);
}
return AppCmdIdentifyReadSubCommands.ExecCommand(argc, argv);
}
CHIP_ERROR ReadAttributeList(int argc, char ** argv)
{
BindingHandler::BindingData * data = Platform::New<BindingHandler::BindingData>();
data->attributeId = Clusters::Identify::Attributes::AttributeList::Id;
data->ClusterId = Clusters::Identify::Id;
data->isReadAttribute = true;
DeviceLayer::PlatformMgr().ScheduleWork(BindingHandler::SwitchWorkerHandler, reinterpret_cast<intptr_t>(data));
return CHIP_NO_ERROR;
}
CHIP_ERROR ReadFeatureMap(int argc, char ** argv)
{
BindingHandler::BindingData * data = Platform::New<BindingHandler::BindingData>();
data->attributeId = Clusters::Identify::Attributes::FeatureMap::Id;
data->ClusterId = Clusters::Identify::Id;
data->isReadAttribute = true;
DeviceLayer::PlatformMgr().ScheduleWork(BindingHandler::SwitchWorkerHandler, reinterpret_cast<intptr_t>(data));
return CHIP_NO_ERROR;
}
} // namespace Identify
namespace Debug {
static CHIP_ERROR DebugHelpHandler(int argc, char ** argv)
{
AppCmdDebugSubCommands.ForEachCommand(Shell::PrintCommandHelp, nullptr);
return CHIP_NO_ERROR;
}
static CHIP_ERROR AppCommandHandler(int argc, char ** argv)
{
if (argc == 0)
{
return DebugHelpHandler(argc, argv);
}
return AppCmdDebugSubCommands.ExecCommand(argc, argv);
}
CHIP_ERROR StartBLEAdvertisingDebugCommandHandler(int argc, char * argv[])
{
CHIP_ERROR err = CHIP_NO_ERROR;
if ((argc > 0) && (strcmp(argv[0], "start") == 0))
{
printf("Start BLE advertising ...\n");
err = StartBLEAdvertisingHandler();
}
else if ((argc > 0) && (strcmp(argv[0], "stop") == 0))
{
printf("Stop BLE advertising ...\n");
err = StopBLEAdvertisingHandler();
}
else
{
return CHIP_ERROR_INVALID_ARGUMENT;
}
return err;
}
static CHIP_ERROR TableDebugCommandHandler(int argc, char ** argv)
{
BindingHandler::GetInstance().PrintBindingTable();
return CHIP_NO_ERROR;
}
/*
* Usage: switch debug bind_group [fabric index] [group id] [cluster id]
*/
CHIP_ERROR GroupBindCommandHandler(int argc, char ** argv)
{
VerifyOrReturnError(argc == 3, CHIP_ERROR_INVALID_ARGUMENT);
EmberBindingTableEntry * entry = Platform::New<EmberBindingTableEntry>();
entry->type = MATTER_MULTICAST_BINDING;
entry->local = 1; // Hardcoded to endpoint 1 for now
entry->fabricIndex = atoi(argv[0]);
entry->groupId = atoi(argv[1]);
entry->clusterId.emplace(atoi(argv[3]));
DeviceLayer::PlatformMgr().ScheduleWork(BindingHandler::BindingWorkerHandler, reinterpret_cast<intptr_t>(entry));
return CHIP_NO_ERROR;
}
/*
* Usage: switch debug bind_unicast [fabric index] [node id] [endpoint] [cluster id]
*/
CHIP_ERROR UnicastBindCommandHandler(int argc, char ** argv)
{
VerifyOrReturnError(argc == 4, CHIP_ERROR_INVALID_ARGUMENT);
EmberBindingTableEntry * entry = Platform::New<EmberBindingTableEntry>();
entry->type = MATTER_UNICAST_BINDING;
entry->local = 1; // Hardcoded to endpoint 1 for now
entry->fabricIndex = atoi(argv[0]);
entry->nodeId = atoi(argv[1]);
entry->remote = atoi(argv[2]);
entry->clusterId.emplace(atoi(argv[3]));
DeviceLayer::PlatformMgr().ScheduleWork(BindingHandler::BindingWorkerHandler, reinterpret_cast<intptr_t>(entry));
return CHIP_NO_ERROR;
}
/*
* Usage: switch debug brightness [brightness value]
*/
CHIP_ERROR ChangeBrightnessCommandHandler(int argc, char ** argv)
{
LightSwitch::GetInstance().DimmerChangeBrightness(atoi(argv[0]));
return CHIP_NO_ERROR;
}
} // namespace Debug
void RegisterAppShellCommands()
{
static const shell_command_t ifxAppCmdSubCommands[] = {
{ &AppCmdHelpHandler, "help", "Switch commands" },
{ &Local::AppCommandHandler, "local", "Light-switch on/off local device." },
{ &Unicast::AppCommandHandler, "onoff", "Lightbulb on/off remote device by unicast." },
{ &Group::AppCommandHandler, "groups", "Lightbulb on/off remote device by group." },
{ &Debug::AppCommandHandler, "debug", "Extend the debug command." },
{ &Identify::AppCommandHandler, "identify", "identify read attribute" },
};
static const shell_command_t ifxAppCmdLocalSubCommands[] = { { &Local::OnOffHelpHandler, "help",
"Usage: switch local [on|off|toggle]" },
{ &Local::OnCommandHandler, "on", "Make light on" },
{ &Local::OffCommandHandler, "off", "Make light off" },
{ &Local::ToggleCommandHandler, "toggle", "Toggle the light" } };
static const shell_command_t ifxAppCmdOnOffSubCommands[] = {
{ &Unicast::OnOffHelpHandler, "help", "Usage: switch onoff [on|off|toggle]" },
{ &Unicast::OnCommandHandler, "on", "Sends on command to bound Lightbulb" },
{ &Unicast::OffCommandHandler, "off", "Sends off command to bound Lightbulb" },
{ &Unicast::ToggleCommandHandler, "toggle", "Sends toggle command to bound Lightbulb" },
};
static const shell_command_t ifxAppCmdGroupsSubCommands[] = {
{ &Group::AppSwitchHelpHandler, "help", "Switch a group of bounded Lightbulbs" },
{ &Group::OnOffCommandHandler, "onoff", "Usage: switch groups onoff [on|off|toggle]" },
};
static const shell_command_t ifxAppCmdGroupsOnOffSubCommands[] = {
{ &Group::OnOffHelpHandler, "help", "Usage: switch groups onoff [on|off|toggle]" },
{ &Group::OnCommandHandler, "on", "Sends on command to bound Group" },
{ &Group::OffCommandHandler, "off", "Sends off command to bound Group" },
{ &Group::ToggleCommandHandler, "toggle", "Sends toggle command to bound Group" },
};
static const shell_command_t ifxAppCmdDebugSubCommands[] = {
{ &Debug::DebugHelpHandler, "help", "Debug use commands " },
{ &Debug::StartBLEAdvertisingDebugCommandHandler, "bleadv", "Usage: switch debug bleadv [start|stop]" },
{ &Debug::TableDebugCommandHandler, "table", "Print a binding table. Usage: switch debug table" },
{ &Debug::GroupBindCommandHandler, "bind_group", "Usage: switch debug bind_group [fabric index] [group id] [cluster id]" },
{ &Debug::UnicastBindCommandHandler, "bind_unicast",
"Usage: switch debug bind_unicast [fabric index] [node id] [endpoint] [cluster id]" },
{ &Debug::ChangeBrightnessCommandHandler, "brightness",
"Change the brightness and range is 0-254. Usage: switch debug brightness [brightness value]" },
};
static const shell_command_t ifxAppCmdIdentifySubCommands[] = {
{ &Identify::Read, "read", "Usage: switch identify read <attribute>" },
};
static const shell_command_t ifxAppCmdIdentifyReadSubCommands[] = {
{ &Identify::ReadHelpHandler, "help", "Usage: switch identify read <attribute>" },
{ &Identify::ReadAttributeList, "attlist", "attribute list attribute" },
{ &Identify::ReadFeatureMap, "featureMap", "featureMap attribute" },
};
static const shell_command_t AppLightSwitchCommand = {
&AppCmdCommandHandler, "switch", "Light switch commands. Usage: switch [local|onoff|groups|debug][identify]"
};
AppCmdSubCommands.RegisterCommands(ifxAppCmdSubCommands, ArraySize(ifxAppCmdSubCommands));
AppCmdLocalSubCommands.RegisterCommands(ifxAppCmdLocalSubCommands, ArraySize(ifxAppCmdLocalSubCommands));
AppCmdOnOffSubCommands.RegisterCommands(ifxAppCmdOnOffSubCommands, ArraySize(ifxAppCmdOnOffSubCommands));
AppCmdGroupsSubCommands.RegisterCommands(ifxAppCmdGroupsSubCommands, ArraySize(ifxAppCmdGroupsSubCommands));
AppCmdGroupsOnOffSubCommands.RegisterCommands(ifxAppCmdGroupsOnOffSubCommands, ArraySize(ifxAppCmdGroupsOnOffSubCommands));
AppCmdDebugSubCommands.RegisterCommands(ifxAppCmdDebugSubCommands, ArraySize(ifxAppCmdDebugSubCommands));
AppCmdIdentifySubCommands.RegisterCommands(ifxAppCmdIdentifySubCommands, ArraySize(ifxAppCmdIdentifySubCommands));
AppCmdIdentifyReadSubCommands.RegisterCommands(ifxAppCmdIdentifyReadSubCommands, ArraySize(ifxAppCmdIdentifyReadSubCommands));
Engine::Root().RegisterCommands(&AppLightSwitchCommand, 1);
}