Skip to content

Commit

Permalink
Refactored OnboardingCodesUtil to decrease memory footprint. (#18318)
Browse files Browse the repository at this point in the history
* Refactored OnboardingCodesUtil to decrease memory footprint.

OnboardingCodesUtil uses SetupPayload object that contains
a lot unnecessary data and takes a lot of flash.

Replaced using SetupPayload with PayloadContents
and QRCodeSetupPayloadGenerator with QRCodeBasicSetupPayloadGenerator.
It allowed to save about 3.28 k of flash for nrfconnect platform.

* Fixed linux builds

* Changed char span size for codes buffers and fixed builds

* Added documentation for OnboardingCodesUtil methods
* Changed char span sizes returned by codes encoding methods
to not include null terminator
* Aligned examples using GetQRCode and GetManualPairingCode
to the new API.

* Fixed EFR32 build

* Addressed review comments regarding reducing span size.

* Fixed unit tests to reset span size after every encoding call.
  • Loading branch information
kkasperczyk-no authored and pull[bot] committed Nov 1, 2023
1 parent 70bada4 commit 2190336
Show file tree
Hide file tree
Showing 21 changed files with 186 additions and 91 deletions.
10 changes: 7 additions & 3 deletions examples/all-clusters-app/esp32/main/DeviceWithDisplay.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
*/

#include "DeviceWithDisplay.h"
#include <setup_payload/QRCodeSetupPayloadGenerator.h>

#if CONFIG_HAVE_DISPLAY
using namespace ::chip;
Expand Down Expand Up @@ -651,8 +652,11 @@ esp_err_t InitM5Stack(std::string qrCodeText)

void InitDeviceDisplay()
{
std::string qrCodeText;
// Create buffer for QR code that can fit max size and null terminator.
char qrCodeBuffer[chip::QRCodeBasicSetupPayloadGenerator::kMaxQRCodeBase38RepresentationLength + 1];
chip::MutableCharSpan qrCodeText(qrCodeBuffer);

// Get QR Code and emulate its content using NFC tag
GetQRCode(qrCodeText, chip::RendezvousInformationFlags(CONFIG_RENDEZVOUS_MODE));

// Initialize the display device.
Expand Down Expand Up @@ -681,12 +685,12 @@ void InitDeviceDisplay()

#if CONFIG_DEVICE_TYPE_M5STACK

InitM5Stack(qrCodeText);
InitM5Stack(qrCodeText.data());

#elif CONFIG_DEVICE_TYPE_ESP32_WROVER_KIT

// Display the QR Code
QRCodeScreen qrCodeScreen(qrCodeText);
QRCodeScreen qrCodeScreen(qrCodeText.data());
qrCodeScreen.Display();

#endif
Expand Down
9 changes: 6 additions & 3 deletions examples/chef/esp32/main/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
#include <app/server/Dnssd.h>
#include <app/util/af-event.h>
#include <app/util/af.h>
#include <setup_payload/QRCodeSetupPayloadGenerator.h>

#include "Display.h"
#include "QRCodeScreen.h"
Expand Down Expand Up @@ -137,7 +138,9 @@ const char * TAG = "chef-app";
#if CONFIG_HAVE_DISPLAY
void printQRCode()
{
std::string qrCodeText;
// Create buffer for QR code that can fit max size and null terminator.
char qrCodeBuffer[chip::QRCodeBasicSetupPayloadGenerator::kMaxQRCodeBase38RepresentationLength + 1];
chip::MutableCharSpan qrCodeText(qrCodeBuffer);

GetQRCode(qrCodeText, chip::RendezvousInformationFlags(CONFIG_RENDEZVOUS_MODE));

Expand All @@ -153,8 +156,8 @@ void printQRCode()
ScreenManager::Init();

ESP_LOGI(TAG, "Opening QR code screen");
ESP_LOGI(TAG, "QR CODE Text: '%s'", qrCodeText.c_str());
ScreenManager::PushScreen(chip::Platform::New<QRCodeScreen>(qrCodeText));
ESP_LOGI(TAG, "QR CODE Text: '%s'", qrCodeText.data());
ScreenManager::PushScreen(chip::Platform::New<QRCodeScreen>(qrCodeText.data()));
}
#endif // CONFIG_HAVE_DISPLAY

Expand Down
7 changes: 5 additions & 2 deletions examples/common/pigweed/rpc_services/Device.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include "platform/ConfigurationManager.h"
#include "platform/DiagnosticDataProvider.h"
#include "platform/PlatformManager.h"
#include <setup_payload/QRCodeSetupPayloadGenerator.h>

namespace chip {
namespace rpc {
Expand Down Expand Up @@ -146,10 +147,12 @@ class Device : public pw_rpc::nanopb::Device::Service<Device>
snprintf(response.serial_number, sizeof(response.serial_number), CHIP_DEVICE_CONFIG_TEST_SERIAL_NUMBER);
}

std::string qrCodeText;
// Create buffer for QR code that can fit max size and null terminator.
char qrCodeBuffer[chip::QRCodeBasicSetupPayloadGenerator::kMaxQRCodeBase38RepresentationLength + 1];
chip::MutableCharSpan qrCodeText(qrCodeBuffer);
if (GetQRCode(qrCodeText, chip::RendezvousInformationFlags(chip::RendezvousInformationFlag::kBLE)) == CHIP_NO_ERROR)
{
snprintf(response.pairing_info.qr_code, sizeof(response.pairing_info.qr_code), "%s", qrCodeText.c_str());
snprintf(response.pairing_info.qr_code, sizeof(response.pairing_info.qr_code), "%s", qrCodeText.data());
GetQRCodeUrl(response.pairing_info.qr_code_url, sizeof(response.pairing_info.qr_code_url), qrCodeText);
response.has_pairing_info = true;
}
Expand Down
6 changes: 4 additions & 2 deletions examples/light-switch-app/efr32/src/AppTask.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -239,11 +239,13 @@ CHIP_ERROR AppTask::Init()

// Print setup info on LCD if available
#ifdef DISPLAY_ENABLED
std::string QRCode;
// Create buffer for QR code that can fit max size and null terminator.
char qrCodeBuffer[chip::QRCodeBasicSetupPayloadGenerator::kMaxQRCodeBase38RepresentationLength + 1];
chip::MutableCharSpan QRCode(qrCodeBuffer);

if (GetQRCode(QRCode, chip::RendezvousInformationFlags(chip::RendezvousInformationFlag::kBLE)) == CHIP_NO_ERROR)
{
LCDWriteQRCode((uint8_t *) QRCode.c_str());
LCDWriteQRCode((uint8_t *) QRCode.data());
}
else
{
Expand Down
6 changes: 4 additions & 2 deletions examples/lighting-app/efr32/src/AppTask.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -283,11 +283,13 @@ CHIP_ERROR AppTask::Init()

// Print setup info on LCD if available
#ifdef DISPLAY_ENABLED
std::string QRCode;
// Create buffer for QR code that can fit max size and null terminator.
char qrCodeBuffer[chip::QRCodeBasicSetupPayloadGenerator::kMaxQRCodeBase38RepresentationLength + 1];
chip::MutableCharSpan QRCode(qrCodeBuffer);

if (GetQRCode(QRCode, chip::RendezvousInformationFlags(chip::RendezvousInformationFlag::kBLE)) == CHIP_NO_ERROR)
{
LCDWriteQRCode((uint8_t *) QRCode.c_str());
LCDWriteQRCode((uint8_t *) QRCode.data());
}
else
{
Expand Down
6 changes: 4 additions & 2 deletions examples/lock-app/efr32/src/AppTask.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -274,11 +274,13 @@ CHIP_ERROR AppTask::Init()

// Print setup info on LCD if available
#ifdef DISPLAY_ENABLED
std::string QRCode;
// Create buffer for QR code that can fit max size and null terminator.
char qrCodeBuffer[chip::QRCodeBasicSetupPayloadGenerator::kMaxQRCodeBase38RepresentationLength + 1];
chip::MutableCharSpan QRCode(qrCodeBuffer);

if (GetQRCode(QRCode, chip::RendezvousInformationFlags(chip::RendezvousInformationFlag::kBLE)) == CHIP_NO_ERROR)
{
LCDWriteQRCode((uint8_t *) QRCode.c_str());
LCDWriteQRCode((uint8_t *) QRCode.data());
}
else
{
Expand Down
6 changes: 4 additions & 2 deletions examples/ota-requestor-app/efr32/src/AppTask.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -170,11 +170,13 @@ CHIP_ERROR AppTask::Init()

// Print setup info on LCD if available
#ifdef DISPLAY_ENABLED
std::string QRCode;
// Create buffer for QR code that can fit max size and null terminator.
char qrCodeBuffer[chip::QRCodeBasicSetupPayloadGenerator::kMaxQRCodeBase38RepresentationLength + 1];
chip::MutableCharSpan QRCode(qrCodeBuffer);

if (GetQRCode(QRCode, chip::RendezvousInformationFlags(chip::RendezvousInformationFlag::kBLE)) == CHIP_NO_ERROR)
{
LCDWriteQRCode((uint8_t *) QRCode.c_str());
LCDWriteQRCode((uint8_t *) QRCode.data());
}
else
{
Expand Down
4 changes: 2 additions & 2 deletions examples/platform/linux/AppMain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ int ChipLinuxAppInit(int argc, char * const argv[], OptionSet * customOptions)
LinuxDeviceOptions::GetInstance());
SuccessOrExit(err);

err = GetSetupPayload(LinuxDeviceOptions::GetInstance().payload, rendezvousFlags);
err = GetPayloadContents(LinuxDeviceOptions::GetInstance().payload, rendezvousFlags);
SuccessOrExit(err);

ConfigurationMgr().LogDeviceConfig();
Expand All @@ -254,7 +254,7 @@ int ChipLinuxAppInit(int argc, char * const argv[], OptionSet * customOptions)
{
// For testing of manual pairing code with custom commissioning flow
ChipLogProgress(NotSpecified, "==== Onboarding payload for Custom Commissioning Flows ====");
err = GetSetupPayload(LinuxDeviceOptions::GetInstance().payload, rendezvousFlags);
err = GetPayloadContents(LinuxDeviceOptions::GetInstance().payload, rendezvousFlags);
SuccessOrExit(err);

LinuxDeviceOptions::GetInstance().payload.commissioningFlow = chip::CommissioningFlow::kCustom;
Expand Down
2 changes: 1 addition & 1 deletion examples/platform/linux/Options.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@

struct LinuxDeviceOptions
{
chip::SetupPayload payload;
chip::PayloadContents payload;
chip::Optional<uint16_t> discriminator;
chip::Optional<std::vector<uint8_t>> spake2pVerifier;
chip::Optional<std::vector<uint8_t>> spake2pSalt;
Expand Down
5 changes: 4 additions & 1 deletion examples/window-app/efr32/include/WindowAppImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include <LEDWidget.h>
#include <WindowApp.h>
#include <queue.h>
#include <setup_payload/QRCodeSetupPayloadGenerator.h>
#include <sl_simple_button_instances.h>
#include <string>
#include <task.h>
Expand Down Expand Up @@ -77,7 +78,9 @@ class WindowAppImpl : public WindowApp
QueueHandle_t mQueue = nullptr;
LEDWidget mStatusLED;
LEDWidget mActionLED;
std::string mQRCode;

// Get QR Code and emulate its content using NFC tag
char mQRCodeBuffer[chip::QRCodeBasicSetupPayloadGenerator::kMaxQRCodeBase38RepresentationLength + 1];
Timer mIconTimer;
LcdIcon mIcon = LcdIcon::None;
};
5 changes: 3 additions & 2 deletions examples/window-app/efr32/src/WindowAppImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -433,9 +433,10 @@ void WindowAppImpl::UpdateLCD()
#ifdef QR_CODE_ENABLED
else
{
if (GetQRCode(mQRCode, chip::RendezvousInformationFlags(chip::RendezvousInformationFlag::kBLE)) == CHIP_NO_ERROR)
chip::MutableCharSpan qrCode(mQRCodeBuffer);
if (GetQRCode(qrCode, chip::RendezvousInformationFlags(chip::RendezvousInformationFlag::kBLE)) == CHIP_NO_ERROR)
{
LCDWriteQRCode((uint8_t *) mQRCode.c_str());
LCDWriteQRCode((uint8_t *) qrCode.data());
}
}
#endif // QR_CODE_ENABLED
Expand Down
69 changes: 35 additions & 34 deletions src/app/server/OnboardingCodesUtil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,29 +37,29 @@ using namespace ::chip::DeviceLayer;

void PrintOnboardingCodes(chip::RendezvousInformationFlags aRendezvousFlags)
{
chip::SetupPayload payload;
chip::PayloadContents payload;

CHIP_ERROR err = GetSetupPayload(payload, aRendezvousFlags);
CHIP_ERROR err = GetPayloadContents(payload, aRendezvousFlags);
if (err != CHIP_NO_ERROR)
{
ChipLogError(AppServer, "GetSetupPayload() failed: %s", chip::ErrorStr(err));
ChipLogError(AppServer, "GetPayloadContents() failed: %s", chip::ErrorStr(err));
}

PrintOnboardingCodes(payload);
}

void PrintOnboardingCodes(const chip::SetupPayload & payload)
void PrintOnboardingCodes(const chip::PayloadContents & payload)
{
std::string qrCode;
std::string manualPairingCode;
char payloadBuffer[chip::QRCodeBasicSetupPayloadGenerator::kMaxQRCodeBase38RepresentationLength + 1];
chip::MutableCharSpan qrCode(payloadBuffer);

if (GetQRCode(qrCode, payload) == CHIP_NO_ERROR)
{
chip::Platform::ScopedMemoryBuffer<char> qrCodeBuffer;
const size_t qrCodeBufferMaxSize = strlen(kQrCodeBaseUrl) + strlen(kUrlDataAssignmentPhrase) + 3 * qrCode.size() + 1;
qrCodeBuffer.Alloc(qrCodeBufferMaxSize);

ChipLogProgress(AppServer, "SetupQRCode: [%s]", qrCode.c_str());
ChipLogProgress(AppServer, "SetupQRCode: [%s]", qrCode.data());
if (GetQRCodeUrl(qrCodeBuffer.Get(), qrCodeBufferMaxSize, qrCode) == CHIP_NO_ERROR)
{
ChipLogProgress(AppServer, "Copy/paste the below URL in a browser to see the QR Code:");
Expand All @@ -71,9 +71,10 @@ void PrintOnboardingCodes(const chip::SetupPayload & payload)
ChipLogError(AppServer, "Getting QR code failed!");
}

chip::MutableCharSpan manualPairingCode(payloadBuffer);
if (GetManualPairingCode(manualPairingCode, payload) == CHIP_NO_ERROR)
{
ChipLogProgress(AppServer, "Manual pairing code: [%s]", manualPairingCode.c_str());
ChipLogProgress(AppServer, "Manual pairing code: [%s]", manualPairingCode.data());
}
else
{
Expand All @@ -85,47 +86,49 @@ void PrintOnboardingCodes(const chip::SetupPayload & payload)
void ShareQRCodeOverNFC(chip::RendezvousInformationFlags aRendezvousFlags)
{
// Get QR Code and emulate its content using NFC tag
std::string qrCode;
char payloadBuffer[chip::QRCodeBasicSetupPayloadGenerator::kMaxQRCodeBase38RepresentationLength + 1];
chip::MutableCharSpan qrCode(payloadBuffer);

ReturnOnFailure(GetQRCode(qrCode, chip::RendezvousInformationFlags(chip::RendezvousInformationFlag::kBLE)));

ReturnOnFailure(NFCMgr().StartTagEmulation(qrCode.c_str(), qrCode.size()));
ReturnOnFailure(NFCMgr().StartTagEmulation(qrCode.data(), qrCode.size()));
}
#endif

CHIP_ERROR GetSetupPayload(chip::SetupPayload & aSetupPayload, chip::RendezvousInformationFlags aRendezvousFlags)
CHIP_ERROR GetPayloadContents(chip::PayloadContents & aPayload, chip::RendezvousInformationFlags aRendezvousFlags)
{
CHIP_ERROR err = CHIP_NO_ERROR;
aSetupPayload.version = 0;
aSetupPayload.rendezvousInformation = aRendezvousFlags;
CHIP_ERROR err = CHIP_NO_ERROR;
aPayload.version = 0;
aPayload.rendezvousInformation = aRendezvousFlags;

err = GetCommissionableDataProvider()->GetSetupPasscode(aSetupPayload.setUpPINCode);
err = GetCommissionableDataProvider()->GetSetupPasscode(aPayload.setUpPINCode);
if (err != CHIP_NO_ERROR)
{
ChipLogError(AppServer, "GetCommissionableDataProvider()->GetSetupPasscode() failed: %s", chip::ErrorStr(err));
#if defined(CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE) && CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE
ChipLogProgress(AppServer, "*** Using default EXAMPLE passcode %u ***",
static_cast<unsigned>(CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE));
aSetupPayload.setUpPINCode = CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE;
aPayload.setUpPINCode = CHIP_DEVICE_CONFIG_USE_TEST_SETUP_PIN_CODE;
#else
return err;
#endif
}

err = GetCommissionableDataProvider()->GetSetupDiscriminator(aSetupPayload.discriminator);
err = GetCommissionableDataProvider()->GetSetupDiscriminator(aPayload.discriminator);
if (err != CHIP_NO_ERROR)
{
ChipLogError(AppServer, "GetCommissionableDataProvider()->GetSetupDiscriminator() failed: %s", chip::ErrorStr(err));
return err;
}

err = ConfigurationMgr().GetVendorId(aSetupPayload.vendorID);
err = ConfigurationMgr().GetVendorId(aPayload.vendorID);
if (err != CHIP_NO_ERROR)
{
ChipLogError(AppServer, "ConfigurationMgr().GetVendorId() failed: %s", chip::ErrorStr(err));
return err;
}

err = ConfigurationMgr().GetProductId(aSetupPayload.productID);
err = ConfigurationMgr().GetProductId(aPayload.productID);
if (err != CHIP_NO_ERROR)
{
ChipLogError(AppServer, "ConfigurationMgr().GetProductId() failed: %s", chip::ErrorStr(err));
Expand All @@ -135,25 +138,23 @@ CHIP_ERROR GetSetupPayload(chip::SetupPayload & aSetupPayload, chip::RendezvousI
return err;
}

CHIP_ERROR GetQRCode(std::string & aQRCode, chip::RendezvousInformationFlags aRendezvousFlags)
CHIP_ERROR GetQRCode(chip::MutableCharSpan & aQRCode, chip::RendezvousInformationFlags aRendezvousFlags)
{
chip::SetupPayload payload;
chip::PayloadContents payload;

CHIP_ERROR err = GetSetupPayload(payload, aRendezvousFlags);
CHIP_ERROR err = GetPayloadContents(payload, aRendezvousFlags);
if (err != CHIP_NO_ERROR)
{
ChipLogError(AppServer, "GetSetupPayload() failed: %s", chip::ErrorStr(err));
ChipLogError(AppServer, "GetPayloadContents() failed: %s", chip::ErrorStr(err));
return err;
}

return GetQRCode(aQRCode, payload);
}

CHIP_ERROR GetQRCode(std::string & aQRCode, const chip::SetupPayload & payload)
CHIP_ERROR GetQRCode(chip::MutableCharSpan & aQRCode, const chip::PayloadContents & payload)
{
// TODO: Usage of STL will significantly increase the image size, this should be changed to more efficient method for
// generating payload
CHIP_ERROR err = chip::QRCodeSetupPayloadGenerator(payload).payloadBase38Representation(aQRCode);
CHIP_ERROR err = chip::QRCodeBasicSetupPayloadGenerator(payload).payloadBase38Representation(aQRCode);
if (err != CHIP_NO_ERROR)
{
ChipLogError(AppServer, "Generating QR Code failed: %s", chip::ErrorStr(err));
Expand All @@ -163,7 +164,7 @@ CHIP_ERROR GetQRCode(std::string & aQRCode, const chip::SetupPayload & payload)
return CHIP_NO_ERROR;
}

CHIP_ERROR GetQRCodeUrl(char * aQRCodeUrl, size_t aUrlMaxSize, const std::string & aQRCode)
CHIP_ERROR GetQRCodeUrl(char * aQRCodeUrl, size_t aUrlMaxSize, const chip::CharSpan & aQRCode)
{
VerifyOrReturnError(aQRCodeUrl, CHIP_ERROR_INVALID_ARGUMENT);
VerifyOrReturnError(aUrlMaxSize >= (strlen(kQrCodeBaseUrl) + strlen(kUrlDataAssignmentPhrase) + aQRCode.size() + 1),
Expand All @@ -173,24 +174,24 @@ CHIP_ERROR GetQRCodeUrl(char * aQRCodeUrl, size_t aUrlMaxSize, const std::string
VerifyOrReturnError((writtenDataSize > 0) && (static_cast<size_t>(writtenDataSize) < aUrlMaxSize),
CHIP_ERROR_INVALID_STRING_LENGTH);

return EncodeQRCodeToUrl(aQRCode.c_str(), aQRCode.size(), aQRCodeUrl + writtenDataSize,
return EncodeQRCodeToUrl(aQRCode.data(), aQRCode.size(), aQRCodeUrl + writtenDataSize,
aUrlMaxSize - static_cast<size_t>(writtenDataSize));
}

CHIP_ERROR GetManualPairingCode(std::string & aManualPairingCode, chip::RendezvousInformationFlags aRendezvousFlags)
CHIP_ERROR GetManualPairingCode(chip::MutableCharSpan & aManualPairingCode, chip::RendezvousInformationFlags aRendezvousFlags)
{
chip::SetupPayload payload;
chip::PayloadContents payload;

CHIP_ERROR err = GetSetupPayload(payload, aRendezvousFlags);
CHIP_ERROR err = GetPayloadContents(payload, aRendezvousFlags);
if (err != CHIP_NO_ERROR)
{
ChipLogError(AppServer, "GetSetupPayload() failed: %s", chip::ErrorStr(err));
ChipLogError(AppServer, "GetPayloadContents() failed: %s", chip::ErrorStr(err));
return err;
}
return GetManualPairingCode(aManualPairingCode, payload);
}

CHIP_ERROR GetManualPairingCode(std::string & aManualPairingCode, const chip::SetupPayload & payload)
CHIP_ERROR GetManualPairingCode(chip::MutableCharSpan & aManualPairingCode, const chip::PayloadContents & payload)
{
CHIP_ERROR err = chip::ManualSetupPayloadGenerator(payload).payloadDecimalStringRepresentation(aManualPairingCode);
if (err != CHIP_NO_ERROR)
Expand Down
Loading

0 comments on commit 2190336

Please sign in to comment.