Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[linux] Enable setup code options for linux example apps #8547

Merged
merged 5 commits into from
Jul 28, 2021
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
73 changes: 65 additions & 8 deletions src/app/server/OnboardingCodesUtil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,17 +36,17 @@ 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[0], qrCodeBufferMaxSize, qrCode) == CHIP_NO_ERROR)
bzbarsky-apple marked this conversation as resolved.
Show resolved Hide resolved
{
ChipLogProgress(AppServer, "Copy/paste the below URL in a browser to see the QR Code:");
ChipLogProgress(AppServer, "%s", &qrCodeBuffer[0]);
bzbarsky-apple marked this conversation as resolved.
Show resolved Hide resolved
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