Skip to content

Commit

Permalink
[linux] Enable setup code options for linux example apps (#8547)
Browse files Browse the repository at this point in the history
* [TE4] Enable setup code options in linux example apps

* Update src/app/server/OnboardingCodesUtil.cpp

Co-authored-by: Boris Zbarsky <bzbarsky@apple.com>

* Update src/app/server/OnboardingCodesUtil.cpp

Co-authored-by: Boris Zbarsky <bzbarsky@apple.com>

* Rename QRCode to qrCode

* Apply suggestions from code review

Co-authored-by: Justin Wood <woody@apple.com>
Co-authored-by: Boris Zbarsky <bzbarsky@apple.com>
  • Loading branch information
3 people authored and pull[bot] committed Sep 13, 2021
1 parent 31d6f91 commit 3978768
Show file tree
Hide file tree
Showing 6 changed files with 162 additions and 28 deletions.
2 changes: 2 additions & 0 deletions examples/bridge-app/linux/include/Options.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,11 @@
#include <cstdint>

#include <core/CHIPError.h>
#include <setup_payload/SetupPayload.h>

struct LinuxDeviceOptions
{
chip::SetupPayload payload;
uint32_t mBleDevice = 0;

static LinuxDeviceOptions & GetInstance();
Expand Down
17 changes: 11 additions & 6 deletions examples/platform/linux/AppMain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,23 +72,28 @@ void EventHandler(const chip::DeviceLayer::ChipDeviceEvent * event, intptr_t arg

int ChipLinuxAppInit(int argc, char ** argv)
{
CHIP_ERROR err = CHIP_NO_ERROR;
CHIP_ERROR err = CHIP_NO_ERROR;
chip::RendezvousInformationFlags rendezvousFlags = chip::RendezvousInformationFlag::kBLE;

#ifdef CONFIG_RENDEZVOUS_MODE
rendezvousFlags = static_cast<chip::RendezvousInformationFlags>(CONFIG_RENDEZVOUS_MODE);
#endif

err = chip::Platform::MemoryInit();
SuccessOrExit(err);

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

err = ParseArguments(argc, argv);
SuccessOrExit(err);

err = chip::DeviceLayer::PlatformMgr().InitChipStack();
SuccessOrExit(err);

ConfigurationMgr().LogDeviceConfig();
#ifdef CONFIG_RENDEZVOUS_MODE
PrintOnboardingCodes(static_cast<chip::RendezvousInformationFlags>(CONFIG_RENDEZVOUS_MODE));
#else
PrintOnboardingCodes(chip::RendezvousInformationFlag::kBLE);
#endif

PrintOnboardingCodes(LinuxDeviceOptions::GetInstance().payload);

#if defined(PW_RPC_ENABLED)
chip::rpc::Init();
Expand Down
89 changes: 77 additions & 12 deletions examples/platform/linux/Options.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

#include "Options.h"

#include <app/server/OnboardingCodesUtil.h>
#include <platform/CHIPDeviceLayer.h>

#include <core/CHIPError.h>
Expand All @@ -32,9 +33,16 @@ LinuxDeviceOptions gDeviceOptions;
// Follow the code style of command line arguments in case we need to add more options in the future.
enum
{
kDeviceOption_BleDevice = 0x1000,
kDeviceOption_WiFi = 0x1001,
kDeviceOption_Thread = 0x1002,
kDeviceOption_BleDevice = 0x1000,
kDeviceOption_WiFi = 0x1001,
kDeviceOption_Thread = 0x1002,
kDeviceOption_Version = 0x1003,
kDeviceOption_VendorID = 0x1004,
kDeviceOption_ProductID = 0x1005,
kDeviceOption_CustomFlow = 0x1006,
kDeviceOption_Capabilities = 0x1007,
kDeviceOption_Discriminator = 0x1008,
kDeviceOption_Passcode = 0x1009
};

constexpr unsigned kAppUsageLength = 64;
Expand All @@ -46,21 +54,50 @@ OptionDef sDeviceOptionDefs[] = { { "ble-device", kArgumentRequired, kDeviceOpti
#if CHIP_ENABLE_OPENTHREAD
{ "thread", kNoArgument, kDeviceOption_Thread },
#endif // CHIP_ENABLE_OPENTHREAD
{ "version", kArgumentRequired, kDeviceOption_Version },
{ "vendor-id", kArgumentRequired, kDeviceOption_VendorID },
{ "product-id", kArgumentRequired, kDeviceOption_ProductID },
{ "custom-flow", kArgumentRequired, kDeviceOption_CustomFlow },
{ "capabilities", kArgumentRequired, kDeviceOption_Capabilities },
{ "discriminator", kArgumentRequired, kDeviceOption_Discriminator },
{ "passcode", kArgumentRequired, kDeviceOption_Passcode },
{} };

const char * sDeviceOptionHelp = " --ble-device <number>\n"
" The device number for CHIPoBLE, without 'hci' prefix, can be found by hciconfig.\n"
const char * sDeviceOptionHelp =
" --ble-device <number>\n"
" The device number for CHIPoBLE, without 'hci' prefix, can be found by hciconfig.\n"
#if CHIP_DEVICE_CONFIG_ENABLE_WPA
"\n"
" --wifi\n"
" Enable WiFi management via wpa_supplicant.\n"
"\n"
" --wifi\n"
" Enable WiFi management via wpa_supplicant.\n"
#endif // CHIP_DEVICE_CONFIG_ENABLE_WPA
#if CHIP_ENABLE_OPENTHREAD
"\n"
" --thread\n"
" Enable Thread management via ot-agent.\n"
"\n"
" --thread\n"
" Enable Thread management via ot-agent.\n"
#endif // CHIP_ENABLE_OPENTHREAD
"\n";
"\n"
" --version <version>\n"
" The version indication provides versioning of the setup payload.\n"
"\n"
" --vendor-id <id>\n"
" The Vendor ID is assigned by the Connectivity Standards Alliance.\n"
"\n"
" --product-id <id>\n"
" The Product ID is specified by vendor.\n"
"\n"
" --custom-flow <Standard = 0 | UserActionRequired = 1 | Custom = 2>\n"
" A 2-bit unsigned enumeration specifying manufacturer-specific custom flow options.\n"
"\n"
" --capabilities <None = 0, SoftAP = 1 << 0, BLE = 1 << 1, OnNetwork = 1 << 2>\n"
" Discovery Capabilities Bitmask which contains information about Device’s available technologies for device discovery.\n"
"\n"
" --discriminator <discriminator>\n"
" A 12-bit unsigned integer match the value which a device advertises during commissioning.\n"
"\n"
" --passcode <passcode>\n"
" A 27-bit unsigned integer, which serves as proof of possession during commissioning.\n"
"\n";

bool HandleOption(const char * aProgram, OptionSet * aOptions, int aIdentifier, const char * aName, const char * aValue)
{
Expand All @@ -85,6 +122,34 @@ bool HandleOption(const char * aProgram, OptionSet * aOptions, int aIdentifier,
LinuxDeviceOptions::GetInstance().mThread = true;
break;

case kDeviceOption_Version:
LinuxDeviceOptions::GetInstance().payload.version = static_cast<uint8_t>(atoi(aValue));
break;

case kDeviceOption_VendorID:
LinuxDeviceOptions::GetInstance().payload.vendorID = static_cast<uint16_t>(atoi(aValue));
break;

case kDeviceOption_ProductID:
LinuxDeviceOptions::GetInstance().payload.productID = static_cast<uint16_t>(atoi(aValue));
break;

case kDeviceOption_CustomFlow:
LinuxDeviceOptions::GetInstance().payload.commissioningFlow = static_cast<CommissioningFlow>(atoi(aValue));
break;

case kDeviceOption_Capabilities:
LinuxDeviceOptions::GetInstance().payload.rendezvousInformation.SetRaw(static_cast<uint8_t>(atoi(aValue)));
break;

case kDeviceOption_Discriminator:
LinuxDeviceOptions::GetInstance().payload.discriminator = static_cast<uint16_t>(atoi(aValue));
break;

case kDeviceOption_Passcode:
LinuxDeviceOptions::GetInstance().payload.setUpPINCode = static_cast<uint32_t>(atoi(aValue));
break;

default:
PrintArgError("%s: INTERNAL ERROR: Unhandled option: %s\n", aProgram, aName);
retval = false;
Expand Down
2 changes: 2 additions & 0 deletions examples/platform/linux/Options.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,11 @@
#include <cstdint>

#include <core/CHIPError.h>
#include <setup_payload/SetupPayload.h>

struct LinuxDeviceOptions
{
chip::SetupPayload payload;
uint32_t mBleDevice = 0;
bool mWiFi = false;
bool mThread = false;
Expand Down
75 changes: 66 additions & 9 deletions src/app/server/OnboardingCodesUtil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,20 +36,20 @@ using namespace ::chip::DeviceLayer;

void PrintOnboardingCodes(chip::RendezvousInformationFlags aRendezvousFlags)
{
std::string QRCode;
std::string qrCode;
std::string manualPairingCode;

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

ChipLogProgress(AppServer, "SetupQRCode: [%s]", QRCode.c_str());
if (GetQRCodeUrl(&qrCodeBuffer[0], qrCodeBufferMaxSize, QRCode) == CHIP_NO_ERROR)
ChipLogProgress(AppServer, "SetupQRCode: [%s]", qrCode.c_str());
if (GetQRCodeUrl(qrCodeBuffer.Get(), qrCodeBufferMaxSize, qrCode) == CHIP_NO_ERROR)
{
ChipLogProgress(AppServer, "Copy/paste the below URL in a browser to see the QR Code:");
ChipLogProgress(AppServer, "%s", &qrCodeBuffer[0]);
ChipLogProgress(AppServer, "%s", qrCodeBuffer.Get());
}
}
else
Expand All @@ -67,14 +67,47 @@ void PrintOnboardingCodes(chip::RendezvousInformationFlags aRendezvousFlags)
}
}

void PrintOnboardingCodes(const chip::SetupPayload & payload)
{
std::string qrCode;
std::string manualPairingCode;

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());
if (GetQRCodeUrl(qrCodeBuffer.Get(), qrCodeBufferMaxSize, qrCode) == CHIP_NO_ERROR)
{
ChipLogProgress(AppServer, "Copy/paste the below URL in a browser to see the QR Code:");
ChipLogProgress(AppServer, "%s", qrCodeBuffer.Get());
}
}
else
{
ChipLogError(AppServer, "Getting QR code failed!");
}

if (GetManualPairingCode(manualPairingCode, payload) == CHIP_NO_ERROR)
{
ChipLogProgress(AppServer, "Manual pairing code: [%s]", manualPairingCode.c_str());
}
else
{
ChipLogError(AppServer, "Getting manual pairing code failed!");
}
}

#if CHIP_DEVICE_CONFIG_ENABLE_NFC
void ShareQRCodeOverNFC(chip::RendezvousInformationFlags aRendezvousFlags)
{
// Get QR Code and emulate its content using NFC tag
std::string QRCode;
ReturnOnFailure(GetQRCode(QRCode, chip::RendezvousInformationFlags(chip::RendezvousInformationFlag::kBLE)));
std::string qrCode;
ReturnOnFailure(GetQRCode(qrCode, chip::RendezvousInformationFlags(chip::RendezvousInformationFlag::kBLE)));

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

Expand Down Expand Up @@ -138,6 +171,18 @@ CHIP_ERROR GetQRCode(std::string & aQRCode, chip::RendezvousInformationFlags aRe
return CHIP_NO_ERROR;
}

CHIP_ERROR GetQRCode(std::string & aQRCode, const chip::SetupPayload & payload)
{
CHIP_ERROR err = chip::QRCodeSetupPayloadGenerator(payload).payloadBase38Representation(aQRCode);
if (err != CHIP_NO_ERROR)
{
ChipLogProgress(AppServer, "Generating QR Code failed: %s", chip::ErrorStr(err));
return err;
}

return CHIP_NO_ERROR;
}

CHIP_ERROR GetQRCodeUrl(char * aQRCodeUrl, size_t aUrlMaxSize, const std::string & aQRCode)
{
VerifyOrReturnError(aQRCodeUrl, CHIP_ERROR_INVALID_ARGUMENT);
Expand Down Expand Up @@ -173,6 +218,18 @@ CHIP_ERROR GetManualPairingCode(std::string & aManualPairingCode, chip::Rendezvo
return CHIP_NO_ERROR;
}

CHIP_ERROR GetManualPairingCode(std::string & aManualPairingCode, const chip::SetupPayload & payload)
{
CHIP_ERROR err = chip::ManualSetupPayloadGenerator(payload).payloadDecimalStringRepresentation(aManualPairingCode);
if (err != CHIP_NO_ERROR)
{
ChipLogProgress(AppServer, "Generating Manual Pairing Code failed: %s", chip::ErrorStr(err));
return err;
}

return CHIP_NO_ERROR;
}

static inline bool isCharUnreservedInRfc3986(const char c)
{
return isalpha(c) || isdigit(c) || (strchr(kSpecialCharsUnreservedInRfc3986, c) != nullptr);
Expand Down
5 changes: 4 additions & 1 deletion src/app/server/OnboardingCodesUtil.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,13 @@
#include <setup_payload/SetupPayload.h>

void PrintOnboardingCodes(chip::RendezvousInformationFlags aRendezvousFlags);
void PrintOnboardingCodes(const chip::SetupPayload & payload);
void ShareQRCodeOverNFC(chip::RendezvousInformationFlags aRendezvousFlags);
CHIP_ERROR GetQRCode(std::string & QRCode, chip::RendezvousInformationFlags aRendezvousFlags);
CHIP_ERROR GetQRCode(std::string & aQRCode, chip::RendezvousInformationFlags aRendezvousFlags);
CHIP_ERROR GetQRCode(std::string & aQRCode, const chip::SetupPayload & payload);
CHIP_ERROR GetQRCodeUrl(char * aQRCodeUrl, size_t aUrlMaxSize, const std::string & aQRCode);
CHIP_ERROR GetManualPairingCode(std::string & aManualPairingCode, chip::RendezvousInformationFlags aRendezvousFlags);
CHIP_ERROR GetManualPairingCode(std::string & aManualPairingCode, const chip::SetupPayload & payload);
CHIP_ERROR GetSetupPayload(chip::SetupPayload & aSetupPayload, chip::RendezvousInformationFlags aRendezvousFlags);

/**
Expand Down

0 comments on commit 3978768

Please sign in to comment.