blob: 0b254f5d13e86e94a3aa917a02e39d058576ece3 [file] [log] [blame]
/*
*
* Copyright (c) 2022 Project CHIP Authors
*
* 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 "OTAHelper.h"
#include <app/clusters/ota-requestor/BDXDownloader.h>
#include <app/clusters/ota-requestor/DefaultOTARequestor.h>
#include <app/clusters/ota-requestor/DefaultOTARequestorStorage.h>
#include <app/clusters/ota-requestor/ExtendedOTARequestorDriver.h>
#include <platform/ESP32/OTAImageProcessorImpl.h>
#include <system/SystemEvent.h>
#include <app/clusters/ota-requestor/DefaultOTARequestorUserConsent.h>
#include <lib/shell/Commands.h>
#include <lib/shell/Engine.h>
#include <lib/shell/commands/Help.h>
#include <lib/support/logging/CHIPLogging.h>
using namespace chip::DeviceLayer;
using namespace chip;
class CustomOTARequestorDriver : public DeviceLayer::ExtendedOTARequestorDriver
{
public:
bool CanConsent() override;
};
namespace {
DefaultOTARequestor gRequestorCore;
DefaultOTARequestorStorage gRequestorStorage;
CustomOTARequestorDriver gRequestorUser;
BDXDownloader gDownloader;
OTAImageProcessorImpl gImageProcessor;
chip::Optional<bool> gRequestorCanConsent;
static chip::ota::UserConsentState gUserConsentState = chip::ota::UserConsentState::kUnknown;
chip::ota::DefaultOTARequestorUserConsent gUserConsentProvider;
// WARNING: This is just an example for using key for decrypting the encrypted OTA image
// Please do not use it as is for production use cases
#if CONFIG_ENABLE_ENCRYPTED_OTA
extern const char sOTADecryptionKeyStart[] asm("_binary_esp_image_encryption_key_pem_start");
extern const char sOTADecryptionKeyEnd[] asm("_binary_esp_image_encryption_key_pem_end");
CharSpan sOTADecryptionKey(sOTADecryptionKeyStart, sOTADecryptionKeyEnd - sOTADecryptionKeyStart);
#endif // CONFIG_ENABLE_ENCRYPTED_OTA
} // namespace
bool CustomOTARequestorDriver::CanConsent()
{
return gRequestorCanConsent.ValueOr(DeviceLayer::ExtendedOTARequestorDriver::CanConsent());
}
void OTAHelpers::InitOTARequestor()
{
if (!GetRequestorInstance())
{
SetRequestorInstance(&gRequestorCore);
gRequestorStorage.Init(Server::GetInstance().GetPersistentStorage());
gRequestorCore.Init(Server::GetInstance(), gRequestorStorage, gRequestorUser, gDownloader);
gImageProcessor.SetOTADownloader(&gDownloader);
gDownloader.SetImageProcessorDelegate(&gImageProcessor);
gRequestorUser.Init(&gRequestorCore, &gImageProcessor);
#if CONFIG_ENABLE_ENCRYPTED_OTA
gImageProcessor.InitEncryptedOTA(sOTADecryptionKey);
#endif // CONFIG_ENABLE_ENCRYPTED_OTA
if (gUserConsentState != chip::ota::UserConsentState::kUnknown)
{
gUserConsentProvider.SetUserConsentState(gUserConsentState);
gRequestorUser.SetUserConsentDelegate(&gUserConsentProvider);
}
}
}
namespace chip {
namespace Shell {
namespace {
Shell::Engine sSubShell;
CHIP_ERROR UserConsentStateHandler(int argc, char ** argv)
{
VerifyOrReturnError(argc == 1, CHIP_ERROR_INVALID_ARGUMENT);
if (strcmp(argv[0], "granted") == 0)
{
gUserConsentState = chip::ota::UserConsentState::kGranted;
}
else if (strcmp(argv[0], "denied") == 0)
{
gUserConsentState = chip::ota::UserConsentState::kDenied;
}
else if (strcmp(argv[0], "deferred") == 0)
{
gUserConsentState = chip::ota::UserConsentState::kObtaining;
}
return CHIP_NO_ERROR;
}
CHIP_ERROR RequestorCanConsentHandler(int argc, char ** argv)
{
VerifyOrReturnError(argc == 1, CHIP_ERROR_INVALID_ARGUMENT);
if (strcmp(argv[0], "true") == 0)
{
gRequestorCanConsent.SetValue(true);
}
else if (strcmp(argv[0], "false") == 0)
{
gRequestorCanConsent.SetValue(false);
}
return CHIP_NO_ERROR;
}
CHIP_ERROR SetPeriodicQueryTimeoutHandler(int argc, char ** argv)
{
VerifyOrReturnError(argc == 1, CHIP_ERROR_INVALID_ARGUMENT);
gRequestorUser.SetPeriodicQueryTimeout(strtoul(argv[0], NULL, 0));
gRequestorUser.RekickPeriodicQueryTimer();
return CHIP_NO_ERROR;
}
CHIP_ERROR OTARequestorHandler(int argc, char ** argv)
{
if (argc == 0)
{
sSubShell.ForEachCommand(PrintCommandHelp, nullptr);
return CHIP_NO_ERROR;
}
CHIP_ERROR error = sSubShell.ExecCommand(argc, argv);
if (error != CHIP_NO_ERROR)
{
streamer_printf(streamer_get(), "Error: %" CHIP_ERROR_FORMAT "\r\n", error.Format());
}
return error;
}
} // namespace
void OTARequestorCommands::Register()
{
// Register subcommands of the `OTARequestor` commands.
static const shell_command_t subCommands[] = {
{ &UserConsentStateHandler, "userConsentState",
"Set UserConsentState for QueryImageCommand\n"
"Usage: OTARequestor userConsentState <granted/denied/deferred>" },
{ &RequestorCanConsentHandler, "requestorCanConsent",
"Set requestorCanConsent for QueryImageCommand\n"
"Usage: OTARequestor requestorCanConsent <true/false>" },
{ &SetPeriodicQueryTimeoutHandler, "PeriodicQueryTimeout",
"Set timeout for querying the OTA provider for an update\n"
"Usage: OTARequestor PeriodicQueryTimeout <seconds>" },
};
sSubShell.RegisterCommands(subCommands, ArraySize(subCommands));
// Register the root `OTA Requestor` command in the top-level shell.
static const shell_command_t otaRequestorCommand = { &OTARequestorHandler, "OTARequestor", "OTA Requestor commands" };
Engine::Root().RegisterCommands(&otaRequestorCommand, 1);
}
} // namespace Shell
} // namespace chip