Skip to content
Open
Show file tree
Hide file tree
Changes from 16 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
20 changes: 19 additions & 1 deletion examples/ota-provider-app/linux/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include <json/json.h>
#include <ota-provider-common/BdxOtaSender.h>
#include <ota-provider-common/OTAProviderExample.h>
#include <ota-provider-common/OtaProviderAppCommandDelegate.h>

#include "AppMain.h"

Expand Down Expand Up @@ -59,6 +60,8 @@ constexpr uint16_t kOptionIgnoreApplyUpdate = 'y';
constexpr uint16_t kOptionPollInterval = 'P';

OTAProviderExample gOtaProvider;
NamedPipeCommands sChipNamedPipeCommands;
OtaProviderAppCommandDelegate sOtaProviderAppCommandDelegate;
chip::ota::DefaultOTAProviderUserConsent gUserConsentProvider;

// Global variables used for passing the CLI arguments to the OTAProviderExample object
Expand Down Expand Up @@ -403,9 +406,24 @@ void ApplicationInit()
}

chip::app::Clusters::OTAProvider::SetDelegate(kOtaProviderEndpoint, &gOtaProvider);

std::string path = std::string(LinuxDeviceOptions::GetInstance().app_pipe);
std::string path_out = std::string(LinuxDeviceOptions::GetInstance().app_pipe_out);

if ((!path.empty()) and (sChipNamedPipeCommands.Start(path, path_out, &sOtaProviderAppCommandDelegate) != CHIP_NO_ERROR))
{
ChipLogError(NotSpecified, "Failed to start CHIP NamedPipeCommand");
sChipNamedPipeCommands.Stop();
}
}

void ApplicationShutdown() {}
void ApplicationShutdown()
{
if (sChipNamedPipeCommands.Stop() != CHIP_NO_ERROR)
{
ChipLogError(NotSpecified, "Failed to stop CHIP NamedPipeCommands");
}
}

namespace {
class OtaProviderAppMainLoopImplementation : public AppMainLoopImplementation
Expand Down
8 changes: 7 additions & 1 deletion examples/ota-provider-app/ota-provider-common/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@ import("//build_overrides/chip.gni")
import("${chip_root}/src/app/chip_data_model.gni")

config("config") {
include_dirs = [ ".." ]
include_dirs = [
"..",
"${chip_root}/examples/platform/linux",
]
}

chip_data_model("ota-provider-common") {
Expand All @@ -28,9 +31,12 @@ chip_data_model("ota-provider-common") {
"BdxOtaSender.h",
"OTAProviderExample.cpp",
"OTAProviderExample.h",
"OtaProviderAppCommandDelegate.cpp",
"OtaProviderAppCommandDelegate.h",
]

deps = [
"${chip_root}/examples/platform/linux:app-main",
"${chip_root}/src/app/clusters/ota-provider:user-consent",
"${chip_root}/src/protocols/bdx",
]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/*
*json
* Copyright (c) 2025 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 "OtaProviderAppCommandDelegate.h"
#include <platform/PlatformManager.h>

using namespace chip;
using namespace chip::app;
using namespace chip::app::Clusters;
using namespace chip::DeviceLayer;

OtaProviderAppCommandHandler * OtaProviderAppCommandHandler::FromJSON(const char * json)
{
Json::Reader reader;
Json::Value value;

if (!reader.parse(json, value))
{
ChipLogError(NotSpecified,
"OTA Provider Example: Error parsing JSON with error %s:", reader.getFormattedErrorMessages().c_str());
return nullptr;
}

if (value.empty() || !value.isObject())
{
ChipLogError(NotSpecified, "OTA Provider Example: Invalid JSON command received");
return nullptr;
}

if (!value.isMember("Name") || !value["Name"].isString())
{
ChipLogError(NotSpecified, "OTA Provider Example: Invalid JSON command received: command name is missing");
return nullptr;
}

return chip::Platform::New<OtaProviderAppCommandHandler>(std::move(value));
}

std::string OtaProviderAppCommandHandler::GetQueryImageResponse()
{
return "Test";
}

void OtaProviderAppCommandHandler::HandleCommand(intptr_t context)
{
auto * self = reinterpret_cast<OtaProviderAppCommandHandler *>(context);
std::string name = self->mJsonValue["Name"].asString();

VerifyOrExit(!self->mJsonValue.empty(), ChipLogError(NotSpecified, "Invalid JSON event command received"));

if (name == "GetQueryImageResponse")
{
std::string queryImage = self->GetQueryImageResponse();
}
else
{
ChipLogError(NotSpecified, "Unhandled command: Should never happen");
}

exit:
chip::Platform::Delete(self);
}

void OtaProviderAppCommandDelegate::OnEventCommandReceived(const char * json)
{
auto handler = OtaProviderAppCommandHandler::FromJSON(json);
if (nullptr == handler)
{
ChipLogError(NotSpecified, "OTA Provider App: Unable to instantiate a command handler");
return;
}

chip::DeviceLayer::PlatformMgr().ScheduleWork(OtaProviderAppCommandHandler::HandleCommand, reinterpret_cast<intptr_t>(handler));
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
*
* Copyright (c) 2025 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 "NamedPipeCommands.h"

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

#include <string>

class OtaProviderAppCommandHandler {
public:
static OtaProviderAppCommandHandler * FromJSON(const char * json);

static void HandleCommand(intptr_t context);

OtaProviderAppCommandHandler(Json::Value && jsonValue)
: mJsonValue(std::move(jsonValue))
{
}

private:
Json::Value mJsonValue;

std::string GetQueryImageResponse();
};

class OtaProviderAppCommandDelegate : public NamedPipeCommandDelegate {
public:
void OnEventCommandReceived(const char * json) override;
};
47 changes: 44 additions & 3 deletions examples/platform/linux/NamedPipeCommands.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,10 @@ CHIP_ERROR NamedPipeCommands::Start(std::string & path, NamedPipeCommandDelegate
VerifyOrReturnError(!mStarted, CHIP_NO_ERROR);
VerifyOrReturnError(delegate != nullptr, CHIP_ERROR_INVALID_ARGUMENT);

mStarted = true;
mDelegate = delegate;
mChipEventFifoPath = path;
mStarted = true;
mDelegate = delegate;
mChipEventFifoPath = path;
mChipEventFifoPathOut = "";

// Creating the named file(FIFO)
VerifyOrReturnError((mkfifo(path.c_str(), 0666) == 0) || (errno == EEXIST), CHIP_ERROR_OPEN_FAILED);
Expand All @@ -48,6 +49,27 @@ CHIP_ERROR NamedPipeCommands::Start(std::string & path, NamedPipeCommandDelegate
return CHIP_NO_ERROR;
}

CHIP_ERROR NamedPipeCommands::Start(std::string & path, std::string & path_out, NamedPipeCommandDelegate * delegate)
{
VerifyOrReturnError(!mStarted, CHIP_NO_ERROR);
VerifyOrReturnError(delegate != nullptr, CHIP_ERROR_INVALID_ARGUMENT);

mStarted = true;
mDelegate = delegate;
mChipEventFifoPath = path;
mChipEventFifoPathOut = path_out;

// Creating the named file(FIFO)
VerifyOrReturnError((mkfifo(path.c_str(), 0666) == 0) || (errno == EEXIST), CHIP_ERROR_OPEN_FAILED);
VerifyOrReturnError(
pthread_create(&mChipEventCommandListener, nullptr, EventCommandListenerTask, reinterpret_cast<void *>(this)) == 0,
CHIP_ERROR_UNEXPECTED_EVENT);

VerifyOrReturnError((mkfifo(path_out.c_str(), 0666) == 0) || (errno == EEXIST), CHIP_ERROR_OPEN_FAILED);

return CHIP_NO_ERROR;
}

CHIP_ERROR NamedPipeCommands::Stop()
{
VerifyOrReturnError(mStarted, CHIP_NO_ERROR);
Expand All @@ -63,9 +85,28 @@ CHIP_ERROR NamedPipeCommands::Stop()
VerifyOrReturnError(unlink(mChipEventFifoPath.c_str()) == 0, CHIP_ERROR_WRITE_FAILED);
mChipEventFifoPath.clear();

if (mChipEventFifoPath != "")
{
VerifyOrReturnError(unlink(mChipEventFifoPathOut.c_str()) == 0, CHIP_ERROR_WRITE_FAILED);
mChipEventFifoPathOut.clear();
}

return CHIP_NO_ERROR;
}

void NamedPipeCommands::WriteToOutPipe()
{
// NamedPipeCommands * self = reinterpret_cast<NamedPipeCommands *>(arg);
//
// int fd = open(self->mChipEventFifoPathOut.c_str(), O_RDONLY);
// if (fd == -1)
// {
// ChipLogError(NotSpecified, "Failed to open Event FIFO");
// break;
// }
// write(fd, data, kChipEventCmdBufSize);
}

void * NamedPipeCommands::EventCommandListenerTask(void * arg)
{
char readbuf[kChipEventCmdBufSize];
Expand Down
11 changes: 6 additions & 5 deletions examples/platform/linux/NamedPipeCommands.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,24 +22,25 @@
#include <pthread.h>
#include <string>

class NamedPipeCommandDelegate
{
class NamedPipeCommandDelegate {
public:
virtual ~NamedPipeCommandDelegate() = default;
virtual ~NamedPipeCommandDelegate() = default;
virtual void OnEventCommandReceived(const char * json) = 0;
};

class NamedPipeCommands
{
class NamedPipeCommands {
public:
CHIP_ERROR Start(std::string & path, NamedPipeCommandDelegate * delegate);
CHIP_ERROR Start(std::string & path, std::string & path_out, NamedPipeCommandDelegate * delegate);
CHIP_ERROR Stop();

private:
bool mStarted = false;
pthread_t mChipEventCommandListener;
std::string mChipEventFifoPath;
std::string mChipEventFifoPathOut;
NamedPipeCommandDelegate * mDelegate = nullptr;

static void * EventCommandListenerTask(void * arg);
void WriteToOutPipe();
};
40 changes: 20 additions & 20 deletions examples/platform/linux/Options.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,44 +45,44 @@
#include <access/AccessRestrictionProvider.h>
#endif

struct LinuxDeviceOptions
{
struct LinuxDeviceOptions {
chip::PayloadContents payload;
chip::Optional<uint16_t> discriminator;
chip::Optional<std::vector<uint8_t>> spake2pVerifier;
chip::Optional<std::vector<uint8_t>> spake2pSalt;
chip::Optional<std::string> dacProviderFile;
uint32_t spake2pIterations = 0; // When not provided (0), will default elsewhere
uint32_t mBleDevice = 0;
bool wifiSupports5g = false;
bool mWiFi = false;
bool mThread = false;
bool cameraDeferredOffer = false;
bool cameraTestVideosrc = false;
bool cameraTestAudiosrc = false;
bool cameraAudioPlayback = false;
uint32_t mBleDevice = 0;
bool wifiSupports5g = false;
bool mWiFi = false;
bool mThread = false;
bool cameraDeferredOffer = false;
bool cameraTestVideosrc = false;
bool cameraTestAudiosrc = false;
bool cameraAudioPlayback = false;
chip::Optional<std::string> cameraVideoDevice;
#if CHIP_DEVICE_CONFIG_ENABLE_WIFIPAF
bool mWiFiPAF = false;
bool mWiFiPAF = false;
const char * mWiFiPAFExtCmds = nullptr;
uint32_t mPublishId = 0;
uint32_t mPublishId = 0;
#endif
#if CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE || CHIP_DEVICE_ENABLE_PORT_PARAMS
uint16_t securedDevicePort = CHIP_PORT;
uint16_t securedDevicePort = CHIP_PORT;
uint16_t unsecuredCommissionerPort = CHIP_UDC_PORT;
#endif // CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE || CHIP_DEVICE_ENABLE_PORT_PARAMS
#if CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE
uint16_t securedCommissionerPort = CHIP_PORT + 12; // TODO: why + 12?
uint16_t securedCommissionerPort = CHIP_PORT + 12; // TODO: why + 12?
chip::FabricId commissionerFabricId = chip::kUndefinedFabricId;
#endif // CHIP_DEVICE_CONFIG_ENABLE_BOTH_COMMISSIONER_AND_COMMISSIONEE
const char * command = nullptr;
const char * PICS = nullptr;
const char * KVS = nullptr;
const char * app_pipe = "";
const char * command = nullptr;
const char * PICS = nullptr;
const char * KVS = nullptr;
const char * app_pipe = "";
const char * app_pipe_out = "";
chip::Inet::InterfaceId interfaceId = chip::Inet::InterfaceId::Null();
#if CHIP_CONFIG_TRANSPORT_TRACE_ENABLED
bool traceStreamDecodeEnabled = false;
bool traceStreamToLogEnabled = false;
bool traceStreamToLogEnabled = false;
chip::Optional<std::string> traceStreamFilename;
#endif // CHIP_CONFIG_TRANSPORT_TRACE_ENABLED
chip::Credentials::DeviceAttestationCredentialsProvider * dacProvider = nullptr;
Expand All @@ -94,7 +94,7 @@ struct LinuxDeviceOptions
uint16_t rpcServerPort = 33000;
#endif
#if CONFIG_BUILD_FOR_HOST_UNIT_TEST
int32_t subscriptionCapacity = CHIP_IM_MAX_NUM_SUBSCRIPTIONS;
int32_t subscriptionCapacity = CHIP_IM_MAX_NUM_SUBSCRIPTIONS;
int32_t subscriptionResumptionRetryIntervalSec = -1;
#endif
#if CHIP_CONFIG_USE_ACCESS_RESTRICTIONS
Expand Down
Loading