Skip to content

Commit

Permalink
Update examples/placeholder to supports an interactive websocket mode (
Browse files Browse the repository at this point in the history
  • Loading branch information
vivien-apple authored and pull[bot] committed Nov 28, 2023
1 parent 6a45c94 commit 3586877
Show file tree
Hide file tree
Showing 7 changed files with 239 additions and 1 deletion.
26 changes: 26 additions & 0 deletions examples/placeholder/linux/AppOptions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,12 @@ using chip::ArgParser::OptionSet;
using chip::ArgParser::PrintArgError;

constexpr uint16_t kOptionDacProviderFilePath = 0xFF01;
constexpr uint16_t kOptionInteractiveMode = 0xFF02;
constexpr uint16_t kOptionInteractiveModePort = 0xFF03;

static chip::Credentials::Examples::TestHarnessDACProvider mDacProvider;
static bool gInteractiveMode = false;
static chip::Optional<uint16_t> gInteractiveModePort;

bool AppOptions::HandleOptions(const char * program, OptionSet * options, int identifier, const char * name, const char * value)
{
Expand All @@ -34,6 +38,12 @@ bool AppOptions::HandleOptions(const char * program, OptionSet * options, int id
case kOptionDacProviderFilePath:
mDacProvider.Init(value);
break;
case kOptionInteractiveMode:
gInteractiveMode = true;
break;
case kOptionInteractiveModePort:
gInteractiveModePort = chip::MakeOptional(static_cast<uint16_t>(atoi(value)));
break;
default:
PrintArgError("%s: INTERNAL ERROR: Unhandled option: %s\n", program, name);
retval = false;
Expand All @@ -47,13 +57,19 @@ OptionSet * AppOptions::GetOptions()
{
static OptionDef optionsDef[] = {
{ "dac_provider", chip::ArgParser::kArgumentRequired, kOptionDacProviderFilePath },
{ "interactive", chip::ArgParser::kNoArgument, kOptionInteractiveMode },
{ "port", chip::ArgParser::kArgumentRequired, kOptionInteractiveModePort },
{},
};

static OptionSet options = {
AppOptions::HandleOptions, optionsDef, "PROGRAM OPTIONS",
" --dac_provider <filepath>\n"
" A json file with data used by the example dac provider to validate device attestation procedure.\n"
" --interactive\n"
" Enable server interactive mode.\n"
" --port <port>\n"
" Specify the listening port for the server interactive mode.\n"
};

return &options;
Expand All @@ -63,3 +79,13 @@ chip::Credentials::DeviceAttestationCredentialsProvider * AppOptions::GetDACProv
{
return &mDacProvider;
}

bool AppOptions::GetInteractiveMode()
{
return gInteractiveMode;
}

chip::Optional<uint16_t> AppOptions::GetInteractiveModePort()
{
return gInteractiveModePort;
}
2 changes: 2 additions & 0 deletions examples/placeholder/linux/AppOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ class AppOptions
public:
static chip::ArgParser::OptionSet * GetOptions();
static chip::Credentials::DeviceAttestationCredentialsProvider * GetDACProvider();
static bool GetInteractiveMode();
static chip::Optional<uint16_t> GetInteractiveModePort();

private:
static bool HandleOptions(const char * program, chip::ArgParser::OptionSet * options, int identifier, const char * name,
Expand Down
6 changes: 5 additions & 1 deletion examples/placeholder/linux/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -31,20 +31,23 @@ chip_data_model("configuration") {
config("includes") {
include_dirs = [
".",
"${chip_root}/examples/common",
"include",
]
}

executable("chip-${chip_tests_zap_config}") {
sources = [
"AppOptions.cpp",
"InteractiveServer.cpp",
"main.cpp",
"src/bridged-actions-stub.cpp",
"static-supported-modes-manager.cpp",
]

deps = [
":configuration",
"${chip_root}/examples/common/websocket-server",
"${chip_root}/examples/platform/linux:app-main",
"${chip_root}/src/app/tests/suites/commands/delay",
"${chip_root}/src/app/tests/suites/commands/discovery",
Expand All @@ -54,9 +57,10 @@ executable("chip-${chip_tests_zap_config}") {
"${chip_root}/src/lib",
"${chip_root}/src/lib/support:testing", # For sleepMillis. TODO: this is
# odd and should be fixed
"${chip_root}/third_party/jsoncpp",
]

include_dirs = [ "include" ]
public_configs = [ ":includes" ]

cflags = [ "-Wconversion" ]

Expand Down
145 changes: 145 additions & 0 deletions examples/placeholder/linux/InteractiveServer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
/*
*
* Copyright (c) 2023 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 "InteractiveServer.h"

#include <json/json.h>
#include <platform/CHIPDeviceLayer.h>

using namespace chip::DeviceLayer;

namespace {
constexpr const char * kClusterIdKey = "clusterId";
constexpr const char * kEndpointIdKey = "endpointId";
constexpr const char * kAttributeIdKey = "attributeId";
constexpr const char * kWaitTypeKey = "waitType";
constexpr const char * kAttributeWriteKey = "writeAttribute";
constexpr const char * kAttributeReadKey = "readAttribute";
constexpr const char * kCommandIdKey = "commandId";
constexpr const char * kWaitForCommissioningCommand = "WaitForCommissioning";

std::string JsonToString(Json::Value & json)
{
Json::FastWriter writer;
writer.omitEndingLineFeed();
return writer.write(json);
}

void OnPlatformEvent(const ChipDeviceEvent * event, intptr_t arg);

void OnCommissioningComplete(intptr_t context)
{
PlatformMgr().RemoveEventHandler(OnPlatformEvent);
InteractiveServer::GetInstance().CommissioningComplete();
}

void OnPlatformEvent(const ChipDeviceEvent * event, intptr_t arg)
{
switch (event->Type)
{
case DeviceEventType::kCommissioningComplete:
PlatformMgr().ScheduleWork(OnCommissioningComplete, arg);
break;
}
}
} // namespace

InteractiveServer * InteractiveServer::instance = nullptr;
InteractiveServer & InteractiveServer::GetInstance()
{
if (instance == nullptr)
{
instance = new InteractiveServer();
}
return *instance;
}

void InteractiveServer::Run(const chip::Optional<uint16_t> port)
{
mIsReady = false;
wsThread = std::thread(&WebSocketServer::Run, &mWebSocketServer, port, this);
}

bool InteractiveServer::OnWebSocketMessageReceived(char * msg)
{
ChipLogError(chipTool, "Receive message: %s", msg);
if (strcmp(msg, kWaitForCommissioningCommand) == 0)
{
mIsReady = false;
PlatformMgr().AddEventHandler(OnPlatformEvent);
}
else
{
mIsReady = true;
}
return true;
}

bool InteractiveServer::Command(const chip::app::ConcreteCommandPath & path)
{
VerifyOrReturnValue(mIsReady, false);

Json::Value value;
value[kClusterIdKey] = path.mClusterId;
value[kEndpointIdKey] = path.mEndpointId;
value[kCommandIdKey] = path.mCommandId;

auto valueStr = JsonToString(value);
LogErrorOnFailure(mWebSocketServer.Send(valueStr.c_str()));
return mIsReady;
}

bool InteractiveServer::ReadAttribute(const chip::app::ConcreteAttributePath & path)
{
VerifyOrReturnValue(mIsReady, false);

Json::Value value;
value[kClusterIdKey] = path.mClusterId;
value[kEndpointIdKey] = path.mEndpointId;
value[kAttributeIdKey] = path.mAttributeId;
value[kWaitTypeKey] = kAttributeReadKey;

auto valueStr = JsonToString(value);
LogErrorOnFailure(mWebSocketServer.Send(valueStr.c_str()));
return mIsReady;
}

bool InteractiveServer::WriteAttribute(const chip::app::ConcreteAttributePath & path)
{
VerifyOrReturnValue(mIsReady, false);

Json::Value value;
value[kClusterIdKey] = path.mClusterId;
value[kEndpointIdKey] = path.mEndpointId;
value[kAttributeIdKey] = path.mAttributeId;
value[kWaitTypeKey] = kAttributeWriteKey;

auto valueStr = JsonToString(value);
LogErrorOnFailure(mWebSocketServer.Send(valueStr.c_str()));
return mIsReady;
}

void InteractiveServer::CommissioningComplete()
{
VerifyOrReturn(!mIsReady);
mIsReady = true;

Json::Value value = Json::objectValue;
auto valueStr = JsonToString(value);
LogErrorOnFailure(mWebSocketServer.Send(valueStr.c_str()));
}
47 changes: 47 additions & 0 deletions examples/placeholder/linux/include/InteractiveServer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
*
* Copyright (c) 2023 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/ConcreteAttributePath.h>
#include <app/ConcreteCommandPath.h>
#include <thread>
#include <websocket-server/WebSocketServer.h>

class InteractiveServer : public WebSocketServerDelegate
{
public:
static InteractiveServer & GetInstance();
void Run(const chip::Optional<uint16_t> port);

bool Command(const chip::app::ConcreteCommandPath & path);
bool ReadAttribute(const chip::app::ConcreteAttributePath & path);
bool WriteAttribute(const chip::app::ConcreteAttributePath & path);
void CommissioningComplete();

/////////// WebSocketServerDelegate Interface /////////
bool OnWebSocketMessageReceived(char * msg) override;

private:
InteractiveServer(){};
static InteractiveServer * instance;

WebSocketServer mWebSocketServer;
std::thread wsThread;
bool mIsReady;
};
7 changes: 7 additions & 0 deletions examples/placeholder/linux/include/MatterCallbacks.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

#pragma once

#include "InteractiveServer.h"
#include "Options.h"

#include <app/ConcreteAttributePath.h>
Expand Down Expand Up @@ -55,6 +56,8 @@ TestCommand * GetTargetTest()
void MatterPostCommandReceivedCallback(const chip::app::ConcreteCommandPath & commandPath,
const chip::Access::SubjectDescriptor & subjectDescriptor)
{
VerifyOrReturn(!InteractiveServer::GetInstance().Command(commandPath));

auto test = GetTargetTest();
VerifyOrReturn(test != nullptr && test->isRunning);

Expand All @@ -66,6 +69,8 @@ void MatterPostCommandReceivedCallback(const chip::app::ConcreteCommandPath & co

void MatterPostAttributeReadCallback(const chip::app::ConcreteAttributePath & attributePath)
{
VerifyOrReturn(!InteractiveServer::GetInstance().ReadAttribute(attributePath));

auto test = GetTargetTest();
VerifyOrReturn(test != nullptr && test->isRunning);

Expand All @@ -77,6 +82,8 @@ void MatterPostAttributeReadCallback(const chip::app::ConcreteAttributePath & at

void MatterPostAttributeWriteCallback(const chip::app::ConcreteAttributePath & attributePath)
{
VerifyOrReturn(!InteractiveServer::GetInstance().WriteAttribute(attributePath));

auto test = GetTargetTest();
VerifyOrReturn(test != nullptr && test->isRunning);

Expand Down
7 changes: 7 additions & 0 deletions examples/placeholder/linux/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,13 @@ int main(int argc, char * argv[])
}

LinuxDeviceOptions::GetInstance().dacProvider = AppOptions::GetDACProvider();

auto & server = InteractiveServer::GetInstance();
if (AppOptions::GetInteractiveMode())
{
server.Run(AppOptions::GetInteractiveModePort());
}

ChipLinuxAppMainLoop();
return 0;
}

0 comments on commit 3586877

Please sign in to comment.