Skip to content

Commit

Permalink
ota-provider: cli options for software version, setup discriminator, …
Browse files Browse the repository at this point in the history
…and UserConsentNeeded fields (#14619)

* Darwin: Support for setting setup pincode

* ota-provider: cli options for software version, discriminator, passcode

* Address review comments

* Way to respond with different UserConsentNeeded field values

* Update examples/ota-provider-app/linux/main.cpp

Co-authored-by: Carol Yang <clyang@apple.com>

* Remove passcode setting and use strtoul for converting string to
unsigned integers

Co-authored-by: Carol Yang <clyang@apple.com>
  • Loading branch information
2 people authored and pull[bot] committed Feb 13, 2024
1 parent 68e4560 commit 3313361
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 12 deletions.
75 changes: 67 additions & 8 deletions examples/ota-provider-app/linux/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,15 +53,23 @@ constexpr chip::EndpointId kOtaProviderEndpoint = 0;
constexpr uint16_t kOptionFilepath = 'f';
constexpr uint16_t kOptionOtaImageList = 'o';
constexpr uint16_t kOptionQueryImageBehavior = 'q';
constexpr uint16_t kOptionDelayedActionTimeSec = 'd';
constexpr uint16_t kOptionUserConsent = 'u';
constexpr uint16_t kOptionUserConsentState = 'u';
constexpr uint16_t kOptionDelayedActionTimeSec = 't';
constexpr uint16_t kOptionDiscriminator = 'd';
constexpr uint16_t kOptionSoftwareVersion = 's';
constexpr uint16_t kOptionUserConsentNeeded = 'c';

static constexpr uint16_t kMaximumDiscriminatorValue = 0xFFF;

// Global variables used for passing the CLI arguments to the OTAProviderExample object
static OTAProviderExample::QueryImageBehaviorType gQueryImageBehavior = OTAProviderExample::kRespondWithUnknown;
static uint32_t gDelayedActionTimeSec = 0;
static const char * gOtaFilepath = nullptr;
static const char * gOtaImageListFilepath = nullptr;
static chip::ota::UserConsentState gUserConsentState = chip::ota::UserConsentState::kUnknown;
static bool gUserConsentNeeded = false;
static chip::Optional<uint16_t> gSetupDiscriminator;
static chip::Optional<uint32_t> gSoftwareVersion;

// Parses the JSON filepath and extracts DeviceSoftwareVersionModel parameters
static bool ParseJsonFileAndPopulateCandidates(const char * filepath,
Expand Down Expand Up @@ -183,9 +191,9 @@ bool HandleOptions(const char * aProgram, OptionSet * aOptions, int aIdentifier,
}
break;
case kOptionDelayedActionTimeSec:
gDelayedActionTimeSec = static_cast<uint32_t>(strtol(aValue, NULL, 0));
gDelayedActionTimeSec = static_cast<uint32_t>(strtoul(aValue, NULL, 0));
break;
case kOptionUserConsent:
case kOptionUserConsentState:
if (aValue == NULL)
{
PrintArgError("%s: ERROR: NULL UserConsent parameter\n", aProgram);
Expand All @@ -209,6 +217,22 @@ bool HandleOptions(const char * aProgram, OptionSet * aOptions, int aIdentifier,
retval = false;
}
break;
case kOptionDiscriminator: {
uint16_t discriminator = static_cast<uint16_t>(strtoul(aValue, NULL, 0));
if (discriminator > kMaximumDiscriminatorValue)
{
PrintArgError("%s: Input ERROR: setupDiscriminator value %s is out of range \n", aProgram, aValue);
retval = false;
}
gSetupDiscriminator.SetValue(discriminator);
break;
}
case kOptionSoftwareVersion:
gSoftwareVersion.SetValue(static_cast<uint32_t>(strtoul(aValue, NULL, 0)));
break;
case kOptionUserConsentNeeded:
gUserConsentNeeded = true;
break;
default:
PrintArgError("%s: INTERNAL ERROR: Unhandled option: %s\n", aProgram, aName);
retval = false;
Expand All @@ -223,7 +247,10 @@ OptionDef cmdLineOptionsDef[] = {
{ "otaImageList", chip::ArgParser::kArgumentRequired, kOptionOtaImageList },
{ "QueryImageBehavior", chip::ArgParser::kArgumentRequired, kOptionQueryImageBehavior },
{ "DelayedActionTimeSec", chip::ArgParser::kArgumentRequired, kOptionDelayedActionTimeSec },
{ "UserConsent", chip::ArgParser::kArgumentRequired, kOptionUserConsent },
{ "UserConsentState", chip::ArgParser::kArgumentRequired, kOptionUserConsentState },
{ "discriminator", chip::ArgParser::kArgumentRequired, kOptionDiscriminator },
{ "softwareVersion", chip::ArgParser::kArgumentRequired, kOptionSoftwareVersion },
{ "UserConsentNeeded", chip::ArgParser::kNoArgument, kOptionUserConsentNeeded },
{},
};

Expand All @@ -234,14 +261,24 @@ OptionSet cmdLineOptions = { HandleOptions, cmdLineOptionsDef, "PROGRAM OPTIONS"
" Path to a file containing a list of OTA images.\n"
" -q/--QueryImageBehavior <UpdateAvailable | Busy | UpdateNotAvailable>\n"
" Status value in the Query Image Response\n"
" -d/--DelayedActionTimeSec <time>\n"
" -t/--DelayedActionTimeSec <time>\n"
" Value in seconds for the DelayedActionTime in the Query Image Response\n"
" and Apply Update Response\n"
" -u/--UserConsent <granted | denied | deferred>\n"
" -u/--UserConsentState <granted | denied | deferred>\n"
" granted: Status value in QueryImageResponse is set to UpdateAvailable\n"
" denied: Status value in QueryImageResponse is set to UpdateNotAvailable\n"
" deferred: Status value in QueryImageResponse is set to Busy\n"
" -q/--QueryImageBehavior overrides this option\n" };
" -q/--QueryImageBehavior overrides this option\n"
" -d/--discriminator <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"
" -s/--softwareVersion <version>\n"
" Value of SoftwareVersion in the Query Image Response\n"
" If ota image list is present along with this option\n"
" then value from ota image list is used.\n"
" Otherwise, this value will be used is then value from that will be used\n"
" -c/--UserConsentNeeded\n"
" If provided, value of UserConsentNeeded in the Query Image Response is set to true\n" };

HelpOptions helpOptions("ota-provider-app", "Usage: ota-provider-app [options]", "1.0");

Expand Down Expand Up @@ -271,6 +308,19 @@ int main(int argc, char * argv[])
}

chip::DeviceLayer::ConfigurationMgr().LogDeviceConfig();

if (gSetupDiscriminator.HasValue())
{
// Set discriminator to user specified value
ChipLogProgress(SoftwareUpdate, "Setting discriminator to: %" PRIu16, gSetupDiscriminator.Value());
err = chip::DeviceLayer::ConfigurationMgr().StoreSetupDiscriminator(gSetupDiscriminator.Value());
if (err != CHIP_NO_ERROR)
{
ChipLogError(SoftwareUpdate, "Setup discriminator setting failed with code: %" CHIP_ERROR_FORMAT, err.Format());
return 1;
}
}

chip::Server::GetInstance().Init();

// Initialize device attestation config
Expand All @@ -295,13 +345,22 @@ int main(int argc, char * argv[])

otaProvider.SetQueryImageBehavior(gQueryImageBehavior);
otaProvider.SetDelayedActionTimeSec(gDelayedActionTimeSec);
if (gSoftwareVersion.HasValue())
{
otaProvider.SetSoftwareVersion(gSoftwareVersion.Value());
}

if (gUserConsentState != chip::ota::UserConsentState::kUnknown)
{
userConsentProvider.SetGlobalUserConsentState(gUserConsentState);
otaProvider.SetUserConsentDelegate(&userConsentProvider);
}

if (gUserConsentNeeded)
{
otaProvider.SetUserConsentNeeded(true);
}

ChipLogDetail(SoftwareUpdate, "Using ImageList file: %s", gOtaImageListFilepath ? gOtaImageListFilepath : "(none)");

if (gOtaImageListFilepath != nullptr)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -171,8 +171,15 @@ EmberAfStatus OTAProviderExample::HandleQueryImage(chip::app::CommandHandler * c
if (strlen(mOTAFilePath) > 0) // If OTA file is directly provided
{
// TODO: Following details shall be read from the OTA file
newSoftwareVersion = commandData.softwareVersion + 1; // This implementation will always indicate that an update is
// available (if the user provides a file).

// If software version is provided using command line then use it.
// Otherwise, bump the software version received in QueryImage by 1.
newSoftwareVersion = commandData.softwareVersion + 1;
if (mSoftwareVersion.HasValue())
{
newSoftwareVersion = mSoftwareVersion.Value();
}

newSoftwareVersionString = "Example-Image-V0.1";
otaFilePath = mOTAFilePath;
queryStatus = OTAQueryStatus::kUpdateAvailable;
Expand Down Expand Up @@ -270,8 +277,14 @@ EmberAfStatus OTAProviderExample::HandleQueryImage(chip::app::CommandHandler * c

response.status = queryStatus;
response.delayedActionTime.Emplace(delayedActionTimeSec);
response.userConsentNeeded.Emplace(requestorCanConsent);

if (mUserConsentNeeded)
{
response.userConsentNeeded.Emplace(mUserConsentNeeded);
}
else
{
response.userConsentNeeded.Emplace(requestorCanConsent);
}
// For test coverage, sending empty metadata when (requestorNodeId % 2) == 0 and not sending otherwise.
if (commandObj->GetSubjectDescriptor().subject % 2 == 0)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ class OTAProviderExample : public chip::app::Clusters::OTAProviderDelegate
void SetQueryImageBehavior(QueryImageBehaviorType behavior) { mQueryImageBehavior = behavior; }
void SetDelayedActionTimeSec(uint32_t time) { mDelayedActionTimeSec = time; }
void SetUserConsentDelegate(chip::ota::UserConsentDelegate * delegate) { mUserConsentDelegate = delegate; }
void SetSoftwareVersion(uint32_t softwareVersion) { mSoftwareVersion.SetValue(softwareVersion); }
void SetUserConsentNeeded(bool needed) { mUserConsentNeeded = needed; }

private:
BdxOtaSender mBdxOtaSender;
Expand All @@ -88,4 +90,6 @@ class OTAProviderExample : public chip::app::Clusters::OTAProviderDelegate
GetUserConsentSubject(const chip::app::CommandHandler * commandObj, const chip::app::ConcreteCommandPath & commandPath,
const chip::app::Clusters::OtaSoftwareUpdateProvider::Commands::QueryImage::DecodableType & commandData,
uint32_t targetVersion);
chip::Optional<uint32_t> mSoftwareVersion;
bool mUserConsentNeeded = false;
};

0 comments on commit 3313361

Please sign in to comment.