diff --git a/.github/workflows/examples-linux-standalone.yaml b/.github/workflows/examples-linux-standalone.yaml index 245da8d433bc2a..661ca1ad40d754 100644 --- a/.github/workflows/examples-linux-standalone.yaml +++ b/.github/workflows/examples-linux-standalone.yaml @@ -116,6 +116,14 @@ jobs: linux debug ota-provider-app \ out/ota_provider_debug/chip-ota-provider-app \ /tmp/bloat_reports/ + - name: Build example OTA Requestor + timeout-minutes: 5 + run: | + scripts/examples/gn_build_example.sh examples/ota-requestor-app/linux out/ota_requestor_debug + .environment/pigweed-venv/bin/python3 scripts/tools/memory/gh_sizes.py \ + linux debug ota-requestor-app \ + out/ota_requestor_debug/chip-ota-requestor-app \ + /tmp/bloat_reports/ - name: Binary artifact suffix id: outsuffix uses: haya14busa/action-cond@v1.0.0 diff --git a/examples/ota-requestor-app/linux/BUILD.gn b/examples/ota-requestor-app/linux/BUILD.gn index b2eaddb6aa29fd..40324a5e71ef30 100644 --- a/examples/ota-requestor-app/linux/BUILD.gn +++ b/examples/ota-requestor-app/linux/BUILD.gn @@ -17,6 +17,7 @@ import("//build_overrides/chip.gni") executable("chip-ota-requestor-app") { sources = [ + "ExampleSelfCommissioning.h", "PersistentStorage.cpp", "main.cpp", ] diff --git a/examples/ota-requestor-app/linux/ExampleSelfCommissioning.h b/examples/ota-requestor-app/linux/ExampleSelfCommissioning.h new file mode 100644 index 00000000000000..bfd50286a952e7 --- /dev/null +++ b/examples/ota-requestor-app/linux/ExampleSelfCommissioning.h @@ -0,0 +1,78 @@ +/* + * + * 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. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +using chip::PersistentStorageDelegate; +using chip::Controller::DeviceController; +using chip::Controller::ExampleOperationalCredentialsIssuer; + +CHIP_ERROR DoExampleSelfCommissioning(DeviceController & controller, ExampleOperationalCredentialsIssuer * opCredsIssuer, + PersistentStorageDelegate * storage, chip::NodeId localNodeId) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + chip::Platform::ScopedMemoryBuffer noc; + chip::Platform::ScopedMemoryBuffer icac; + chip::Platform::ScopedMemoryBuffer rcac; + chip::Controller::ControllerInitParams initParams; + + VerifyOrExit(storage != nullptr && opCredsIssuer != nullptr, err = CHIP_ERROR_INVALID_ARGUMENT); + + err = opCredsIssuer->Initialize(*storage); + VerifyOrExit(err == CHIP_NO_ERROR, ChipLogError(Controller, "Init failure! Operational Cred Issuer: %s", chip::ErrorStr(err))); + + VerifyOrExit(rcac.Alloc(chip::Controller::kMaxCHIPDERCertLength), err = CHIP_ERROR_NO_MEMORY); + VerifyOrExit(noc.Alloc(chip::Controller::kMaxCHIPDERCertLength), err = CHIP_ERROR_NO_MEMORY); + VerifyOrExit(icac.Alloc(chip::Controller::kMaxCHIPDERCertLength), err = CHIP_ERROR_NO_MEMORY); + + { + chip::MutableByteSpan nocSpan(noc.Get(), chip::Controller::kMaxCHIPDERCertLength); + chip::MutableByteSpan icacSpan(icac.Get(), chip::Controller::kMaxCHIPDERCertLength); + chip::MutableByteSpan rcacSpan(rcac.Get(), chip::Controller::kMaxCHIPDERCertLength); + + chip::Crypto::P256Keypair ephemeralKey; + SuccessOrExit(err = ephemeralKey.Initialize()); + + // TODO - OpCreds should only be generated for pairing command + // store the credentials in persistent storage, and + // generate when not available in the storage. + err = opCredsIssuer->GenerateNOCChainAfterValidation(localNodeId, 0, ephemeralKey.Pubkey(), rcacSpan, icacSpan, nocSpan); + SuccessOrExit(err); + + initParams.ephemeralKeypair = &ephemeralKey; + initParams.controllerRCAC = rcacSpan; + initParams.controllerICAC = icacSpan; + initParams.controllerNOC = nocSpan; + initParams.operationalCredentialsDelegate = opCredsIssuer; + + initParams.storageDelegate = storage; + + err = controller.Init(initParams); + VerifyOrExit(err == CHIP_NO_ERROR, ChipLogError(Controller, "Controller init failure! %s", chip::ErrorStr(err))); + } + +exit: + return err; +} diff --git a/examples/ota-requestor-app/linux/README.md b/examples/ota-requestor-app/linux/README.md index 85580188a49686..8d1089943852eb 100644 --- a/examples/ota-requestor-app/linux/README.md +++ b/examples/ota-requestor-app/linux/README.md @@ -1,29 +1,45 @@ # ota-requestor-app (Linux) -WARNING: this app currently does not build successfully. It is being submitted -as a starting point for further OTA Requestor development. - This is a reference application that is both a server for the OTA Requestor Cluster, as well as a client of the OTA Provider Cluster. It should initiate a Software Update with a given OTA Provider node, and download a file. +## Usage + +Due to #9518, this app must pretend to be `chip-tool` in order to establish a +connection to the OTA Provider. It does this by reading the CASE session and +other necessary credentials stored in persistent memory on startup. + +Therefore, to use this app you should call these commands in the following +order: + +In one terminal: + +``` +./chip-ota-provider-app [-f ] +``` + +In a second terminal: + +``` +./chip-tool pairing onnetwork 0 20202021 3840 ::1 5540 +./chip-ota-requestor-app [-p ] +``` + ## Current Features / Limitations ### Features - Code for running a full BDX download exists in BDX - Sends QueryImage command +- Takes a peer Node ID as an argument ### Limitations - needs chip-tool to pair to the Provider device first, so it can steal the CASE session from persisted memory - uses Controller class to load the CASE session -- Controller does not provide any way to access a new ExchangeContext for the - BDX exchange -- doesn't wait for QueryImageResponse to begin the BDX exchange - does not verify QueryImageResponse message contents - stores the downloaded file at a hardcoded filepath - doesn't close the BDX ExchangeContext when the exchange is over -- only uses hardcoded node IDs - does not support AnnounceOTAProvider command or OTA Requestor attributes diff --git a/examples/ota-requestor-app/linux/main.cpp b/examples/ota-requestor-app/linux/main.cpp index aadcd0118ee6c6..331a48007097a0 100644 --- a/examples/ota-requestor-app/linux/main.cpp +++ b/examples/ota-requestor-app/linux/main.cpp @@ -16,25 +16,29 @@ * limitations under the License. */ -#include -#include - +#include #include #include #include #include #include +#include #include +#include #include +#include #include #include #include +#include +#include #include #include #include #include #include "BDXDownloader.h" +#include "ExampleSelfCommissioning.h" #include "PersistentStorage.h" #include @@ -43,44 +47,110 @@ using chip::ByteSpan; using chip::EndpointId; using chip::VendorId; +using chip::ArgParser::HelpOptions; +using chip::ArgParser::OptionDef; +using chip::ArgParser::OptionSet; +using chip::ArgParser::PrintArgError; using chip::bdx::TransferSession; using chip::Callback::Callback; - +using chip::Controller::Device; +using chip::Controller::DeviceController; +using chip::Controller::ExampleOperationalCredentialsIssuer; +using chip::Controller::OnDeviceConnected; +using chip::Controller::OnDeviceConnectionFailure; + +// TODO: would be nicer to encapsulate these globals and the callbacks in some sort of class +chip::Messaging::ExchangeContext * exchangeCtx = nullptr; +Device * providerDevice = nullptr; +BdxDownloader bdxDownloader; void OnQueryImageResponse(void * context, uint8_t status, uint32_t delayedActionTime, uint8_t * imageURI, uint32_t softwareVersion, chip::ByteSpan updateToken, bool userConsentNeeded, chip::ByteSpan metadataForRequestor) { ChipLogDetail(SoftwareUpdate, "%s", __FUNCTION__); + + TransferSession::TransferInitData initOptions; + initOptions.TransferCtlFlags = chip::bdx::TransferControlFlags::kReceiverDrive; + initOptions.MaxBlockSize = 1024; + char testFileDes[9] = { "test.txt" }; + initOptions.FileDesLength = static_cast(strlen(testFileDes)); + initOptions.FileDesignator = reinterpret_cast(testFileDes); + + { + chip::Messaging::ExchangeManager * exchangeMgr = providerDevice->GetExchangeManager(); + chip::Optional session = providerDevice->GetSecureSession(); + if (exchangeMgr != nullptr && session.HasValue()) + { + exchangeCtx = exchangeMgr->NewContext(session.Value(), &bdxDownloader); + } + + if (exchangeCtx == nullptr) + { + ChipLogError(BDX, "unable to allocate ec: exchangeMgr=%p sessionExists? %u", exchangeMgr, session.HasValue()); + return; + } + } + + bdxDownloader.SetInitialExchange(exchangeCtx); + + // This will kick of a timer which will regularly check for updates to the bdx::TransferSession state machine. + bdxDownloader.InitiateTransfer(&chip::DeviceLayer::SystemLayer(), chip::bdx::TransferRole::kReceiver, initOptions, 20000); } -void OnFailure(void * context, uint8_t status) +void OnQueryFailure(void * context, uint8_t status) { - ChipLogDetail(SoftwareUpdate, "Received failure response %d\n", (int) status); + ChipLogDetail(SoftwareUpdate, "QueryImage failure response %" PRIu8, status); } Callback mQueryImageResponseCallback(OnQueryImageResponse, nullptr); -Callback mOnFailureCallback(OnFailure, nullptr); +Callback mOnQueryFailureCallback(OnQueryFailure, nullptr); +void OnConnection(void * context, Device * device) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + chip::Controller::OtaSoftwareUpdateProviderCluster cluster; + constexpr EndpointId kOtaProviderEndpoint = 0; -chip::Controller::OtaSoftwareUpdateProviderCluster cluster; -const EndpointId kOtaProviderEndpoint = 0; -PersistentStorage mStorage; -chip::Controller::ExampleOperationalCredentialsIssuer mOpCredsIssuer; -chip::Controller::DeviceController mController; -chip::Controller::ControllerInitParams initParams; -chip::Controller::Device * providerDevice; -chip::Messaging::ExchangeManager * exchangeMgr; -BdxDownloader bdxDownloader; + chip::Callback::Cancelable * successCallback = mQueryImageResponseCallback.Cancel(); + chip::Callback::Cancelable * failureCallback = mOnQueryFailureCallback.Cancel(); + + // These QueryImage params have been chosen arbitrarily + constexpr VendorId kExampleVendorId = VendorId::Common; + constexpr uint16_t kExampleProductId = 77; + constexpr uint16_t kExampleImageType = 0; + constexpr uint16_t kExampleHWVersion = 3; + constexpr uint16_t kExampleCurentVersion = 0; + constexpr uint8_t kExampleProtocolsSupported = + EMBER_ZCL_OTA_DOWNLOAD_PROTOCOL_BDX_SYNCHRONOUS; // TODO: support this as a list once ember adds list support + const uint8_t locationBuf[] = { 'U', 'S' }; + ByteSpan exampleLocation(locationBuf); + constexpr bool kExampleClientCanConsent = false; + ByteSpan metadata; + + err = cluster.Associate(device, kOtaProviderEndpoint); + if (err != CHIP_NO_ERROR) + { + ChipLogError(SoftwareUpdate, "Associate() failed: %s", chip::ErrorStr(err)); + return; + } + err = cluster.QueryImage(successCallback, failureCallback, kExampleVendorId, kExampleProductId, kExampleImageType, + kExampleHWVersion, kExampleCurentVersion, kExampleProtocolsSupported, exampleLocation, + kExampleClientCanConsent, metadata); + if (err != CHIP_NO_ERROR) + { + ChipLogError(SoftwareUpdate, "QueryImage() failed: %s", chip::ErrorStr(err)); + } +} + +void OnConnectFail(void * context, chip::NodeId deviceId, CHIP_ERROR error) +{ + ChipLogError(SoftwareUpdate, "failed to connect to 0x%" PRIX64 ": %s", deviceId, chip::ErrorStr(error)); +} + +Callback mConnectionCallback(OnConnection, nullptr); +Callback mConnectFailCallback(OnConnectFail, nullptr); -// QueryImage params -constexpr VendorId testVendorId = VendorId::Common; -constexpr uint16_t testProductId = 77; -constexpr uint16_t testImageType = 0; -constexpr uint16_t testHWVersion = 3; -constexpr uint16_t testCurrentVersion = 101; -constexpr uint8_t testProtocolsSupported = 0; // TODO: blocked because arrays are being generated as uint8_t -uint8_t locationBuf[3] = { 'U', 'S', '\0' }; -ByteSpan location(locationBuf); -constexpr bool clientCanConsent = false; -ByteSpan metadata(locationBuf); +PersistentStorage mStorage; +DeviceController mController; +ExampleOperationalCredentialsIssuer mOpCredsIssuer; chip::Protocols::Id FromFullyQualified(uint32_t rawProtocolId) { @@ -89,20 +159,49 @@ chip::Protocols::Id FromFullyQualified(uint32_t rawProtocolId) return chip::Protocols::Id(vendorId, protocolId); } -int main(int argc, char * argv[]) +constexpr uint16_t kOptionProviderLocation = 'p'; +chip::NodeId providerNodeId = 0x0; + +bool HandleOptions(const char * aProgram, OptionSet * aOptions, int aIdentifier, const char * aName, const char * aValue) { - CHIP_ERROR err = CHIP_NO_ERROR; - chip::Messaging::ExchangeContext * exchange; + bool retval = true; - chip::Callback::Cancelable * successCallback = mQueryImageResponseCallback.Cancel(); - chip::Callback::Cancelable * failureCallback = mOnFailureCallback.Cancel(); + switch (aIdentifier) + { + case kOptionProviderLocation: + if (1 != sscanf(aValue, "%" PRIX64, &providerNodeId)) + { + PrintArgError("%s: unable to parse Node ID: %s\n", aProgram, aValue); + } + break; + default: + PrintArgError("%s: INTERNAL ERROR: Unhandled option: %s\n", aProgram, aName); + retval = false; + break; + } - TransferSession::TransferInitData initOptions; - initOptions.TransferCtlFlags = chip::bdx::TransferControlFlags::kReceiverDrive; - initOptions.MaxBlockSize = 1024; - char testFileDes[9] = { "test.txt" }; - initOptions.FileDesLength = static_cast(strlen(testFileDes)); - initOptions.FileDesignator = reinterpret_cast(testFileDes); + return (retval); +} + +OptionDef cmdLineOptionsDef[] = { + { "providerLocation", chip::ArgParser::kArgumentRequired, kOptionProviderLocation }, + {}, +}; + +OptionSet cmdLineOptions = { HandleOptions, cmdLineOptionsDef, "PROGRAM OPTIONS", + " -p \n" + " --providerLocation \n" + " Node ID of the OTA Provider to connect to (hex format)\n\n" + " This assumes that you've already commissioned the OTA Provider node with chip-tool.\n" + " See README.md for more info.\n" }; + +HelpOptions helpOptions("ota-requestor-app", "Usage: ota-requestor-app [options]", "1.0"); + +OptionSet * allOptions[] = { &cmdLineOptions, &helpOptions, nullptr }; + +int main(int argc, char * argv[]) +{ + CHIP_ERROR err = CHIP_NO_ERROR; // NOTE: most of the following Init() calls were just copied from chip-tool code @@ -119,52 +218,43 @@ int main(int argc, char * argv[]) return 1; } + if (!chip::ArgParser::ParseArgs(argv[0], argc, argv, allOptions)) + { + return 1; + } + chip::DeviceLayer::ConfigurationMgr().LogDeviceConfig(); err = mStorage.Init(); VerifyOrExit(err == CHIP_NO_ERROR, ChipLogError(Controller, "Init Storage failure: %s", chip::ErrorStr(err))); chip::Logging::SetLogFilter(mStorage.GetLoggingLevel()); - initParams.storageDelegate = &mStorage; - - err = mOpCredsIssuer.Initialize(mStorage); - VerifyOrExit(err == CHIP_NO_ERROR, ChipLogError(Controller, "Init failure! Operational Cred Issuer: %s", chip::ErrorStr(err))); - - initParams.operationalCredentialsDelegate = &mOpCredsIssuer; - err = mController.SetUdpListenPort(mStorage.GetListenPort()); - VerifyOrExit(err == CHIP_NO_ERROR, ChipLogError(Controller, "Init failure! Commissioner: %s", chip::ErrorStr(err))); + VerifyOrExit(err == CHIP_NO_ERROR, ChipLogError(Controller, "failed to set UDP port: %s", chip::ErrorStr(err))); - err = mController.Init(initParams); - VerifyOrExit(err == CHIP_NO_ERROR, ChipLogError(Controller, "Init failure! Commissioner: %s", chip::ErrorStr(err))); + // Until #9518 is fixed, the only way to open a CASE session to another node is to commission it first using the + // DeviceController API. Thus, the ota-requestor-app must do self commissioning and then read CASE credentials from persistent + // storage to connect to the Provider node. See README.md for instructions. + // NOTE: Controller is initialized in this call + err = DoExampleSelfCommissioning(mController, &mOpCredsIssuer, &mStorage, mStorage.GetLocalNodeId()); + VerifyOrExit(err == CHIP_NO_ERROR, ChipLogError(SoftwareUpdate, "example self-commissioning failed: %s", chip::ErrorStr(err))); err = mController.ServiceEvents(); - VerifyOrExit(err == CHIP_NO_ERROR, ChipLogError(Controller, "Init failure! Run Loop: %s", chip::ErrorStr(err))); + VerifyOrExit(err == CHIP_NO_ERROR, ChipLogError(Controller, "ServiceEvents() failed: %s", chip::ErrorStr(err))); + + ChipLogProgress(SoftwareUpdate, "Attempting to connect to device 0x%" PRIX64, providerNodeId); - // WARNING: In order for this to work, you must first pair to the OTA Provider device using chip-tool. + // WARNING: In order for this to work, you must first commission the OTA Provider device using chip-tool. // Currently, that pairing action will persist the CASE session in persistent memory, which will then be read by the following // call. - err = mController.GetDevice(chip::kTestDeviceNodeId, &providerDevice); + err = mController.GetDevice(providerNodeId, &providerDevice); VerifyOrExit(err == CHIP_NO_ERROR, ChipLogError(Controller, "No device found: %s", chip::ErrorStr(err))); - cluster.Associate(providerDevice, kOtaProviderEndpoint); - cluster.QueryImage(successCallback, failureCallback, testVendorId, testProductId, testImageType, testHWVersion, - testCurrentVersion, testProtocolsSupported, location, clientCanConsent, metadata); - - // WARNING: GetNewExchangeContext() was implemented locally as a workaround to get access to an ExchangeContext, but does not - // exist now. Currently there is GetSecureSession(), but the caller still needs access to the ExchangeManager in order to get a - // new ExchangeContext. - exchange = providerDevice->GetNewExchangeContext(&bdxDownloader); - VerifyOrExit(exchange != nullptr, ChipLogError(BDX, "unable to allocate ec")); - - bdxDownloader.SetInitialExchange(exchange); - - // This will kick of a timer which will regularly check for updates to the bdx::TransferSession state machine. - bdxDownloader.InitiateTransfer(&chip::DeviceLayer::SystemLayer, chip::bdx::TransferRole::kReceiver, initOptions, 20000); + err = providerDevice->EstablishConnectivity(&mConnectionCallback, &mConnectFailCallback); chip::DeviceLayer::PlatformMgr().RunEventLoop(); exit: - ChipLogDetail(BDX, "%s", ErrorStr(err)); + ChipLogDetail(SoftwareUpdate, "%s", ErrorStr(err)); return 0; } diff --git a/examples/ota-requestor-app/ota-requestor-common/BDXDownloader.cpp b/examples/ota-requestor-app/ota-requestor-common/BDXDownloader.cpp index fb50d73581a4f0..d3ccf55d4e7dbe 100644 --- a/examples/ota-requestor-app/ota-requestor-common/BDXDownloader.cpp +++ b/examples/ota-requestor-app/ota-requestor-common/BDXDownloader.cpp @@ -19,15 +19,15 @@ #include #include +#include #include #include -bool isTransferComplete = false; - using namespace chip::bdx; -uint32_t numBlocksRead = 0; +uint32_t numBlocksRead = 0; +const char outFilePath[] = "test-ota-out.txt"; void BdxDownloader::SetInitialExchange(chip::Messaging::ExchangeContext * ec) { @@ -37,14 +37,20 @@ void BdxDownloader::SetInitialExchange(chip::Messaging::ExchangeContext * ec) void BdxDownloader::HandleTransferSessionOutput(TransferSession::OutputEvent & event) { CHIP_ERROR err = CHIP_NO_ERROR; - ChipLogDetail(BDX, "OutputEvent type: %d", static_cast(event.EventType)); + + if (event.EventType != TransferSession::OutputEventType::kNone) + { + ChipLogDetail(BDX, "OutputEvent type: %d", static_cast(event.EventType)); + } + switch (event.EventType) { case TransferSession::OutputEventType::kNone: - if (isTransferComplete) + if (mIsTransferComplete) { - ChipLogDetail(BDX, "Transfer complete!"); + ChipLogDetail(BDX, "Transfer complete! Contents written/appended to %s", outFilePath); mTransfer.Reset(); + mIsTransferComplete = false; } break; case TransferSession::OutputEventType::kMsgToSend: { @@ -54,6 +60,10 @@ void BdxDownloader::HandleTransferSessionOutput(TransferSession::OutputEvent & e { sendFlags.Set(chip::Messaging::SendMessageFlags::kFromInitiator); } + if (event.msgTypeData.MessageType != static_cast(MessageType::BlockAckEOF)) + { + sendFlags.Set(chip::Messaging::SendMessageFlags::kExpectResponse); + } err = mExchangeCtx->SendMessage(event.msgTypeData.ProtocolId, event.msgTypeData.MessageType, std::move(event.MsgData), sendFlags); VerifyOrReturn(err == CHIP_NO_ERROR, ChipLogError(BDX, "%s: SendMessage failed: %s", __FUNCTION__, chip::ErrorStr(err))); @@ -66,18 +76,24 @@ void BdxDownloader::HandleTransferSessionOutput(TransferSession::OutputEvent & e case TransferSession::OutputEventType::kBlockReceived: { ChipLogDetail(BDX, "Got block length %zu", event.blockdata.Length); - std::ofstream otaFile("test-ota-out.txt", std::ifstream::out | std::ifstream::ate | std::ifstream::app); + // TODO: something more elegant than appending to a local file + // TODO: while convenient, we should not do a synchronous block write in our example application - this is bad practice + std::ofstream otaFile(outFilePath, std::ifstream::out | std::ifstream::ate | std::ifstream::app); otaFile.write(reinterpret_cast(event.blockdata.Data), event.blockdata.Length); if (event.blockdata.IsEof) { - ReturnOnFailure(mTransfer.PrepareBlockAck()); + err = mTransfer.PrepareBlockAck(); + VerifyOrReturn(err == CHIP_NO_ERROR, + ChipLogError(BDX, "%s: PrepareBlockAck failed: %s", __FUNCTION__, chip::ErrorStr(err))); + mIsTransferComplete = true; } else { - ReturnOnFailure(mTransfer.PrepareBlockQuery()); + err = mTransfer.PrepareBlockQuery(); + VerifyOrReturn(err == CHIP_NO_ERROR, + ChipLogError(BDX, "%s: PrepareBlockQuery failed: %s", __FUNCTION__, chip::ErrorStr(err))); } - otaFile.close(); break; } case TransferSession::OutputEventType::kStatusReceived: @@ -97,6 +113,6 @@ void BdxDownloader::HandleTransferSessionOutput(TransferSession::OutputEvent & e case TransferSession::OutputEventType::kQueryReceived: case TransferSession::OutputEventType::kAckEOFReceived: default: - ChipLogError(BDX, "%s: unsupported event type", __FUNCTION__); + ChipLogError(BDX, "%s: unexpected event type", __FUNCTION__); } } diff --git a/examples/ota-requestor-app/ota-requestor-common/BDXDownloader.h b/examples/ota-requestor-app/ota-requestor-common/BDXDownloader.h index 0fa98438fef194..b948bdc462c73d 100644 --- a/examples/ota-requestor-app/ota-requestor-common/BDXDownloader.h +++ b/examples/ota-requestor-app/ota-requestor-common/BDXDownloader.h @@ -30,4 +30,6 @@ class BdxDownloader : public chip::bdx::Initiator private: // inherited from bdx::Endpoint void HandleTransferSessionOutput(chip::bdx::TransferSession::OutputEvent & event); + + bool mIsTransferComplete = false; }; diff --git a/examples/ota-requestor-app/ota-requestor-common/ota-requestor-app.zap b/examples/ota-requestor-app/ota-requestor-common/ota-requestor-app.zap index 670a0ad9321ebb..dc1adc1ba2f9c0 100644 --- a/examples/ota-requestor-app/ota-requestor-common/ota-requestor-app.zap +++ b/examples/ota-requestor-app/ota-requestor-common/ota-requestor-app.zap @@ -1,5 +1,5 @@ { - "featureLevel": 45, + "featureLevel": 51, "creator": "zap", "keyValuePairs": [ { @@ -1031,8 +1031,8 @@ "bounded": 0, "defaultValue": "1", "reportable": 0, - "minInterval": 0, - "maxInterval": 65344, + "minInterval": 1, + "maxInterval": 65534, "reportableChange": 0 } ] @@ -1074,99 +1074,8 @@ "bounded": 0, "defaultValue": "1", "reportable": 0, - "minInterval": 0, - "maxInterval": 65344, - "reportableChange": 0 - } - ] - }, - { - "name": "OTA Software Update Requestor", - "code": 42, - "mfgCode": null, - "define": "OTA_REQUESTOR_CLUSTER", - "side": "client", - "enabled": 0, - "commands": [ - { - "name": "AnnounceOtaProvider", - "code": 0, - "mfgCode": null, - "source": "client", - "incoming": 1, - "outgoing": 0 - } - ], - "attributes": [ - { - "name": "ClusterRevision", - "code": 65533, - "mfgCode": null, - "side": "client", - "included": 1, - "storageOption": "RAM", - "singleton": 0, - "bounded": 0, - "defaultValue": "1", - "reportable": 0, - "minInterval": 0, - "maxInterval": 65344, - "reportableChange": 0 - } - ] - }, - { - "name": "OTA Software Update Requestor", - "code": 42, - "mfgCode": null, - "define": "OTA_REQUESTOR_CLUSTER", - "side": "server", - "enabled": 1, - "commands": [], - "attributes": [ - { - "name": "default ota provider", - "code": 1, - "mfgCode": null, - "side": "server", - "included": 1, - "storageOption": "RAM", - "singleton": 0, - "bounded": 0, - "defaultValue": "", - "reportable": 0, - "minInterval": 0, - "maxInterval": 65344, - "reportableChange": 0 - }, - { - "name": "update possible", - "code": 2, - "mfgCode": null, - "side": "server", - "included": 1, - "storageOption": "RAM", - "singleton": 0, - "bounded": 0, - "defaultValue": "", - "reportable": 0, - "minInterval": 0, - "maxInterval": 65344, - "reportableChange": 0 - }, - { - "name": "ClusterRevision", - "code": 65533, - "mfgCode": null, - "side": "server", - "included": 1, - "storageOption": "RAM", - "singleton": 0, - "bounded": 0, - "defaultValue": "1", - "reportable": 0, - "minInterval": 0, - "maxInterval": 65344, + "minInterval": 1, + "maxInterval": 65534, "reportableChange": 0 } ] diff --git a/zzz_generated/ota-requestor-app/zap-generated/IMClusterCommandHandler.cpp b/zzz_generated/ota-requestor-app/zap-generated/IMClusterCommandHandler.cpp index a99ae32315426c..3888038afbf35a 100644 --- a/zzz_generated/ota-requestor-app/zap-generated/IMClusterCommandHandler.cpp +++ b/zzz_generated/ota-requestor-app/zap-generated/IMClusterCommandHandler.cpp @@ -245,123 +245,6 @@ void DispatchClientCommand(CommandSender * apCommandObj, CommandId aCommandId, E } // namespace OtaSoftwareUpdateProvider -namespace OtaSoftwareUpdateRequestor { - -void DispatchServerCommand(CommandHandler * apCommandObj, CommandId aCommandId, EndpointId aEndpointId, TLV::TLVReader & aDataTlv) -{ - // We are using TLVUnpackError and TLVError here since both of them can be CHIP_END_OF_TLV - // When TLVError is CHIP_END_OF_TLV, it means we have iterated all of the items, which is not a real error. - // Any error value TLVUnpackError means we have received an illegal value. - // The following variables are used for all commands to save code size. - CHIP_ERROR TLVError = CHIP_NO_ERROR; - CHIP_ERROR TLVUnpackError = CHIP_NO_ERROR; - uint32_t validArgumentCount = 0; - uint32_t expectArgumentCount = 0; - uint32_t currentDecodeTagId = 0; - bool wasHandled = false; - { - switch (aCommandId) - { - case Clusters::OtaSoftwareUpdateRequestor::Commands::Ids::AnnounceOtaProvider: { - expectArgumentCount = 4; - chip::ByteSpan serverLocation; - uint16_t vendorId; - uint8_t announcementReason; - chip::ByteSpan metadataForNode; - bool argExists[4]; - - memset(argExists, 0, sizeof argExists); - - while ((TLVError = aDataTlv.Next()) == CHIP_NO_ERROR) - { - // Since call to aDataTlv.Next() is CHIP_NO_ERROR, the read head always points to an element. - // Skip this element if it is not a ContextTag, not consider it as an error if other values are valid. - if (!TLV::IsContextTag(aDataTlv.GetTag())) - { - continue; - } - currentDecodeTagId = TLV::TagNumFromTag(aDataTlv.GetTag()); - if (currentDecodeTagId < 4) - { - if (argExists[currentDecodeTagId]) - { - ChipLogProgress(Zcl, "Duplicate TLV tag %" PRIx32, TLV::TagNumFromTag(aDataTlv.GetTag())); - TLVUnpackError = CHIP_ERROR_IM_MALFORMED_COMMAND_DATA_ELEMENT; - break; - } - else - { - argExists[currentDecodeTagId] = true; - validArgumentCount++; - } - } - switch (currentDecodeTagId) - { - case 0: - TLVUnpackError = aDataTlv.Get(serverLocation); - break; - case 1: - TLVUnpackError = aDataTlv.Get(vendorId); - break; - case 2: - TLVUnpackError = aDataTlv.Get(announcementReason); - break; - case 3: - TLVUnpackError = aDataTlv.Get(metadataForNode); - break; - default: - // Unsupported tag, ignore it. - ChipLogProgress(Zcl, "Unknown TLV tag during processing."); - break; - } - if (CHIP_NO_ERROR != TLVUnpackError) - { - break; - } - } - - if (CHIP_END_OF_TLV == TLVError) - { - // CHIP_END_OF_TLV means we have iterated all items in the structure, which is not a real error. - TLVError = CHIP_NO_ERROR; - } - - if (CHIP_NO_ERROR == TLVError && CHIP_NO_ERROR == TLVUnpackError && 4 == validArgumentCount) - { - wasHandled = emberAfOtaSoftwareUpdateRequestorClusterAnnounceOtaProviderCallback( - aEndpointId, apCommandObj, serverLocation, vendorId, announcementReason, metadataForNode); - } - break; - } - default: { - // Unrecognized command ID, error status will apply. - ReportCommandUnsupported(apCommandObj, aEndpointId, Clusters::OtaSoftwareUpdateRequestor::Id, aCommandId); - return; - } - } - } - - if (CHIP_NO_ERROR != TLVError || CHIP_NO_ERROR != TLVUnpackError || expectArgumentCount != validArgumentCount || !wasHandled) - { - CommandPathParams returnStatusParam = { aEndpointId, - 0, // GroupId - Clusters::OtaSoftwareUpdateRequestor::Id, aCommandId, - (CommandPathFlags::kEndpointIdValid) }; - apCommandObj->AddStatusCode(returnStatusParam, Protocols::SecureChannel::GeneralStatusCode::kBadRequest, - Protocols::SecureChannel::Id, Protocols::InteractionModel::ProtocolCode::InvalidCommand); - ChipLogProgress(Zcl, - "Failed to dispatch command, %" PRIu32 "/%" PRIu32 " arguments parsed, TLVError=%" CHIP_ERROR_FORMAT - ", UnpackError=%" CHIP_ERROR_FORMAT " (last decoded tag = %" PRIu32, - validArgumentCount, expectArgumentCount, TLVError.Format(), TLVUnpackError.Format(), currentDecodeTagId); - // A command with no arguments would never write currentDecodeTagId. If - // progress logging is also disabled, it would look unused. Silence that - // warning. - UNUSED_VAR(currentDecodeTagId); - } -} - -} // namespace OtaSoftwareUpdateRequestor - } // namespace clusters void DispatchSingleClusterCommand(ClusterId aClusterId, CommandId aCommandId, EndpointId aEndPointId, TLV::TLVReader & aReader, @@ -374,9 +257,6 @@ void DispatchSingleClusterCommand(ClusterId aClusterId, CommandId aCommandId, En SuccessOrExit(aReader.EnterContainer(dataTlvType)); switch (aClusterId) { - case Clusters::OtaSoftwareUpdateRequestor::Id: - clusters::OtaSoftwareUpdateRequestor::DispatchServerCommand(apCommandObj, aCommandId, aEndPointId, aReader); - break; default: // Unrecognized cluster ID, error status will apply. CommandPathParams returnStatusParam = { aEndPointId, diff --git a/zzz_generated/ota-requestor-app/zap-generated/callback-stub.cpp b/zzz_generated/ota-requestor-app/zap-generated/callback-stub.cpp index d254e68094bb83..fcbfa7673b9182 100644 --- a/zzz_generated/ota-requestor-app/zap-generated/callback-stub.cpp +++ b/zzz_generated/ota-requestor-app/zap-generated/callback-stub.cpp @@ -31,9 +31,6 @@ void emberAfClusterInitCallback(EndpointId endpoint, ClusterId clusterId) case ZCL_OTA_PROVIDER_CLUSTER_ID: emberAfOtaSoftwareUpdateProviderClusterInitCallback(endpoint); break; - case ZCL_OTA_REQUESTOR_CLUSTER_ID: - emberAfOtaSoftwareUpdateRequestorClusterInitCallback(endpoint); - break; default: // Unrecognized cluster ID break; @@ -45,11 +42,6 @@ void __attribute__((weak)) emberAfOtaSoftwareUpdateProviderClusterInitCallback(E // To prevent warning (void) endpoint; } -void __attribute__((weak)) emberAfOtaSoftwareUpdateRequestorClusterInitCallback(EndpointId endpoint) -{ - // To prevent warning - (void) endpoint; -} // // Non-Cluster Related Callbacks diff --git a/zzz_generated/ota-requestor-app/zap-generated/endpoint_config.h b/zzz_generated/ota-requestor-app/zap-generated/endpoint_config.h index 5194e30333b9db..5b660114be73f0 100644 --- a/zzz_generated/ota-requestor-app/zap-generated/endpoint_config.h +++ b/zzz_generated/ota-requestor-app/zap-generated/endpoint_config.h @@ -26,26 +26,16 @@ #if BIGENDIAN_CPU #define GENERATED_DEFAULTS \ { \ - \ - /* Endpoint: 1, Cluster: OTA Software Update Requestor (server), big-endian */ \ - \ - /* 0 - default ota provider, */ \ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ } #else // !BIGENDIAN_CPU #define GENERATED_DEFAULTS \ { \ - \ - /* Endpoint: 1, Cluster: OTA Software Update Requestor (server), little-endian */ \ - \ - /* 0 - default ota provider, */ \ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ } #endif // BIGENDIAN_CPU -#define GENERATED_DEFAULTS_COUNT (1) +#define GENERATED_DEFAULTS_COUNT (0) #define ZAP_TYPE(type) ZCL_##type##_ATTRIBUTE_TYPE #define ZAP_LONG_DEFAULTS_INDEX(index) \ @@ -73,18 +63,12 @@ #define ZAP_ATTRIBUTE_MASK(mask) ATTRIBUTE_MASK_##mask // This is an array of EmberAfAttributeMetadata structures. -#define GENERATED_ATTRIBUTE_COUNT 4 +#define GENERATED_ATTRIBUTE_COUNT 1 #define GENERATED_ATTRIBUTES \ { \ \ /* Endpoint: 1, Cluster: OTA Software Update Provider (client) */ \ { 0xFFFD, ZAP_TYPE(INT16U), 2, ZAP_ATTRIBUTE_MASK(CLIENT), ZAP_SIMPLE_DEFAULT(1) }, /* ClusterRevision */ \ - \ - /* Endpoint: 1, Cluster: OTA Software Update Requestor (server) */ \ - { 0x0001, ZAP_TYPE(OCTET_STRING), 17, ZAP_ATTRIBUTE_MASK(WRITABLE), \ - ZAP_LONG_DEFAULTS_INDEX(0) }, /* default ota provider */ \ - { 0x0002, ZAP_TYPE(BOOLEAN), 1, 0, ZAP_EMPTY_DEFAULT() }, /* update possible */ \ - { 0xFFFD, ZAP_TYPE(INT16U), 2, 0, ZAP_SIMPLE_DEFAULT(1) }, /* ClusterRevision */ \ } // This is an array of EmberAfCluster structures. @@ -94,15 +78,12 @@ #define GENERATED_FUNCTION_ARRAYS #define ZAP_CLUSTER_MASK(mask) CLUSTER_MASK_##mask -#define GENERATED_CLUSTER_COUNT 2 +#define GENERATED_CLUSTER_COUNT 1 #define GENERATED_CLUSTERS \ { \ { \ 0x0029, ZAP_ATTRIBUTE_INDEX(0), 1, 2, ZAP_CLUSTER_MASK(CLIENT), NULL \ }, /* Endpoint: 1, Cluster: OTA Software Update Provider (client) */ \ - { \ - 0x002A, ZAP_ATTRIBUTE_INDEX(1), 3, 20, ZAP_CLUSTER_MASK(SERVER), NULL \ - }, /* Endpoint: 1, Cluster: OTA Software Update Requestor (server) */ \ } #define ZAP_CLUSTER_INDEX(index) ((EmberAfCluster *) (&generatedClusters[index])) @@ -110,17 +91,17 @@ // This is an array of EmberAfEndpointType structures. #define GENERATED_ENDPOINT_TYPES \ { \ - { ZAP_CLUSTER_INDEX(0), 2, 22 }, \ + { ZAP_CLUSTER_INDEX(0), 1, 2 }, \ } // Largest attribute size is needed for various buffers -#define ATTRIBUTE_LARGEST (18) +#define ATTRIBUTE_LARGEST (3) // Total size of singleton attributes #define ATTRIBUTE_SINGLETONS_SIZE (0) // Total size of attribute storage -#define ATTRIBUTE_MAX_SIZE (22) +#define ATTRIBUTE_MAX_SIZE (2) // Number of fixed endpoints #define FIXED_ENDPOINT_COUNT (1) @@ -164,7 +145,7 @@ // Array of EmberAfCommandMetadata structs. #define ZAP_COMMAND_MASK(mask) COMMAND_MASK_##mask -#define EMBER_AF_GENERATED_COMMAND_COUNT (6) +#define EMBER_AF_GENERATED_COMMAND_COUNT (5) #define GENERATED_COMMANDS \ { \ \ @@ -174,9 +155,6 @@ { 0x0029, 0x02, ZAP_COMMAND_MASK(INCOMING_SERVER) }, /* NotifyUpdateApplied */ \ { 0x0029, 0x03, ZAP_COMMAND_MASK(INCOMING_CLIENT) }, /* QueryImageResponse */ \ { 0x0029, 0x04, ZAP_COMMAND_MASK(INCOMING_CLIENT) }, /* ApplyUpdateRequestResponse */ \ - \ - /* Endpoint: 1, Cluster: OTA Software Update Requestor (server) */ \ - { 0x002A, 0x00, ZAP_COMMAND_MASK(INCOMING_SERVER) }, /* AnnounceOtaProvider */ \ } // Array of EmberAfManufacturerCodeEntry structures for commands. diff --git a/zzz_generated/ota-requestor-app/zap-generated/gen_config.h b/zzz_generated/ota-requestor-app/zap-generated/gen_config.h index 5b1eeb9f181a50..117fa5171f5a6b 100644 --- a/zzz_generated/ota-requestor-app/zap-generated/gen_config.h +++ b/zzz_generated/ota-requestor-app/zap-generated/gen_config.h @@ -30,15 +30,9 @@ /**** Cluster endpoint counts ****/ #define EMBER_AF_OTA_PROVIDER_CLUSTER_CLIENT_ENDPOINT_COUNT (1) -#define EMBER_AF_OTA_REQUESTOR_CLUSTER_SERVER_ENDPOINT_COUNT (1) /**** Cluster Plugins ****/ // Use this macro to check if the client side of the OTA Software Update Provider cluster is included #define ZCL_USING_OTA_PROVIDER_CLUSTER_CLIENT #define EMBER_AF_PLUGIN_OTA_SOFTWARE_UPDATE_PROVIDER_CLIENT - -// Use this macro to check if the server side of the OTA Software Update Requestor cluster is included -#define ZCL_USING_OTA_REQUESTOR_CLUSTER_SERVER -#define EMBER_AF_PLUGIN_OTA_SOFTWARE_UPDATE_REQUESTOR_SERVER -#define EMBER_AF_PLUGIN_OTA_SOFTWARE_UPDATE_REQUESTOR