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

[ota-requestor] Build QueryImage based on Basic cluster attributes #12671

Merged
merged 1 commit into from
Dec 8, 2021
Merged
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
Original file line number Diff line number Diff line change
@@ -776,7 +776,7 @@
"mfgCode": null,
"define": "BASIC_CLUSTER",
"side": "server",
"enabled": 0,
"enabled": 1,
"commands": [
{
"name": "StartUp",
@@ -3711,5 +3711,6 @@
"endpointVersion": 1,
"deviceIdentifier": 22
}
]
],
"log": []
}
160 changes: 82 additions & 78 deletions src/app/clusters/ota-requestor/OTARequestor.cpp
Original file line number Diff line number Diff line change
@@ -29,61 +29,36 @@

#include "BDXDownloader.h"

#include <app-common/zap-generated/attributes/Accessors.h>
#include <controller/CHIPDeviceControllerFactory.h>
#include <controller/CommissioneeDeviceProxy.h>
#include <controller/ExampleOperationalCredentialsIssuer.h>

#include <zap-generated/CHIPClientCallbacks.h>
#include <zap-generated/CHIPClusters.h>

using chip::ByteSpan;
using chip::CASESessionManager;
using chip::CASESessionManagerConfig;
using chip::CharSpan;
using chip::DeviceProxy;
using chip::EndpointId;
using chip::FabricIndex;
using chip::FabricInfo;
using chip::NodeId;
using chip::OnDeviceConnected;
using chip::OnDeviceConnectionFailure;
using chip::PeerId;
using chip::Server;
using chip::VendorId;
using chip::bdx::TransferSession;
using chip::Callback::Callback;
using chip::System::Layer;
using chip::Transport::PeerAddress;
// using namespace chip::ArgParser;
using namespace chip;
using namespace chip::app::Clusters;
using namespace chip::bdx;
using namespace chip::Messaging;
using namespace chip::app::Clusters::OtaSoftwareUpdateProvider::Commands;
using chip::Inet::IPAddress;

namespace {
// Global instance of the OTARequestorInterface.
OTARequestorInterface * globalOTARequestorInstance = nullptr;

constexpr uint32_t kImmediateStartDelayMs = 1; // Start the timer with this value when starting OTA "immediately"

// Callbacks for connection management
void OnConnected(void * context, chip::OperationalDeviceProxy * deviceProxy);
Callback<OnDeviceConnected> mOnConnectedCallback(OnConnected, nullptr);
Callback::Callback<OnDeviceConnected> mOnConnectedCallback(OnConnected, nullptr);

void OnConnectionFailure(void * context, NodeId deviceId, CHIP_ERROR error);
Callback<OnDeviceConnectionFailure> mOnConnectionFailureCallback(OnConnectionFailure, nullptr);
Callback::Callback<OnDeviceConnectionFailure> mOnConnectionFailureCallback(OnConnectionFailure, nullptr);

void OnQueryImageResponse(void * context, const QueryImageResponse::DecodableType & response);
void OnQueryImageFailure(void * context, EmberAfStatus status);

void SetRequestorInstance(OTARequestorInterface * instance)
{
globalOTARequestorInstance = instance;
}

OTARequestorInterface * GetRequestorInstance()
{
return globalOTARequestorInstance;
}

void StartDelayTimerHandler(chip::System::Layer * systemLayer, void * appState)
{
VerifyOrReturn(appState != nullptr);
@@ -95,6 +70,17 @@ void OnQueryImageFailure(void * context, EmberAfStatus status)
ChipLogDetail(SoftwareUpdate, "QueryImage failure response %" PRIu8, status);
}

// Called whenever FindOrEstablishSession is successful. Finds the Requestor instance
// and calls the corresponding OTARequestor member function
void OnConnected(void * context, chip::OperationalDeviceProxy * deviceProxy)
{
OTARequestor * requestorCore = static_cast<OTARequestor *>(GetRequestorInstance());

VerifyOrDie(requestorCore != nullptr);

requestorCore->mOnConnected(context, deviceProxy);
}

void OnConnectionFailure(void * context, NodeId deviceId, CHIP_ERROR error)
{
ChipLogError(SoftwareUpdate, "failed to connect to 0x%" PRIX64 ": %" CHIP_ERROR_FORMAT, deviceId, error.Format());
@@ -104,10 +90,27 @@ void OnQueryImageResponse(void * context, const QueryImageResponse::DecodableTyp
{
OTARequestor * requestorCore = static_cast<OTARequestor *>(GetRequestorInstance());

assert(requestorCore != nullptr);
VerifyOrDie(requestorCore != nullptr);

requestorCore->mOnQueryImageResponse(context, response);
}
} // namespace

void SetRequestorInstance(OTARequestorInterface * instance)
{
globalOTARequestorInstance = instance;
}

OTARequestorInterface * GetRequestorInstance()
{
return globalOTARequestorInstance;
}

struct OTARequestor::QueryImageRequest
{
char location[2];
QueryImage::Type args;
};

void OTARequestor::mOnQueryImageResponse(void * context, const QueryImageResponse::DecodableType & response)
{
@@ -297,7 +300,7 @@ void OTARequestor::ConnectToProvider()

// Explicitly calling UpdateDeviceData() should not be needed once OperationalDeviceProxy can resolve IP address from node ID
// and fabric index
PeerAddress addr = PeerAddress::UDP(mIpAddress, CHIP_PORT);
Transport::PeerAddress addr = Transport::PeerAddress::UDP(mIpAddress, CHIP_PORT);
operationalDeviceProxy->UpdateDeviceData(addr, operationalDeviceProxy->GetMRPConfig());

CHIP_ERROR err = operationalDeviceProxy->Connect(&mOnConnectedCallback, &mOnConnectionFailureCallback);
@@ -307,58 +310,25 @@ void OTARequestor::ConnectToProvider()
}
}

// Called whenever FindOrEstablishSession is successful. Finds the Requestor instance
// and calls the corresponding OTARequestor member function
void OnConnected(void * context, chip::OperationalDeviceProxy * deviceProxy)
{
OTARequestor * requestorCore = static_cast<OTARequestor *>(GetRequestorInstance());

assert(requestorCore != nullptr);

requestorCore->mOnConnected(context, deviceProxy);
}

// Member function called whenever FindOrEstablishSession is successful
void OTARequestor::mOnConnected(void * context, chip::DeviceProxy * deviceProxy)
{
switch (onConnectedState)
{
case kQueryImage: {
CHIP_ERROR err = CHIP_NO_ERROR;
chip::Controller::OtaSoftwareUpdateProviderCluster cluster;
constexpr EndpointId kOtaProviderEndpoint = 0;

// These QueryImage params have been chosen arbitrarily
constexpr VendorId kExampleVendorId = VendorId::Common;
constexpr uint16_t kExampleProductId = 77;
constexpr uint16_t kExampleHWVersion = 3;
constexpr uint16_t kExampleSoftwareVersion = 0;
constexpr EmberAfOTADownloadProtocol kExampleProtocolsSupported[] = { EMBER_ZCL_OTA_DOWNLOAD_PROTOCOL_BDX_SYNCHRONOUS };
const char locationBuf[] = { 'U', 'S' };
CharSpan exampleLocation(locationBuf);
constexpr bool kExampleClientCanConsent = false;
ByteSpan metadata;

err = cluster.Associate(deviceProxy, kOtaProviderEndpoint);
if (err != CHIP_NO_ERROR)
{
ChipLogError(SoftwareUpdate, "Associate() failed: %" CHIP_ERROR_FORMAT, err.Format());
return;
}
QueryImage::Type args;
args.vendorId = kExampleVendorId;
args.productId = kExampleProductId;
args.softwareVersion = kExampleSoftwareVersion;
args.protocolsSupported = kExampleProtocolsSupported;
args.hardwareVersion.Emplace(kExampleHWVersion);
args.location.Emplace(exampleLocation);
args.requestorCanConsent.Emplace(kExampleClientCanConsent);
args.metadataForProvider.Emplace(metadata);
err = cluster.InvokeCommand(args, /* context = */ nullptr, OnQueryImageResponse, OnQueryImageFailure);
if (err != CHIP_NO_ERROR)
{
ChipLogError(SoftwareUpdate, "QueryImage() failed: %" CHIP_ERROR_FORMAT, err.Format());
}
QueryImageRequest request;
CHIP_ERROR err = BuildQueryImageRequest(request);
VerifyOrReturn(err == CHIP_NO_ERROR,
ChipLogError(SoftwareUpdate, "Failed to build QueryImage command: %" CHIP_ERROR_FORMAT, err.Format()));

Controller::OtaSoftwareUpdateProviderCluster cluster;
cluster.Associate(deviceProxy, kOtaProviderEndpoint);

err = cluster.InvokeCommand(request.args, /* context = */ nullptr, OnQueryImageResponse, OnQueryImageFailure);
VerifyOrReturn(err == CHIP_NO_ERROR,
ChipLogError(SoftwareUpdate, "Failed to send QueryImage command: %" CHIP_ERROR_FORMAT, err.Format()));

break;
}
@@ -410,3 +380,37 @@ void OTARequestor::TriggerImmediateQuery()
// Perhaps we don't need a separate function ConnectToProvider, revisit this
ConnectToProvider();
}

CHIP_ERROR OTARequestor::BuildQueryImageRequest(QueryImageRequest & request)
{
constexpr EmberAfOTADownloadProtocol kProtocolsSupported[] = { EMBER_ZCL_OTA_DOWNLOAD_PROTOCOL_BDX_SYNCHRONOUS };
constexpr bool kRequestorCanConsent = false;
QueryImage::Type & args = request.args;

uint16_t vendorId;
VerifyOrReturnError(Basic::Attributes::VendorID::Get(kRootEndpointId, &vendorId) == EMBER_ZCL_STATUS_SUCCESS,
CHIP_ERROR_READ_FAILED);
args.vendorId = static_cast<VendorId>(vendorId);

VerifyOrReturnError(Basic::Attributes::ProductID::Get(kRootEndpointId, &args.productId) == EMBER_ZCL_STATUS_SUCCESS,
CHIP_ERROR_READ_FAILED);

VerifyOrReturnError(Basic::Attributes::SoftwareVersion::Get(kRootEndpointId, &args.softwareVersion) == EMBER_ZCL_STATUS_SUCCESS,
CHIP_ERROR_READ_FAILED);

args.protocolsSupported = kProtocolsSupported;
args.requestorCanConsent.SetValue(kRequestorCanConsent);

uint16_t hardwareVersion;
if (Basic::Attributes::HardwareVersion::Get(kRootEndpointId, &hardwareVersion) == EMBER_ZCL_STATUS_SUCCESS)
{
args.hardwareVersion.SetValue(hardwareVersion);
}

if (Basic::Attributes::Location::Get(kRootEndpointId, MutableCharSpan(request.location)) == EMBER_ZCL_STATUS_SUCCESS)
{
args.location.SetValue(CharSpan(request.location));
}

return CHIP_NO_ERROR;
}
3 changes: 3 additions & 0 deletions src/app/clusters/ota-requestor/OTARequestor.h
Original file line number Diff line number Diff line change
@@ -85,6 +85,8 @@ class OTARequestor : public OTARequestorInterface
kStartBDX,
};

struct QueryImageRequest;
andy31415 marked this conversation as resolved.
Show resolved Hide resolved

// TODO: the application should define this, along with initializing the BDXDownloader

// This class is purely for delivering messages and sending outgoing messages to/from the BDXDownloader.
@@ -169,4 +171,5 @@ class OTARequestor : public OTARequestorInterface

// Functions
CHIP_ERROR SetupCASESessionManager(chip::FabricIndex fabricIndex);
CHIP_ERROR BuildQueryImageRequest(QueryImageRequest & req);
};
7 changes: 4 additions & 3 deletions src/lib/core/DataModelTypes.h
Original file line number Diff line number Diff line change
@@ -43,8 +43,9 @@ typedef uint32_t FieldId;
typedef uint16_t ListIndex;
typedef uint32_t TransactionId;

static constexpr FabricIndex kUndefinedFabricIndex = 0;
static constexpr EndpointId kInvalidEndpointId = 0xFFFF;
static constexpr ListIndex kInvalidListIndex = 0xFFFF; // List index is a uint16 thus 0xFFFF is a invalid list index.
constexpr FabricIndex kUndefinedFabricIndex = 0;
Damian-Nordic marked this conversation as resolved.
Show resolved Hide resolved
constexpr EndpointId kInvalidEndpointId = 0xFFFF;
constexpr EndpointId kRootEndpointId = 0;
constexpr ListIndex kInvalidListIndex = 0xFFFF; // List index is a uint16 thus 0xFFFF is a invalid list index.

} // namespace chip

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

99 changes: 67 additions & 32 deletions zzz_generated/ota-requestor-app/zap-generated/endpoint_config.h

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions zzz_generated/ota-requestor-app/zap-generated/gen_config.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.