From e2bff0d89672994959c8bd562bb63ab08f801abf Mon Sep 17 00:00:00 2001 From: Carol Yang Date: Thu, 7 Oct 2021 21:25:59 -0700 Subject: [PATCH 1/3] Make a QueryImage command from OTA Requestor to OTA Provider * Make ota-provider-app and ota-requestor-app compilable on Mac * Remove self commissioning code from ota-requestor-app * Add a parameter for IP address for OTA Requestor to use for creating secure session * Add a parameter for fabric index for OTA Requestor to use for creating secure session * Add a parameter for time to wait for OTA Requestor to initiate a QueryImage command from startup --- examples/ota-provider-app/linux/README.md | 9 +- .../ota-provider-common/BdxOtaSender.cpp | 2 +- examples/ota-requestor-app/linux/BUILD.gn | 7 +- .../linux/ExampleSelfCommissioning.h | 85 ------ .../linux/PersistentStorage.cpp | 251 ---------------- .../linux/PersistentStorage.h | 54 ---- examples/ota-requestor-app/linux/README.md | 73 +++-- examples/ota-requestor-app/linux/main.cpp | 281 +++++++++--------- .../ota-requestor-common/BDXDownloader.cpp | 2 +- src/app/device/OperationalDeviceProxy.cpp | 11 +- src/app/device/OperationalDeviceProxy.h | 11 - src/controller/CHIPDevice.cpp | 14 + src/controller/CHIPDevice.h | 4 + 13 files changed, 219 insertions(+), 585 deletions(-) delete mode 100644 examples/ota-requestor-app/linux/ExampleSelfCommissioning.h delete mode 100644 examples/ota-requestor-app/linux/PersistentStorage.cpp delete mode 100644 examples/ota-requestor-app/linux/PersistentStorage.h diff --git a/examples/ota-provider-app/linux/README.md b/examples/ota-provider-app/linux/README.md index 85a43080a8a787..819b9d3842cfc7 100644 --- a/examples/ota-provider-app/linux/README.md +++ b/examples/ota-provider-app/linux/README.md @@ -10,12 +10,12 @@ Suggest doing the following: ## Usage -`./ota-provider-app [--filepath \]` +`./ota-provider-app [-f/--filepath \]` -If `-filepath` is provided, `ota-provider-app` will automatically serve that -file to the Requestor (SoftwareVersion will be Requester version + 1). +If `--filepath` is supplied, `ota-provider-app` will automatically serve that +file to the OTA Requestor (SoftwareVersion will be Requester version + 1). -If no `-filepath` is provided, `ota-provider-app` will respond to `QueryImage` +If no `--filepath` is supplied, `ota-provider-app` will respond to `QueryImage` with `NotAvailable` status. ## Current Features/Limitations @@ -31,6 +31,5 @@ with `NotAvailable` status. - Synchronous BDX transfer only - using hardcoded test values for local and peer Node IDs - does not check VID/PID -- no configuration for `Busy`/`DelayedActionTime` - no configuration for `AwaitNextAction` - only one transfer at a time (does not check incoming `UpdateTokens`) diff --git a/examples/ota-provider-app/ota-provider-common/BdxOtaSender.cpp b/examples/ota-provider-app/ota-provider-common/BdxOtaSender.cpp index a867097bd11e2b..256eee033939f3 100644 --- a/examples/ota-provider-app/ota-provider-common/BdxOtaSender.cpp +++ b/examples/ota-provider-app/ota-provider-common/BdxOtaSender.cpp @@ -117,7 +117,7 @@ void BdxOtaSender::HandleTransferSessionOutput(TransferSession::OutputEvent & ev VerifyOrReturn(otaFile.good() || otaFile.eof(), ChipLogError(BDX, "%s: file read failed", __FUNCTION__)); blockData.Data = blockBuf->Start(); - blockData.Length = otaFile.gcount(); + blockData.Length = static_cast(otaFile.gcount()); blockData.IsEof = (blockData.Length < blockSize) || (mNumBytesSent + static_cast(blockData.Length) == mTransfer.GetTransferLength() || (otaFile.peek() == EOF)); mNumBytesSent = static_cast(mNumBytesSent + blockData.Length); diff --git a/examples/ota-requestor-app/linux/BUILD.gn b/examples/ota-requestor-app/linux/BUILD.gn index b02beb704b86e1..72f31fa74dd2d4 100644 --- a/examples/ota-requestor-app/linux/BUILD.gn +++ b/examples/ota-requestor-app/linux/BUILD.gn @@ -16,15 +16,12 @@ import("//build_overrides/build.gni") import("//build_overrides/chip.gni") executable("chip-ota-requestor-app") { - sources = [ - "ExampleSelfCommissioning.h", - "PersistentStorage.cpp", - "main.cpp", - ] + sources = [ "main.cpp" ] deps = [ "${chip_root}/examples/ota-requestor-app/ota-requestor-common", "${chip_root}/examples/platform/linux:app-main", + "${chip_root}/src/app/device", "${chip_root}/src/app/server", "${chip_root}/src/lib", ] diff --git a/examples/ota-requestor-app/linux/ExampleSelfCommissioning.h b/examples/ota-requestor-app/linux/ExampleSelfCommissioning.h deleted file mode 100644 index 99346b7813216c..00000000000000 --- a/examples/ota-requestor-app/linux/ExampleSelfCommissioning.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - * - * 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, uint16_t listenPort) -{ - CHIP_ERROR err = CHIP_NO_ERROR; - chip::Platform::ScopedMemoryBuffer noc; - chip::Platform::ScopedMemoryBuffer icac; - chip::Platform::ScopedMemoryBuffer rcac; - chip::Controller::FactoryInitParams initParams; - chip::Controller::SetupParams setupParams; - - 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); - - setupParams.ephemeralKeypair = &ephemeralKey; - setupParams.controllerRCAC = rcacSpan; - setupParams.controllerICAC = icacSpan; - setupParams.controllerNOC = nocSpan; - setupParams.operationalCredentialsDelegate = opCredsIssuer; - - initParams.storageDelegate = storage; - initParams.listenPort = listenPort; - - auto & factory = chip::Controller::DeviceControllerFactory::GetInstance(); - - err = factory.Init(initParams); - VerifyOrExit(err == CHIP_NO_ERROR, ChipLogError(Controller, "Controller Factory init failure! %s", chip::ErrorStr(err))); - - err = factory.SetupController(setupParams, controller); - 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/PersistentStorage.cpp b/examples/ota-requestor-app/linux/PersistentStorage.cpp deleted file mode 100644 index 3f4a7a5b1a63e9..00000000000000 --- a/examples/ota-requestor-app/linux/PersistentStorage.cpp +++ /dev/null @@ -1,251 +0,0 @@ -/* - * 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 "PersistentStorage.h" - -#include -#include -#include - -#include -#include - -using String = std::basic_string; -using Section = std::map; -using Sections = std::map; - -using namespace ::chip; -using namespace ::chip::Controller; -using namespace ::chip::Logging; - -constexpr const char kFilename[] = "/tmp/chip_tool_config.ini"; -constexpr const char kDefaultSectionName[] = "Default"; -constexpr const char kPortKey[] = "ListenPort"; -constexpr const char kLoggingKey[] = "LoggingLevel"; -constexpr const char kLocalNodeIdKey[] = "LocalNodeId"; -constexpr const char kRemoteNodeIdKey[] = "RemoteNodeId"; -constexpr LogCategory kDefaultLoggingLevel = kLogCategory_Detail; - -namespace { - -std::string StringToBase64(const std::string & value) -{ - std::unique_ptr buffer(new char[BASE64_ENCODED_LEN(value.length())]); - - uint32_t len = - chip::Base64Encode32(reinterpret_cast(value.data()), static_cast(value.length()), buffer.get()); - if (len == UINT32_MAX) - { - return ""; - } - - return std::string(buffer.get(), len); -} - -std::string Base64ToString(const std::string & b64Value) -{ - std::unique_ptr buffer(new uint8_t[BASE64_MAX_DECODED_LEN(b64Value.length())]); - - uint32_t len = chip::Base64Decode32(b64Value.data(), static_cast(b64Value.length()), buffer.get()); - if (len == UINT32_MAX) - { - return ""; - } - - return std::string(reinterpret_cast(buffer.get()), len); -} - -} // namespace - -CHIP_ERROR PersistentStorage::Init() -{ - CHIP_ERROR err = CHIP_NO_ERROR; - - std::ifstream ifs; - ifs.open(kFilename, std::ifstream::in); - if (!ifs.good()) - { - CommitConfig(); - ifs.open(kFilename, std::ifstream::in); - } - VerifyOrExit(ifs.is_open(), err = CHIP_ERROR_OPEN_FAILED); - - mConfig.parse(ifs); - ifs.close(); - -exit: - return err; -} - -CHIP_ERROR PersistentStorage::SyncGetKeyValue(const char * key, void * value, uint16_t & size) -{ - std::string iniValue; - - auto section = mConfig.sections[kDefaultSectionName]; - auto it = section.find(key); - ReturnErrorCodeIf(it == section.end(), CHIP_ERROR_KEY_NOT_FOUND); - - ReturnErrorCodeIf(!inipp::extract(section[key], iniValue), CHIP_ERROR_INVALID_ARGUMENT); - - iniValue = Base64ToString(iniValue); - - uint16_t dataSize = static_cast(iniValue.size()); - if (dataSize > size) - { - size = dataSize; - return CHIP_ERROR_BUFFER_TOO_SMALL; - } - - size = dataSize; - memcpy(value, iniValue.data(), dataSize); - - return CHIP_NO_ERROR; -} - -CHIP_ERROR PersistentStorage::SyncSetKeyValue(const char * key, const void * value, uint16_t size) -{ - auto section = mConfig.sections[kDefaultSectionName]; - section[key] = StringToBase64(std::string(static_cast(value), size)); - - mConfig.sections[kDefaultSectionName] = section; - return CommitConfig(); -} - -CHIP_ERROR PersistentStorage::SyncDeleteKeyValue(const char * key) -{ - auto section = mConfig.sections[kDefaultSectionName]; - section.erase(key); - - mConfig.sections[kDefaultSectionName] = section; - return CommitConfig(); -} - -CHIP_ERROR PersistentStorage::CommitConfig() -{ - CHIP_ERROR err = CHIP_NO_ERROR; - - std::ofstream ofs; - std::string tmpPath = kFilename; - tmpPath.append(".tmp"); - ofs.open(tmpPath, std::ofstream::out | std::ofstream::trunc); - VerifyOrExit(ofs.good(), err = CHIP_ERROR_WRITE_FAILED); - - mConfig.generate(ofs); - ofs.close(); - VerifyOrExit(ofs.good(), err = CHIP_ERROR_WRITE_FAILED); - - VerifyOrExit(rename(tmpPath.c_str(), kFilename) == 0, err = CHIP_ERROR_WRITE_FAILED); - -exit: - return err; -} - -uint16_t PersistentStorage::GetListenPort() -{ - CHIP_ERROR err = CHIP_NO_ERROR; - // By default chip-tool listens on CHIP_PORT + 1. This is done in order to avoid - // having 2 servers listening on CHIP_PORT when one runs an accessory server locally. - uint16_t chipListenPort = CHIP_PORT + 1; - - char value[6]; - uint16_t size = static_cast(sizeof(value)); - err = SyncGetKeyValue(kPortKey, value, size); - if (CHIP_NO_ERROR == err) - { - uint16_t tmpValue; - std::stringstream ss(value); - ss >> tmpValue; - if (!ss.fail() && ss.eof()) - { - chipListenPort = tmpValue; - } - } - - return chipListenPort; -} - -LogCategory PersistentStorage::GetLoggingLevel() -{ - CHIP_ERROR err = CHIP_NO_ERROR; - LogCategory chipLogLevel = kDefaultLoggingLevel; - - char value[9]; - uint16_t size = static_cast(sizeof(value)); - err = SyncGetKeyValue(kLoggingKey, value, size); - if (CHIP_NO_ERROR == err) - { - if (strcasecmp(value, "none") == 0) - { - chipLogLevel = kLogCategory_None; - } - else if (strcasecmp(value, "error") == 0) - { - chipLogLevel = kLogCategory_Error; - } - else if (strcasecmp(value, "progress") == 0) - { - chipLogLevel = kLogCategory_Progress; - } - else if (strcasecmp(value, "detail") == 0) - { - chipLogLevel = kLogCategory_Detail; - } - } - - return chipLogLevel; -} - -NodeId PersistentStorage::GetNodeId(const char * key, NodeId defaultVal) -{ - CHIP_ERROR err = CHIP_NO_ERROR; - - uint64_t nodeId; - uint16_t size = static_cast(sizeof(nodeId)); - err = SyncGetKeyValue(key, &nodeId, size); - if (err == CHIP_NO_ERROR) - { - return static_cast(Encoding::LittleEndian::HostSwap64(nodeId)); - } - - return defaultVal; -} - -NodeId PersistentStorage::GetLocalNodeId() -{ - return GetNodeId(kLocalNodeIdKey, kTestControllerNodeId); -} - -NodeId PersistentStorage::GetRemoteNodeId() -{ - return GetNodeId(kRemoteNodeIdKey, kTestDeviceNodeId); -} - -CHIP_ERROR PersistentStorage::SetNodeId(const char * key, NodeId value) -{ - uint64_t nodeId = Encoding::LittleEndian::HostSwap64(value); - return SyncSetKeyValue(key, &nodeId, sizeof(nodeId)); -} - -CHIP_ERROR PersistentStorage::SetLocalNodeId(NodeId nodeId) -{ - return SetNodeId(kLocalNodeIdKey, nodeId); -} - -CHIP_ERROR PersistentStorage::SetRemoteNodeId(NodeId nodeId) -{ - return SetNodeId(kRemoteNodeIdKey, nodeId); -} diff --git a/examples/ota-requestor-app/linux/PersistentStorage.h b/examples/ota-requestor-app/linux/PersistentStorage.h deleted file mode 100644 index 35cc775f81b8d5..00000000000000 --- a/examples/ota-requestor-app/linux/PersistentStorage.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * 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 - -class PersistentStorage : public chip::PersistentStorageDelegate -{ -public: - CHIP_ERROR Init(); - - /////////// PersistentStorageDelegate Interface ///////// - CHIP_ERROR SyncGetKeyValue(const char * key, void * buffer, uint16_t & size) override; - CHIP_ERROR SyncSetKeyValue(const char * key, const void * value, uint16_t size) override; - CHIP_ERROR SyncDeleteKeyValue(const char * key) override; - - uint16_t GetListenPort(); - chip::Logging::LogCategory GetLoggingLevel(); - - // Return the stored node ids, or the default ones if nothing is stored. - chip::NodeId GetLocalNodeId(); - chip::NodeId GetRemoteNodeId(); - - // Store node ids. - CHIP_ERROR SetLocalNodeId(chip::NodeId nodeId); - CHIP_ERROR SetRemoteNodeId(chip::NodeId nodeId); - -private: - // Helpers for node ids. - chip::NodeId GetNodeId(const char * key, chip::NodeId defaultVal); - CHIP_ERROR SetNodeId(const char * key, chip::NodeId value); - - CHIP_ERROR CommitConfig(); - inipp::Ini mConfig; -}; diff --git a/examples/ota-requestor-app/linux/README.md b/examples/ota-requestor-app/linux/README.md index 738cfd24dc3fbf..eba184e134eb48 100644 --- a/examples/ota-requestor-app/linux/README.md +++ b/examples/ota-requestor-app/linux/README.md @@ -6,28 +6,53 @@ 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. +In order to use this reference application to connect to a device running OTA +Provider server and download a software image, these commands should be called +in the following order: -Therefore, to use this app you should call these commands in the following -order: +In terminal 1: -In one terminal: +``` +./chip-ota-provider-app -f ${SW_IMAGE_FILE} +``` + +- `${SW_IMAGE_FILE}` is the file representing a software image to be served. + +In terminal 2: + +``` +./chip-tool pairing onnetwork ${NODE_ID_TO_ASSIGN_PROVIDER} 20202021 +``` + +- `${NODE_ID_TO_ASSIGN_PROVIDER}` is the node id to assign to the + ota-provider-app running in terminal 1. + +In terminal 3: ``` -./chip-ota-provider-app [-f ] +./chip-ota-requestor-app -d ${REQUESTOR_LONG_DISCRIMINATOR} -u ${REQUESTOR_UDP_PORT} -i ${PROVIDER_IP_ADDRESS} -n ${PROVIDER_NODE_ID} -q ${DELAY_QUERY_SECONDS} ``` -In a second terminal: +- `{REQUESTOR_LONG_DISCRIMINATOR}` is the long discriminator specified for the + ota-requestor-app for commissioning discovery +- `{REQUESTOR_UDP_PORT}` is the UDP port that the ota-requestor-app listens on + for secure connections +- `${PROVIDER_IP_ADDRESS}` is the IP address of the ota-provider-app that has + been resolved manually +- `${PROVIDER_NODE_ID}` is the node ID of the ota-provider-app assigned above +- `${DELAY_QUERY_SECONDS}` is the amount of time in seconds to wait before + initiating secure session establishment and query for software image + +In terminal 2: ``` -./chip-tool pairing onnetwork-long ${NODE_ID_TO_ASSIGN} 20202021 3840 -./chip-ota-requestor-app [-p ] +./chip-tool pairing onnetwork-long ${NODE_ID_TO_ASSIGN_REQUESTOR} 20202021 ${REQUESTOR_LONG_DISCRIMINATOR} ``` -where `${NODE_ID_TO_ASSIGN}` is the node id to assign to the provider app, which -should match the `-p` argument passed to `chip-ota-requestor-app`. +- `${NODE_ID_TO_ASSIGN_REQUESTOR}` is the node id to assign to the + ota-requestor-app running in terminal 3 +- `${REQUESTOR_LONG_DISCRIMINATOR}` is the long discriminator of the + ota-requestor-app specified in terminal 3 above ## Current Features / Limitations @@ -35,21 +60,15 @@ should match the `-p` argument passed to `chip-ota-requestor-app`. - Code for running a full BDX download exists in BDX - Sends QueryImage command -- Takes a peer Node ID as an argument -- Takes an optional udpPort command argument which when present disables the - self-commissioning and automatic image download logic and instead makes the - Requestor initialize like a standard Matter application. The udpPort - parameter specifies the UDP Port that the Requestor listens on for secure - connections -- Takes an optional discriminator command argument to specify the Setup - Discriminator. When the parameter is omitted the value of 3840 is used +- Downloads a file over BDX served by an OTA Provider server +- Supports various command line configurations ### 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 -- 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 -- does not support AnnounceOTAProvider command or OTA Requestor attributes +- Needs chip-tool to pair to the OTA Provider device first because the Node ID + and IP Address of the OTA Provider can must be supplied to this reference + application +- Does not verify QueryImageResponse message contents +- Stores the downloaded file at a hardcoded filepath +- Does not close the BDX ExchangeContext when the exchange is over +- 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 857294fa859294..ff8e59f38d1965 100644 --- a/examples/ota-requestor-app/linux/main.cpp +++ b/examples/ota-requestor-app/linux/main.cpp @@ -16,59 +16,98 @@ * 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 #include "BDXDownloader.h" -#include "ExampleSelfCommissioning.h" -#include "PersistentStorage.h" - -#include -#include using chip::ByteSpan; using chip::CharSpan; using chip::EndpointId; +using chip::FabricIndex; +using chip::NodeId; +using chip::Server; 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; +using chip::Inet::IPAddress; +using chip::System::Layer; +using chip::Transport::PeerAddress; +using namespace chip::ArgParser; +using namespace chip::Messaging; +using namespace chip::app::device; + +void OnQueryImageResponse(void * context, uint8_t status, uint32_t delayedActionTime, CharSpan imageURI, uint32_t softwareVersion, + CharSpan softwareVersionString, ByteSpan updateToken, bool userConsentNeeded, + ByteSpan metadataForRequestor); +void OnQueryImageFailure(void * context, uint8_t status); +void OnConnected(void * context, OperationalDeviceProxy * operationalDeviceProxy); +void OnConnectionFailure(void * context, OperationalDeviceProxy * operationalDeviceProxy, CHIP_ERROR error); +bool HandleOptions(const char * aProgram, OptionSet * aOptions, int aIdentifier, const char * aName, const char * aValue); // TODO: would be nicer to encapsulate these globals and the callbacks in some sort of class -chip::Messaging::ExchangeContext * exchangeCtx = nullptr; -Device * providerDevice = nullptr; +OperationalDeviceProxy gOperationalDeviceProxy; +ExchangeContext * exchangeCtx = nullptr; BdxDownloader bdxDownloader; +Callback mQueryImageResponseCallback(OnQueryImageResponse, nullptr); +Callback mOnQueryFailureCallback(OnQueryImageFailure, nullptr); +Callback mOnConnectedCallback(OnConnected, nullptr); +Callback mOnConnectionFailureCallback(OnConnectionFailure, nullptr); + +constexpr uint16_t kOptionProviderNodeId = 'n'; +constexpr uint16_t kOptionProviderFabricIndex = 'f'; +constexpr uint16_t kOptionUdpPort = 'u'; +constexpr uint16_t kOptionDiscriminator = 'd'; +constexpr uint16_t kOptionIPAddress = 'i'; +constexpr uint16_t kOptionDelayQuery = 'q'; + +const char * ipAddress = NULL; +NodeId providerNodeId = 0x0; +FabricIndex providerFabricIndex = 1; +uint16_t requestorSecurePort = 0; +uint16_t setupDiscriminator = CHIP_DEVICE_CONFIG_USE_TEST_SETUP_DISCRIMINATOR; +uint16_t delayQueryTimeInSec = 0; + +OptionDef cmdLineOptionsDef[] = { + { "providerNodeId", chip::ArgParser::kArgumentRequired, kOptionProviderNodeId }, + { "providerFabricIndex", chip::ArgParser::kArgumentRequired, kOptionProviderFabricIndex }, + { "udpPort", chip::ArgParser::kArgumentRequired, kOptionUdpPort }, + { "discriminator", chip::ArgParser::kArgumentRequired, kOptionDiscriminator }, + { "ipaddress", chip::ArgParser::kArgumentRequired, kOptionIPAddress }, + { "delayQuery", chip::ArgParser::kArgumentRequired, kOptionDelayQuery }, + {}, +}; + +OptionSet cmdLineOptions = { HandleOptions, cmdLineOptionsDef, "PROGRAM OPTIONS", + " -n/--providerNodeId \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" + " -f/--providerFabricIndex \n" + " Fabric index of the OTA Provider to connect to. If none is specified, default value is 1.\n\n" + " This assumes that you've already commissioned the OTA Provider node with chip-tool.\n" + " -u/--udpPort \n" + " UDP Port that the OTA Requestor listens on for secure connections.\n" + " -d/--discriminator \n" + " A 12-bit value used to discern between multiple commissionable CHIP device\n" + " advertisements. If none is specified, default value is 3840.\n" + " -i/--ipaddress \n" + " The IP Address of the OTA Provider to connect to. This value must be supplied.\n" + " -q/--delayQuery