Skip to content

Commit

Permalink
Update OTAProviderExample with flexible-image selection logic (#13890)
Browse files Browse the repository at this point in the history
* Update OTAProviderExample with flexible-image selection logic

* Replaced input file format from CSV to JSON

* Restyled by gn

* Restyled by prettier-markdown

* Review comments

* Restyled by clang-format

* Fix Darwin build

Co-authored-by: Restyled.io <commits@restyled.io>
  • Loading branch information
2 people authored and pull[bot] committed Jan 25, 2024
1 parent 5caba6f commit 7c64346
Show file tree
Hide file tree
Showing 6 changed files with 234 additions and 25 deletions.
8 changes: 8 additions & 0 deletions .github/.wordlist.txt
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ CCMP
CCS
CCSTUDIO
CCXML
CDVersionNumber
ced
cfg
CFLAGS
Expand Down Expand Up @@ -267,6 +268,7 @@ DBUILD
dbus
dcc
DCHIP
DCL
DCMAKE
DCONFIG
debianutils
Expand All @@ -291,6 +293,7 @@ DeviceLayer
DeviceNetworkProvisioningDelegate
DeviceNetworkProvisioningDelegateImpl
DevicePairingDelegate
deviceSoftwareVersionModel
DevKitC
DevKitM
df
Expand Down Expand Up @@ -605,6 +608,7 @@ MatterLock
matterSdkSourceBuild
matterSourceBuildAbiFilters
matterUTestLib
maxApplicableSoftwareVersion
MaxInterval
MaxIntervalCeilingSeconds
MaxRtrAdvInterval
Expand Down Expand Up @@ -640,6 +644,7 @@ microcontroller
microcontrollers
MicroSD
middleware
minApplicableSoftwareVersion
Minicom
MinInterval
MinIntervalFloorSeconds
Expand Down Expand Up @@ -729,6 +734,7 @@ optionsOverride
orgs
OTA
OTADownloader
otaImageList
OTAImageProcessorDriver
OTAImageProcessorInterface
OTAProvider
Expand All @@ -740,6 +746,7 @@ OTARequestor
OTARequestorDriver
OTARequestorSerialPort
otasoftwareupdaterequestor
otaURL
OTBR
otcli
PAA
Expand Down Expand Up @@ -929,6 +936,7 @@ softmmu
SoftwareDiagnostics
SoftwareVersion
SoftwareVersionString
softwareVersionValid
SPI
spinel
src
Expand Down
1 change: 1 addition & 0 deletions examples/ota-provider-app/linux/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ executable("chip-ota-provider-app") {
"${chip_root}/src/app/server",
"${chip_root}/src/lib",
"${chip_root}/src/protocols/bdx",
"${chip_root}/third_party/jsoncpp",
]

cflags = [ "-Wconversion" ]
Expand Down
32 changes: 29 additions & 3 deletions examples/ota-provider-app/linux/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,39 @@ Suggest doing the following:

## Usage

`./ota-provider-app [-f/--filepath \<file\>]`
`./ota-provider-app [-f/--filepath \<file\>] [-o/--otaImageList \<file\>]`

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 supplied, `ota-provider-app` will respond to `QueryImage`
with `NotAvailable` status.
If `--otaImageList` is supplied, `ota-provider-app` will parse the JSON file and
extract all required data. Then the most recent, valid software version will be
selected and the corresponding ota-file will be sent to the OTA Requestor.

Here's an example of the otaImageList file contents:

{ "foo": 1, // ignored by parser "deviceSoftwareVersionModel": [ { "vendorId":
1, "productId": 1, "softwareVersion": 10, "softwareVersionString": "1.0.0",
"cDVersionNumber": 18, "softwareVersionValid": true,
"minApplicableSoftwareVersion": 0, "maxApplicableSoftwareVersion": 100,
"otaURL": "/tmp/ota.txt" }, { "vendorId": 1, "productId": 1, "softwareVersion":
20, "softwareVersionString": "1.0.1", "cDVersionNumber": 18,
"softwareVersionValid": false, "minApplicableSoftwareVersion": 0,
"maxApplicableSoftwareVersion": 100, "otaURL": "/tmp/ota.txt" }, { "vendorId":
1, "productId": 1, "softwareVersion": 30, "softwareVersionString": "1.0.2",
"cDVersionNumber": 18, "softwareVersionValid": true,
"minApplicableSoftwareVersion": 0, "maxApplicableSoftwareVersion": 100,
"otaURL": "/tmp/ota.txt" }, { "vendorId": 1, "productId": 1, "softwareVersion":
40, "softwareVersionString": "1.1.0", "cDVersionNumber": 18,
"softwareVersionValid": true, "minApplicableSoftwareVersion": 0,
"maxApplicableSoftwareVersion": 100, "otaURL": "/tmp/ota.txt" }, { "vendorId":
1, "productId": 1, "softwareVersion": 50, "softwareVersionString": "1.1.1",
"cDVersionNumber": 18, "softwareVersionValid": false,
"minApplicableSoftwareVersion": 0, "maxApplicableSoftwareVersion": 100,
"otaURL": "/tmp/ota.txt" } ] }

If neither `--filepath` nor `--otaImageList` are supplied, `ota-provider-app`
will respond to `QueryImage` with `NotAvailable` status.

## Current Features/Limitations

Expand Down
100 changes: 97 additions & 3 deletions examples/ota-provider-app/linux/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include <app/util/util.h>
#include <credentials/DeviceAttestationCredsProvider.h>
#include <credentials/examples/DeviceAttestationCredsExample.h>
#include <json/json.h>
#include <lib/core/CHIPError.h>
#include <lib/support/CHIPArgParser.hpp>
#include <lib/support/CHIPMem.h>
Expand All @@ -50,31 +51,111 @@ using chip::Messaging::ExchangeManager;
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';

// Global variables used for passing the CLI arguments to the OTAProviderExample object
OTAProviderExample::QueryImageBehaviorType gQueryImageBehavior = OTAProviderExample::kRespondWithUpdateAvailable;
uint32_t gDelayedActionTimeSec = 0;
const char * gOtaFilepath = nullptr;
static OTAProviderExample::QueryImageBehaviorType gQueryImageBehavior = OTAProviderExample::kRespondWithUpdateAvailable;
static uint32_t gDelayedActionTimeSec = 0;
static const char * gOtaFilepath = nullptr;
static const char * gOtaImageListFilepath = nullptr;

// Parses the JSON filepath and extracts DeviceSoftwareVersionModel parameters
static bool ParseJsonFileAndPopulateCandidates(const char * filepath,
std::vector<OTAProviderExample::DeviceSoftwareVersionModel> & candidates)
{
bool ret = false;
Json::Value root;
Json::CharReaderBuilder builder;
JSONCPP_STRING errs;
std::ifstream ifs;

builder["collectComments"] = true; // allow C/C++ type comments in JSON file
ifs.open(filepath);

if (!ifs.good())
{
ChipLogError(SoftwareUpdate, "Error opening ifstream with file: \"%s\"", filepath);
return ret;
}

if (!parseFromStream(builder, ifs, &root, &errs))
{
ChipLogError(SoftwareUpdate, "Error parsing JSON from file: \"%s\"", filepath);
return ret;
}

const Json::Value devSofVerModValue = root["deviceSoftwareVersionModel"];
if (!devSofVerModValue || !devSofVerModValue.isArray())
{
ChipLogError(SoftwareUpdate, "Error: Key deviceSoftwareVersionModel not found or its value is not of type Array");
}
else
{
for (auto iter : devSofVerModValue)
{
OTAProviderExample::DeviceSoftwareVersionModel candidate;
candidate.vendorId = static_cast<chip::VendorId>(iter.get("vendorId", 1).asUInt());
candidate.productId = static_cast<uint16_t>(iter.get("productId", 1).asUInt());
candidate.softwareVersion = static_cast<uint32_t>(iter.get("softwareVersion", 10).asUInt64());
strncpy(candidate.softwareVersionString, iter.get("softwareVersionString", "1.0.0").asCString(),
OTAProviderExample::SW_VER_STR_MAX_LEN);
candidate.cDVersionNumber = static_cast<uint16_t>(iter.get("cDVersionNumber", 0).asUInt());
candidate.softwareVersionValid = iter.get("softwareVersionValid", true).asBool() ? true : false;
candidate.minApplicableSoftwareVersion = static_cast<uint32_t>(iter.get("minApplicableSoftwareVersion", 0).asUInt64());
candidate.maxApplicableSoftwareVersion =
static_cast<uint32_t>(iter.get("maxApplicableSoftwareVersion", 1000).asUInt64());
strncpy(candidate.otaURL, iter.get("otaURL", "https://test.com").asCString(), OTAProviderExample::OTA_URL_MAX_LEN);
candidates.push_back(candidate);
ret = true;
}
}
return ret;
}

bool HandleOptions(const char * aProgram, OptionSet * aOptions, int aIdentifier, const char * aName, const char * aValue)
{
bool retval = true;
static bool kOptionFilepathSelected;
static bool kOptionOtaImageListSelected;

switch (aIdentifier)
{
case kOptionFilepath:
kOptionFilepathSelected = true;
if (0 != access(aValue, R_OK))
{
PrintArgError("%s: not permitted to read %s\n", aProgram, aValue);
retval = false;
}
else if (kOptionOtaImageListSelected)
{
PrintArgError("%s: Cannot have both OptionOtaImageList and kOptionOtaFilepath \n", aProgram);
retval = false;
}
else
{
gOtaFilepath = aValue;
}
break;
case kOptionOtaImageList:
kOptionOtaImageListSelected = true;
if (0 != access(aValue, R_OK))
{
PrintArgError("%s: not permitted to read %s\n", aProgram, aValue);
retval = false;
}
else if (kOptionFilepathSelected)
{
PrintArgError("%s: Cannot have both OptionOtaImageList and kOptionOtaFilepath \n", aProgram);
retval = false;
}
else
{
gOtaImageListFilepath = aValue;
}
break;
case kOptionQueryImageBehavior:
if (aValue == NULL)
{
Expand Down Expand Up @@ -113,6 +194,7 @@ bool HandleOptions(const char * aProgram, OptionSet * aOptions, int aIdentifier,

OptionDef cmdLineOptionsDef[] = {
{ "filepath", chip::ArgParser::kArgumentRequired, kOptionFilepath },
{ "otaImageList", chip::ArgParser::kArgumentRequired, kOptionOtaImageList },
{ "QueryImageBehavior", chip::ArgParser::kArgumentRequired, kOptionQueryImageBehavior },
{ "DelayedActionTimeSec", chip::ArgParser::kArgumentRequired, kOptionDelayedActionTimeSec },
{},
Expand All @@ -121,6 +203,8 @@ OptionDef cmdLineOptionsDef[] = {
OptionSet cmdLineOptions = { HandleOptions, cmdLineOptionsDef, "PROGRAM OPTIONS",
" -f/--filepath <file>\n"
" Path to a file containing an OTA image.\n"
" -o/--otaImageList <file>\n"
" 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"
Expand Down Expand Up @@ -179,6 +263,16 @@ int main(int argc, char * argv[])
otaProvider.SetQueryImageBehavior(gQueryImageBehavior);
otaProvider.SetDelayedActionTimeSec(gDelayedActionTimeSec);

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

if (gOtaImageListFilepath != nullptr)
{
// Parse JSON file and load the ota candidates
std::vector<OTAProviderExample::DeviceSoftwareVersionModel> candidates;
ParseJsonFileAndPopulateCandidates(gOtaImageListFilepath, candidates);
otaProvider.SetOTACandidates(candidates);
}

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

chip::DeviceLayer::PlatformMgr().RunEventLoop();
Expand Down
Loading

0 comments on commit 7c64346

Please sign in to comment.