From 17073308c456ada5fe69cd54b8240d4a4c895b29 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damian=20Kr=C3=B3lik?= <66667989+Damian-Nordic@users.noreply.github.com> Date: Mon, 7 Jun 2021 19:05:24 +0200 Subject: [PATCH] [qr-code] Align QR Code format with the spec (#7272) * [qr-code] Align QR Code format with the spec 1. Replace boolean requiresCustomFlow with 2-bit field with the following meaning: 0 - device automatically enters paring mode upon power-up 1 - device needs user interaction to enter pairing mode 2 - device uses a vendor-specific flow that should be retrieved from the distributed ledger. 2. Replace CH: prefix with MT: * Restyled by clang-format * Update src/setup_payload/QRCodeSetupPayloadParser.cpp Co-authored-by: Boris Zbarsky * Restyled by clang-format * Fixes after rebase Co-authored-by: Restyled.io Co-authored-by: Justin Wood Co-authored-by: Boris Zbarsky --- docs/guides/nrfconnect_examples_cli.md | 2 +- examples/all-clusters-app/esp32/main/main.cpp | 4 +- examples/chip-tool/README.md | 4 +- .../payload/SetupPayloadParseCommand.cpp | 4 +- .../payload/SetupPayloadParseCommand.h | 1 - examples/pump-app/cc13x2x7_26x2x7/README.md | 4 +- .../cc13x2x7_26x2x7/README.md | 4 +- .../google/chip/chiptool/CHIPToolActivity.kt | 4 +- src/controller/python/README.md | 8 +- .../python/chip/setup_payload/Parser.cpp | 2 +- .../chip/setup_payload/setup_payload.py | 4 +- src/darwin/Framework/CHIP/CHIPSetupPayload.h | 9 +- src/darwin/Framework/CHIP/CHIPSetupPayload.mm | 19 ++- .../CHIP/CHIPSetupPayload_Internal.h | 3 +- .../CHIPTests/CHIPSetupPayloadParserTests.m | 30 ++--- src/setup_payload/Base38.cpp | 9 +- .../ManualSetupPayloadGenerator.cpp | 4 +- .../ManualSetupPayloadParser.cpp | 2 +- .../QRCodeSetupPayloadGenerator.cpp | 3 +- .../QRCodeSetupPayloadParser.cpp | 9 +- src/setup_payload/SetupPayload.cpp | 9 +- src/setup_payload/SetupPayload.h | 60 +++++---- src/setup_payload/SetupPayloadHelper.cpp | 13 +- .../java/SetupPayloadParser-JNI.cpp | 14 +- .../src/chip/setuppayload/SetupPayload.java | 8 +- src/setup_payload/tests/TestHelpers.h | 16 ++- src/setup_payload/tests/TestManualCode.cpp | 59 ++++---- src/setup_payload/tests/TestQRCode.cpp | 126 ++++++++++++------ 28 files changed, 256 insertions(+), 178 deletions(-) diff --git a/docs/guides/nrfconnect_examples_cli.md b/docs/guides/nrfconnect_examples_cli.md index 5a189da06a54d7..a0bf5ddf41dd18 100644 --- a/docs/guides/nrfconnect_examples_cli.md +++ b/docs/guides/nrfconnect_examples_cli.md @@ -120,7 +120,7 @@ Takes no arguments. ```shell uart:~$ chip qrcode -CH:H34.GHY00 0C9SS0 +MT:W0GU2OTB00KA0648G00 ``` #### `qrcodeurl` diff --git a/examples/all-clusters-app/esp32/main/main.cpp b/examples/all-clusters-app/esp32/main/main.cpp index 35d5e2c8ae9611..eaec0723c1ee66 100644 --- a/examples/all-clusters-app/esp32/main/main.cpp +++ b/examples/all-clusters-app/esp32/main/main.cpp @@ -509,8 +509,8 @@ std::string createSetupPayload() ESP_LOGE(TAG, "Failed to get decimal setup code"); } - payload.requiresCustomFlow = 1; - generator = ManualSetupPayloadGenerator(payload); + payload.commissioningFlow = CommissioningFlow::kCustom; + generator = ManualSetupPayloadGenerator(payload); if (generator.payloadDecimalStringRepresentation(outCode) == CHIP_NO_ERROR) { diff --git a/examples/chip-tool/README.md b/examples/chip-tool/README.md index cbfcc2d05dc2ad..d3a7e916a49743 100644 --- a/examples/chip-tool/README.md +++ b/examples/chip-tool/README.md @@ -132,11 +132,11 @@ and the `parse-setup-payload` command #### QR Code - $ chip-tool payload parse-setup-payload "CH:#####" + $ chip-tool payload parse-setup-payload "MT:#####" #### QR Code with optional Vendor Info - $ chip-tool payload parse-setup-payload "CH:#####" + $ chip-tool payload parse-setup-payload "MT:#####" #### Manual Setup Code diff --git a/examples/chip-tool/commands/payload/SetupPayloadParseCommand.cpp b/examples/chip-tool/commands/payload/SetupPayloadParseCommand.cpp index c90d16dee77c53..9de2fc8d81d571 100644 --- a/examples/chip-tool/commands/payload/SetupPayloadParseCommand.cpp +++ b/examples/chip-tool/commands/payload/SetupPayloadParseCommand.cpp @@ -44,7 +44,7 @@ CHIP_ERROR SetupPayloadParseCommand::Print(chip::SetupPayload payload) std::vector optionalVendorData; CHIP_ERROR err = CHIP_NO_ERROR; - ChipLogProgress(SetupPayload, "RequiresCustomFlow: %u", payload.requiresCustomFlow); + ChipLogProgress(SetupPayload, "CommissioningFlow: %u", payload.commissioningFlow); ChipLogProgress(SetupPayload, "VendorID: %u", payload.vendorID); ChipLogProgress(SetupPayload, "Version: %u", payload.version); ChipLogProgress(SetupPayload, "ProductID: %u", payload.productID); @@ -100,5 +100,5 @@ CHIP_ERROR SetupPayloadParseCommand::Parse(std::string codeString, chip::SetupPa bool SetupPayloadParseCommand::IsQRCode(std::string codeString) { - return codeString.rfind(QRCODE_PREFIX) == 0; + return codeString.rfind(kQRCodePrefix) == 0; } diff --git a/examples/chip-tool/commands/payload/SetupPayloadParseCommand.h b/examples/chip-tool/commands/payload/SetupPayloadParseCommand.h index 58aac2409200a6..2e09ee743109b9 100644 --- a/examples/chip-tool/commands/payload/SetupPayloadParseCommand.h +++ b/examples/chip-tool/commands/payload/SetupPayloadParseCommand.h @@ -32,5 +32,4 @@ class SetupPayloadParseCommand : public Command CHIP_ERROR Parse(std::string codeString, chip::SetupPayload & payload); CHIP_ERROR Print(chip::SetupPayload payload); bool IsQRCode(std::string codeString); - const std::string QRCODE_PREFIX = "CH:"; }; diff --git a/examples/pump-app/cc13x2x7_26x2x7/README.md b/examples/pump-app/cc13x2x7_26x2x7/README.md index 64e6b1b9577240..5b15bef626e2a8 100644 --- a/examples/pump-app/cc13x2x7_26x2x7/README.md +++ b/examples/pump-app/cc13x2x7_26x2x7/README.md @@ -192,7 +192,7 @@ This is done by scanning a QR code. A URL will be displayed on the lock-app's log ([UART terminal](#viewing-logging-output)). It will look like the following: ``` -SetupQRCode: [CH:.81TM -00 0C9SS0] +SetupQRCode: [MT:.81TM -00 0C9SS0] Copy/paste the below URL in a browser to see the QR Code: https://dhrishi.github.io/connectedhomeip/qrcode.html?data=CH%3A.81TM%20-00%200C9SS0 ``` @@ -200,7 +200,7 @@ https://dhrishi.github.io/connectedhomeip/qrcode.html?data=CH%3A.81TM%20-00%200C You can directly navigate to the webpage URL displayed (which has QR payload pre-loaded). Alternatively, you can navigate to [the QR code generator][qr_code_generator] and enter in the payload shown in `SetupQRCode` -(in this case `CH:.81TM -00 0C9SS0`). +(in this case `MT:.81TM -00 0C9SS0`). ### CHIP Remote Commands diff --git a/examples/pump-controller-app/cc13x2x7_26x2x7/README.md b/examples/pump-controller-app/cc13x2x7_26x2x7/README.md index 64e6b1b9577240..5b15bef626e2a8 100644 --- a/examples/pump-controller-app/cc13x2x7_26x2x7/README.md +++ b/examples/pump-controller-app/cc13x2x7_26x2x7/README.md @@ -192,7 +192,7 @@ This is done by scanning a QR code. A URL will be displayed on the lock-app's log ([UART terminal](#viewing-logging-output)). It will look like the following: ``` -SetupQRCode: [CH:.81TM -00 0C9SS0] +SetupQRCode: [MT:.81TM -00 0C9SS0] Copy/paste the below URL in a browser to see the QR Code: https://dhrishi.github.io/connectedhomeip/qrcode.html?data=CH%3A.81TM%20-00%200C9SS0 ``` @@ -200,7 +200,7 @@ https://dhrishi.github.io/connectedhomeip/qrcode.html?data=CH%3A.81TM%20-00%200C You can directly navigate to the webpage URL displayed (which has QR payload pre-loaded). Alternatively, you can navigate to [the QR code generator][qr_code_generator] and enter in the payload shown in `SetupQRCode` -(in this case `CH:.81TM -00 0C9SS0`). +(in this case `MT:.81TM -00 0C9SS0`). ### CHIP Remote Commands diff --git a/src/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/CHIPToolActivity.kt b/src/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/CHIPToolActivity.kt index cbfbe624ee78d6..f776775837b766 100644 --- a/src/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/CHIPToolActivity.kt +++ b/src/android/CHIPTool/app/src/main/java/com/google/chip/chiptool/CHIPToolActivity.kt @@ -146,9 +146,9 @@ class CHIPToolActivity : val records = (messages[0] as NdefMessage).records if (records.size != 1) return - // Require NDEF URI record starting with "ch:" + // Require NDEF URI record starting with "mt:" val uri = records[0].toUri() - if (!uri?.scheme.equals("ch", true)) return + if (!uri?.scheme.equals("mt", true)) return lateinit var setupPayload: SetupPayload try { diff --git a/src/controller/python/README.md b/src/controller/python/README.md index 28e9707bf20886..23c2f79525e48f 100644 --- a/src/controller/python/README.md +++ b/src/controller/python/README.md @@ -388,11 +388,11 @@ chip-device-ctrl > resolve 5544332211 1234 Print the commissioning information encoded in the Manual Pairing Code: ``` -chip-device-ctrl > setup-payload parse-manual 35767807533 +chip-device-ctrl > setup-payload parse-manual 34970112332 Version: 0 VendorID: 0 ProductID: 0 -RequiresCustomFlow: 0 +CommissioningFlow: 0 RendezvousInformation: 0 Discriminator: 3840 SetUpPINCode: 20202021 @@ -403,11 +403,11 @@ SetUpPINCode: 20202021 Print the commissioning information encoded in the QR Code payload: ``` -chip-device-ctrl > setup-payload parse-qr "VP:vendorpayload%CH:H34.GHY00 0C9SS0" +chip-device-ctrl > setup-payload parse-qr "VP:vendorpayload%MT:W0GU2OTB00KA0648G00" Version: 0 VendorID: 9050 ProductID: 20043 -RequiresCustomFlow: 0 +CommissioningFlow: 0 RendezvousInformation: 2 [BLE] Discriminator: 3840 SetUpPINCode: 20202021 diff --git a/src/controller/python/chip/setup_payload/Parser.cpp b/src/controller/python/chip/setup_payload/Parser.cpp index f23fe4ae62cd41..3e407c92972b79 100644 --- a/src/controller/python/chip/setup_payload/Parser.cpp +++ b/src/controller/python/chip/setup_payload/Parser.cpp @@ -34,7 +34,7 @@ void YieldSetupPayloadAttributes(const SetupPayload & payload, AttributeVisitor attrVisitor("Version", std::to_string(payload.version).c_str()); attrVisitor("VendorID", std::to_string(payload.vendorID).c_str()); attrVisitor("ProductID", std::to_string(payload.productID).c_str()); - attrVisitor("RequiresCustomFlow", std::to_string(payload.requiresCustomFlow).c_str()); + attrVisitor("CommissioningFlow", std::to_string(static_cast(payload.commissioningFlow)).c_str()); attrVisitor("RendezvousInformation", std::to_string(payload.rendezvousInformation.Raw()).c_str()); attrVisitor("Discriminator", std::to_string(payload.discriminator).c_str()); attrVisitor("SetUpPINCode", std::to_string(payload.setUpPINCode).c_str()); diff --git a/src/controller/python/chip/setup_payload/setup_payload.py b/src/controller/python/chip/setup_payload/setup_payload.py index f321b75b661b70..05c35b74ad9dfd 100644 --- a/src/controller/python/chip/setup_payload/setup_payload.py +++ b/src/controller/python/chip/setup_payload/setup_payload.py @@ -68,8 +68,8 @@ def Print(self): decorated_value = f" [{decorated_value}]" if decorated_value else "" print(f"{name}: {value}{decorated_value}") - for tag, value in self.vendor_attributes: - print(f"Vendor attribute '{tag:>3}': {value}") + for tag in self.vendor_attributes: + print(f"Vendor attribute '{tag:>3}': {self.vendor_attributes[tag]}") def Clear(self): self.attributes.clear() diff --git a/src/darwin/Framework/CHIP/CHIPSetupPayload.h b/src/darwin/Framework/CHIP/CHIPSetupPayload.h index 823b4bb7c3817e..20298d19c3e471 100644 --- a/src/darwin/Framework/CHIP/CHIPSetupPayload.h +++ b/src/darwin/Framework/CHIP/CHIPSetupPayload.h @@ -28,6 +28,13 @@ typedef NS_ENUM(NSUInteger, CHIPRendezvousInformationFlags) { kRendezvousInformationAllMask = kRendezvousInformationSoftAP | kRendezvousInformationBLE | kRendezvousInformationOnNetwork, }; +typedef NS_ENUM(NSUInteger, CHIPCommissioningFlow) { + kCommissioningFlowStandard = 0, // Device automatically enters pairing mode upon power-up + kCommissioningFlowUserActionRequired = 1, // Device requires a user interaction to enter pairing mode + kCommissioningFlowCustom = 2, // Commissioning steps should be retrieved from the distributed compliance ledger + kCommissioningFlowInvalid = 3, +}; + typedef NS_ENUM(NSUInteger, CHIPOptionalQRCodeInfoType) { kOptionalQRCodeInfoTypeUnknown, kOptionalQRCodeInfoTypeString, @@ -46,7 +53,7 @@ typedef NS_ENUM(NSUInteger, CHIPOptionalQRCodeInfoType) { @property (nonatomic, strong) NSNumber * version; @property (nonatomic, strong) NSNumber * vendorID; @property (nonatomic, strong) NSNumber * productID; -@property (nonatomic, assign) BOOL requiresCustomFlow; +@property (nonatomic, assign) CHIPCommissioningFlow commissioningFlow; @property (nonatomic, assign) CHIPRendezvousInformationFlags rendezvousInformation; @property (nonatomic, strong) NSNumber * discriminator; @property (nonatomic, strong) NSNumber * setUpPINCode; diff --git a/src/darwin/Framework/CHIP/CHIPSetupPayload.mm b/src/darwin/Framework/CHIP/CHIPSetupPayload.mm index bfdddbec36cbe5..61a2c489d16cb8 100644 --- a/src/darwin/Framework/CHIP/CHIPSetupPayload.mm +++ b/src/darwin/Framework/CHIP/CHIPSetupPayload.mm @@ -26,7 +26,7 @@ @implementation CHIPSetupPayload { chip::SetupPayload _chipSetupPayload; } -- (CHIPRendezvousInformationFlags)valueOf:(chip::RendezvousInformationFlags)value +- (CHIPRendezvousInformationFlags)convertRendezvousFlags:(chip::RendezvousInformationFlags)value { if (value.Has(chip::RendezvousInformationFlag::kBLE)) { return kRendezvousInformationBLE; @@ -39,6 +39,19 @@ - (CHIPRendezvousInformationFlags)valueOf:(chip::RendezvousInformationFlags)valu } } +- (CHIPCommissioningFlow)convertCommissioningFlow:(chip::CommissioningFlow)value +{ + if (value == chip::CommissioningFlow::kStandard) { + return kCommissioningFlowStandard; + } else if (value == chip::CommissioningFlow::kUserActionRequired) { + return kCommissioningFlowUserActionRequired; + } else if (value == chip::CommissioningFlow::kCustom) { + return kCommissioningFlowCustom; + } else { + return kCommissioningFlowInvalid; + } +} + - (id)initWithSetupPayload:(chip::SetupPayload)setupPayload { if (self = [super init]) { @@ -46,8 +59,8 @@ - (id)initWithSetupPayload:(chip::SetupPayload)setupPayload _version = [NSNumber numberWithUnsignedChar:setupPayload.version]; _vendorID = [NSNumber numberWithUnsignedShort:setupPayload.vendorID]; _productID = [NSNumber numberWithUnsignedShort:setupPayload.productID]; - _requiresCustomFlow = setupPayload.requiresCustomFlow == 1; - _rendezvousInformation = [self valueOf:setupPayload.rendezvousInformation]; + _commissioningFlow = [self convertCommissioningFlow:setupPayload.commissioningFlow]; + _rendezvousInformation = [self convertRendezvousFlags:setupPayload.rendezvousInformation]; _discriminator = [NSNumber numberWithUnsignedShort:setupPayload.discriminator]; _setUpPINCode = [NSNumber numberWithUnsignedInt:setupPayload.setUpPINCode]; diff --git a/src/darwin/Framework/CHIP/CHIPSetupPayload_Internal.h b/src/darwin/Framework/CHIP/CHIPSetupPayload_Internal.h index 0ffbb8d32fccda..98d336715de80c 100644 --- a/src/darwin/Framework/CHIP/CHIPSetupPayload_Internal.h +++ b/src/darwin/Framework/CHIP/CHIPSetupPayload_Internal.h @@ -17,7 +17,8 @@ #ifdef __cplusplus - (id)initWithSetupPayload:(chip::SetupPayload)setupPayload; -- (CHIPRendezvousInformationFlags)valueOf:(chip::RendezvousInformationFlags)value; +- (CHIPRendezvousInformationFlags)convertRendezvousFlags:(chip::RendezvousInformationFlags)value; +- (CHIPCommissioningFlow)convertCommissioningFlow:(chip::CommissioningFlow)value; #endif @end diff --git a/src/darwin/Framework/CHIPTests/CHIPSetupPayloadParserTests.m b/src/darwin/Framework/CHIPTests/CHIPSetupPayloadParserTests.m index 39d778d2136eb8..6010e0cf782469 100644 --- a/src/darwin/Framework/CHIPTests/CHIPSetupPayloadParserTests.m +++ b/src/darwin/Framework/CHIPTests/CHIPSetupPayloadParserTests.m @@ -49,7 +49,7 @@ - (void)testOnboardingPayloadParser_Manual_NoError XCTAssertEqual(payload.setUpPINCode.unsignedIntegerValue, 123456780); XCTAssertEqual(payload.vendorID.unsignedIntegerValue, 1); XCTAssertEqual(payload.productID.unsignedIntegerValue, 1); - XCTAssertTrue(payload.requiresCustomFlow); + XCTAssertEqual(payload.commissioningFlow, kCommissioningFlowCustom); XCTAssertEqual(payload.version.unsignedIntegerValue, 0); XCTAssertEqual(payload.rendezvousInformation, kRendezvousInformationNone); } @@ -79,7 +79,7 @@ - (void)testOnboardingPayloadParser_Admin_NoError XCTAssertEqual(payload.setUpPINCode.unsignedIntegerValue, 123456780); XCTAssertEqual(payload.vendorID.unsignedIntegerValue, 1); XCTAssertEqual(payload.productID.unsignedIntegerValue, 1); - XCTAssertTrue(payload.requiresCustomFlow); + XCTAssertEqual(payload.commissioningFlow, kCommissioningFlowCustom); XCTAssertEqual(payload.version.unsignedIntegerValue, 0); XCTAssertEqual(payload.rendezvousInformation, kRendezvousInformationNone); } @@ -98,7 +98,7 @@ - (void)testOnboardingPayloadParser_Admin_WrongType - (void)testOnboardingPayloadParser_QRCode_NoError { NSError * error; - CHIPSetupPayload * payload = [CHIPOnboardingPayloadParser setupPayloadForOnboardingPayload:@"CH:R5L90UV200A3L900000" + CHIPSetupPayload * payload = [CHIPOnboardingPayloadParser setupPayloadForOnboardingPayload:@"MT:R5L90MP500K64J00000" ofType:CHIPOnboardingPayloadTypeQRCode error:&error]; @@ -109,7 +109,7 @@ - (void)testOnboardingPayloadParser_QRCode_NoError XCTAssertEqual(payload.setUpPINCode.unsignedIntegerValue, 2048); XCTAssertEqual(payload.vendorID.unsignedIntegerValue, 12); XCTAssertEqual(payload.productID.unsignedIntegerValue, 1); - XCTAssertFalse(payload.requiresCustomFlow); + XCTAssertEqual(payload.commissioningFlow, kCommissioningFlowStandard); XCTAssertEqual(payload.version.unsignedIntegerValue, 5); XCTAssertEqual(payload.rendezvousInformation, kRendezvousInformationSoftAP); } @@ -117,7 +117,7 @@ - (void)testOnboardingPayloadParser_QRCode_NoError - (void)testOnboardingPayloadParser_QRCode_WrongType { NSError * error; - CHIPSetupPayload * payload = [CHIPOnboardingPayloadParser setupPayloadForOnboardingPayload:@"CH:R5L90UV200A3L900000" + CHIPSetupPayload * payload = [CHIPOnboardingPayloadParser setupPayloadForOnboardingPayload:@"MT:R5L90MP500K64J00000" ofType:CHIPOnboardingPayloadTypeAdmin error:&error]; @@ -129,7 +129,7 @@ - (void)testOnboardingPayloadParser_NFC_NoError { NSError * error; CHIPSetupPayload * payload = - [CHIPOnboardingPayloadParser setupPayloadForOnboardingPayload:@"CH:R5L90UV200A3L90A33P0GQ670.QT52B.E23O6DE044U1077U.3" + [CHIPOnboardingPayloadParser setupPayloadForOnboardingPayload:@"MT:R5L90MP500K64J0A33P0GQ670.QT52B.E23O6DE0Y3U10O0" ofType:CHIPOnboardingPayloadTypeNFC error:&error]; @@ -140,7 +140,7 @@ - (void)testOnboardingPayloadParser_NFC_NoError XCTAssertEqual(payload.setUpPINCode.unsignedIntegerValue, 2048); XCTAssertEqual(payload.vendorID.unsignedIntegerValue, 12); XCTAssertEqual(payload.productID.unsignedIntegerValue, 1); - XCTAssertFalse(payload.requiresCustomFlow); + XCTAssertEqual(payload.commissioningFlow, kCommissioningFlowStandard); XCTAssertEqual(payload.version.unsignedIntegerValue, 5); XCTAssertEqual(payload.rendezvousInformation, kRendezvousInformationSoftAP); } @@ -149,7 +149,7 @@ - (void)testOnboardingPayloadParser_NFC_WrongType { NSError * error; CHIPSetupPayload * payload = - [CHIPOnboardingPayloadParser setupPayloadForOnboardingPayload:@"CH:R5L90UV200A3L90A33P0GQ670.QT52B.E23O6DE044U1077U.3" + [CHIPOnboardingPayloadParser setupPayloadForOnboardingPayload:@"MT:R5L90MP500K64J0A33P0GQ670.QT52B.E23O6DE0Y3U10O0" ofType:CHIPOnboardingPayloadTypeManualCode error:&error]; @@ -171,7 +171,7 @@ - (void)testManualParser XCTAssertEqual(payload.setUpPINCode.unsignedIntegerValue, 123456780); XCTAssertEqual(payload.vendorID.unsignedIntegerValue, 1); XCTAssertEqual(payload.productID.unsignedIntegerValue, 1); - XCTAssertTrue(payload.requiresCustomFlow); + XCTAssertEqual(payload.commissioningFlow, kCommissioningFlowCustom); XCTAssertEqual(payload.version.unsignedIntegerValue, 0); XCTAssertEqual(payload.rendezvousInformation, kRendezvousInformationNone); } @@ -190,7 +190,7 @@ - (void)testQRCodeParser_Error { NSError * error; CHIPQRCodeSetupPayloadParser * parser = - [[CHIPQRCodeSetupPayloadParser alloc] initWithBase38Representation:@"CH:J5L900CK70WWI0000"]; + [[CHIPQRCodeSetupPayloadParser alloc] initWithBase38Representation:@"MT:R5L90MP500K64J0000."]; CHIPSetupPayload * payload = [parser populatePayload:&error]; XCTAssertNil(payload); @@ -201,7 +201,7 @@ - (void)testQRCodeParser { NSError * error; CHIPQRCodeSetupPayloadParser * parser = - [[CHIPQRCodeSetupPayloadParser alloc] initWithBase38Representation:@"CH:R5L90UV200A3L900000"]; + [[CHIPQRCodeSetupPayloadParser alloc] initWithBase38Representation:@"MT:R5L90MP500K64J00000"]; CHIPSetupPayload * payload = [parser populatePayload:&error]; XCTAssertNotNil(payload); @@ -211,7 +211,7 @@ - (void)testQRCodeParser XCTAssertEqual(payload.setUpPINCode.unsignedIntegerValue, 2048); XCTAssertEqual(payload.vendorID.unsignedIntegerValue, 12); XCTAssertEqual(payload.productID.unsignedIntegerValue, 1); - XCTAssertFalse(payload.requiresCustomFlow); + XCTAssertEqual(payload.commissioningFlow, kCommissioningFlowStandard); XCTAssertEqual(payload.version.unsignedIntegerValue, 5); XCTAssertEqual(payload.rendezvousInformation, kRendezvousInformationSoftAP); } @@ -219,8 +219,8 @@ - (void)testQRCodeParser - (void)testQRCodeParserWithOptionalData { NSError * error; - CHIPQRCodeSetupPayloadParser * parser = [[CHIPQRCodeSetupPayloadParser alloc] - initWithBase38Representation:@"CH:R5L90UV200A3L90A33P0GQ670.QT52B.E23O6DE044U1077U.3"]; + CHIPQRCodeSetupPayloadParser * parser = + [[CHIPQRCodeSetupPayloadParser alloc] initWithBase38Representation:@"MT:R5L90MP500K64J0A33P0GQ670.QT52B.E23O6DE0Y3U10O0"]; CHIPSetupPayload * payload = [parser populatePayload:&error]; XCTAssertNotNil(payload); @@ -231,7 +231,7 @@ - (void)testQRCodeParserWithOptionalData XCTAssertEqual(payload.setUpPINCode.unsignedIntegerValue, 2048); XCTAssertEqual(payload.vendorID.unsignedIntegerValue, 12); XCTAssertEqual(payload.productID.unsignedIntegerValue, 1); - XCTAssertFalse(payload.requiresCustomFlow); + XCTAssertEqual(payload.commissioningFlow, kCommissioningFlowStandard); XCTAssertEqual(payload.rendezvousInformation, kRendezvousInformationSoftAP); XCTAssertTrue([payload.serialNumber isEqualToString:@"1"]); diff --git a/src/setup_payload/Base38.cpp b/src/setup_payload/Base38.cpp index 912bbfdcf3853e..c7283ad7777dc7 100644 --- a/src/setup_payload/Base38.cpp +++ b/src/setup_payload/Base38.cpp @@ -191,7 +191,14 @@ CHIP_ERROR base38Decode(std::string base38, std::vector & result) for (int i = 0; i < bytesInDecodedChunk; i++) { - result.push_back(static_cast(value >> (8 * i))); + result.push_back(static_cast(value)); + value >>= 8; + } + + if (value > 0) + { + // encoded value is too big to represent a correct chunk of size 1, 2 or 3 bytes + return CHIP_ERROR_INVALID_ARGUMENT; } } return CHIP_NO_ERROR; diff --git a/src/setup_payload/ManualSetupPayloadGenerator.cpp b/src/setup_payload/ManualSetupPayloadGenerator.cpp index 0961a13f3e8a57..cf9fdab8644ef2 100644 --- a/src/setup_payload/ManualSetupPayloadGenerator.cpp +++ b/src/setup_payload/ManualSetupPayloadGenerator.cpp @@ -46,7 +46,7 @@ static uint32_t chunk1PayloadRepresentation(const SetupPayload & payload) "Discriminator won't fit"); uint32_t discriminatorChunk = (payload.discriminator >> kDiscriminatorShift) & kDiscriminatorMask; - uint32_t vidPidPresentFlag = payload.requiresCustomFlow ? 1 : 0; + uint32_t vidPidPresentFlag = payload.commissioningFlow == CommissioningFlow::kCustom ? 1 : 0; uint32_t result = (discriminatorChunk << kManualSetupChunk1DiscriminatorMsbitsPos) | (vidPidPresentFlag << kManualSetupChunk1VidPidPresentBitPos); @@ -129,7 +129,7 @@ CHIP_ERROR ManualSetupPayloadGenerator::payloadDecimalStringRepresentation(std:: decimalString += decimalStringWithPadding(chunk2, kManualSetupCodeChunk2CharLength); decimalString += decimalStringWithPadding(chunk3, kManualSetupCodeChunk3CharLength); - if (mSetupPayload.requiresCustomFlow) + if (mSetupPayload.commissioningFlow == CommissioningFlow::kCustom) { decimalString += decimalStringWithPadding(mSetupPayload.vendorID, kManualSetupVendorIdCharLength); decimalString += decimalStringWithPadding(mSetupPayload.productID, kManualSetupProductIdCharLength); diff --git a/src/setup_payload/ManualSetupPayloadParser.cpp b/src/setup_payload/ManualSetupPayloadParser.cpp index e804134e7ed27e..aef68a83cd42de 100644 --- a/src/setup_payload/ManualSetupPayloadParser.cpp +++ b/src/setup_payload/ManualSetupPayloadParser.cpp @@ -188,7 +188,7 @@ CHIP_ERROR ManualSetupPayloadParser::populatePayload(SetupPayload & outPayload) } outPayload.productID = static_cast(productID); } - outPayload.requiresCustomFlow = isLongCode ? 1 : 0; + outPayload.commissioningFlow = isLongCode ? CommissioningFlow::kCustom : CommissioningFlow::kStandard; static_assert(kSetupPINCodeFieldLengthInBits <= 32, "Won't fit in uint32_t"); outPayload.setUpPINCode = static_cast(setUpPINCode); static_assert(kManualSetupDiscriminatorFieldLengthInBits <= 16, "Won't fit in uint16_t"); diff --git a/src/setup_payload/QRCodeSetupPayloadGenerator.cpp b/src/setup_payload/QRCodeSetupPayloadGenerator.cpp index 7a7583544e4c2e..88c20f6ca1c424 100644 --- a/src/setup_payload/QRCodeSetupPayloadGenerator.cpp +++ b/src/setup_payload/QRCodeSetupPayloadGenerator.cpp @@ -176,7 +176,8 @@ static CHIP_ERROR generateBitSet(SetupPayload & payload, uint8_t * bits, uint8_t err = populateBits(bits, offset, payload.version, kVersionFieldLengthInBits, kTotalPayloadDataSizeInBits); err = populateBits(bits, offset, payload.vendorID, kVendorIDFieldLengthInBits, kTotalPayloadDataSizeInBits); err = populateBits(bits, offset, payload.productID, kProductIDFieldLengthInBits, kTotalPayloadDataSizeInBits); - err = populateBits(bits, offset, payload.requiresCustomFlow, kCustomFlowRequiredFieldLengthInBits, kTotalPayloadDataSizeInBits); + err = populateBits(bits, offset, static_cast(payload.commissioningFlow), kCommissioningFlowFieldLengthInBits, + kTotalPayloadDataSizeInBits); err = populateBits(bits, offset, payload.rendezvousInformation.Raw(), kRendezvousInfoFieldLengthInBits, kTotalPayloadDataSizeInBits); err = populateBits(bits, offset, payload.discriminator, kPayloadDiscriminatorFieldLengthInBits, kTotalPayloadDataSizeInBits); diff --git a/src/setup_payload/QRCodeSetupPayloadParser.cpp b/src/setup_payload/QRCodeSetupPayloadParser.cpp index 657fefe0c7d8d2..e7c61a151b0f2b 100644 --- a/src/setup_payload/QRCodeSetupPayloadParser.cpp +++ b/src/setup_payload/QRCodeSetupPayloadParser.cpp @@ -376,13 +376,16 @@ CHIP_ERROR QRCodeSetupPayloadParser::populatePayload(SetupPayload & outPayload) static_assert(kProductIDFieldLengthInBits <= 16, "Won't fit in uint16_t"); outPayload.productID = static_cast(dest); - err = readBits(buf, indexToReadFrom, dest, kCustomFlowRequiredFieldLengthInBits); + err = readBits(buf, indexToReadFrom, dest, kCommissioningFlowFieldLengthInBits); SuccessOrExit(err); - static_assert(kCustomFlowRequiredFieldLengthInBits <= 8, "Won't fit in uint8_t"); - outPayload.requiresCustomFlow = static_cast(dest); + static_assert(kCommissioningFlowFieldLengthInBits <= std::numeric_limits>::digits, + "Won't fit in CommissioningFlow"); + outPayload.commissioningFlow = static_cast(dest); err = readBits(buf, indexToReadFrom, dest, kRendezvousInfoFieldLengthInBits); SuccessOrExit(err); + static_assert(kRendezvousInfoFieldLengthInBits <= 8 * sizeof(RendezvousInformationFlag), + "Won't fit in RendezvousInformationFlags"); outPayload.rendezvousInformation = RendezvousInformationFlags(static_cast(dest)); err = readBits(buf, indexToReadFrom, dest, kPayloadDiscriminatorFieldLengthInBits); diff --git a/src/setup_payload/SetupPayload.cpp b/src/setup_payload/SetupPayload.cpp index b0b681ff4b64e3..abf7962a3d9796 100644 --- a/src/setup_payload/SetupPayload.cpp +++ b/src/setup_payload/SetupPayload.cpp @@ -46,13 +46,18 @@ bool IsVendorTag(uint8_t tag) // Check the Setup Payload for validity // // `vendor_id` and `product_id` are allowed all of uint16_t -// `requiresCustomFlow` is not checked since it is a bool bool SetupPayload::isValidQRCodePayload() { if (version >= 1 << kVersionFieldLengthInBits) { return false; } + + if (static_cast(commissioningFlow) > static_cast((1 << kCommissioningFlowFieldLengthInBits) - 1)) + { + return false; + } + chip::RendezvousInformationFlags allvalid(RendezvousInformationFlag::kBLE, RendezvousInformationFlag::kOnNetwork, RendezvousInformationFlag::kSoftAP); if (!rendezvousInformation.HasOnly(allvalid)) @@ -287,7 +292,7 @@ bool SetupPayload::operator==(SetupPayload & input) std::vector inputOptionalExtensionData; VerifyOrExit(this->version == input.version && this->vendorID == input.vendorID && this->productID == input.productID && - this->requiresCustomFlow == input.requiresCustomFlow && + this->commissioningFlow == input.commissioningFlow && this->rendezvousInformation == input.rendezvousInformation && this->discriminator == input.discriminator && this->setUpPINCode == input.setUpPINCode, isIdentical = false); diff --git a/src/setup_payload/SetupPayload.h b/src/setup_payload/SetupPayload.h index c5c628d0b983d4..ba53f63baef28b 100644 --- a/src/setup_payload/SetupPayload.h +++ b/src/setup_payload/SetupPayload.h @@ -23,8 +23,8 @@ #pragma once +#include #include -#include #include #include @@ -33,13 +33,18 @@ namespace chip { -// TODO this should point to the spec -const int kVersionFieldLengthInBits = 3; -const int kVendorIDFieldLengthInBits = 16; -const int kProductIDFieldLengthInBits = 16; -const int kCustomFlowRequiredFieldLengthInBits = 1; -const int kRendezvousInfoFieldLengthInBits = 8; -const int kPayloadDiscriminatorFieldLengthInBits = 12; +// See section 5.1.2. QR Code in the Matter specification +const int kVersionFieldLengthInBits = 3; +const int kVendorIDFieldLengthInBits = 16; +const int kProductIDFieldLengthInBits = 16; +const int kCommissioningFlowFieldLengthInBits = 2; +const int kRendezvousInfoFieldLengthInBits = 8; +const int kPayloadDiscriminatorFieldLengthInBits = 12; +const int kSetupPINCodeFieldLengthInBits = 27; +const int kPaddingFieldLengthInBits = 4; +const int kRawVendorTagLengthInBits = 7; + +// See section 5.1.3. Manual Pairing Code in the Matter specification const int kManualSetupDiscriminatorFieldLengthInBits = 4; const int kManualSetupChunk1DiscriminatorMsbitsPos = 0; const int kManualSetupChunk1DiscriminatorMsbitsLength = 2; @@ -51,10 +56,6 @@ const int kManualSetupChunk2DiscriminatorLsbitsPos = (kManualSetupChunk2PINCodeL const int kManualSetupChunk2DiscriminatorLsbitsLength = 2; const int kManualSetupChunk3PINCodeMsbitsPos = 0; const int kManualSetupChunk3PINCodeMsbitsLength = 13; -const int kSetupPINCodeFieldLengthInBits = 27; -const int kPaddingFieldLengthInBits = 5; - -const int kRawVendorTagLengthInBits = 7; const int kManualSetupShortCodeCharLength = 10; const int kManualSetupLongCodeCharLength = 20; @@ -74,7 +75,7 @@ const int kTotalPayloadDataSizeInBits = kVersionFieldLengthInBits + kVendorIDFieldLengthInBits + kProductIDFieldLengthInBits + - kCustomFlowRequiredFieldLengthInBits + + kCommissioningFlowFieldLengthInBits + kRendezvousInfoFieldLengthInBits + kPayloadDiscriminatorFieldLengthInBits + kSetupPINCodeFieldLengthInBits + @@ -83,17 +84,24 @@ const int kTotalPayloadDataSizeInBits = const int kTotalPayloadDataSizeInBytes = kTotalPayloadDataSizeInBits / 8; -const char * const kQRCodePrefix = "CH:"; +const char * const kQRCodePrefix = "MT:"; /// The rendezvous type this device supports. -enum class RendezvousInformationFlag : uint16_t +enum class RendezvousInformationFlag : uint8_t { kNone = 0, ///< Device does not support any method for rendezvous kSoftAP = 1 << 0, ///< Device supports Wi-Fi softAP kBLE = 1 << 1, ///< Device supports BLE kOnNetwork = 1 << 2, ///< Device supports Setup on network }; -using RendezvousInformationFlags = chip::BitFlags; +using RendezvousInformationFlags = chip::BitFlags; + +enum class CommissioningFlow : uint8_t +{ + kStandard = 0, ///< Device automatically enters pairing mode upon power-up + kUserActionRequired, ///< Device requires a user interaction to enter pairing mode + kCustom, ///< Commissioning steps should be retrieved from the distributed compliance ledger +}; enum optionalQRCodeInfoType { @@ -145,13 +153,13 @@ class SetupPayload friend class QRCodeSetupPayloadParser; public: - uint8_t version; - uint16_t vendorID; - uint16_t productID; - bool requiresCustomFlow; - RendezvousInformationFlags rendezvousInformation; - uint16_t discriminator; - uint32_t setUpPINCode; + uint8_t version = 0; + uint16_t vendorID = 0; + uint16_t productID = 0; + CommissioningFlow commissioningFlow = CommissioningFlow::kStandard; + RendezvousInformationFlags rendezvousInformation = RendezvousInformationFlag::kNone; + uint16_t discriminator = 0; + uint32_t setUpPINCode = 0; /** @brief A function to add an optional vendor data * @param tag 7 bit [0-127] tag number @@ -201,12 +209,6 @@ class SetupPayload **/ CHIP_ERROR removeSerialNumber(); - // Test that the Setup Payload is within expected value ranges - SetupPayload() : - version(0), vendorID(0), productID(0), requiresCustomFlow(0), rendezvousInformation(RendezvousInformationFlag::kNone), - discriminator(0), setUpPINCode(0) - {} - bool isValidQRCodePayload(); bool isValidManualCode(); bool operator==(SetupPayload & input); diff --git a/src/setup_payload/SetupPayloadHelper.cpp b/src/setup_payload/SetupPayloadHelper.cpp index 41e48bda537ef9..9f2a32f3957294 100644 --- a/src/setup_payload/SetupPayloadHelper.cpp +++ b/src/setup_payload/SetupPayloadHelper.cpp @@ -34,7 +34,7 @@ enum SetupPayloadKey SetupPayloadKey_Version, SetupPayloadKey_VendorID, SetupPayloadKey_ProductID, - SetupPayloadKey_RequiresCustomFlowTrue, + SetupPayloadKey_CommissioningFlow, SetupPayloadKey_RendezVousInformation, SetupPayloadKey_Discriminator, SetupPayloadKey_SetupPINCode, @@ -64,10 +64,9 @@ static CHIP_ERROR resolveSetupPayloadParameter(SetupPayloadParameter & parameter { parameter.key = SetupPayloadKey_ProductID; } - else if (key == "requiresCustomFlowTrue") + else if (key == "commissioningFlow") { - parameter.key = SetupPayloadKey_RequiresCustomFlowTrue; - shouldHaveValue = false; + parameter.key = SetupPayloadKey_CommissioningFlow; } else if (key == "rendezVousInformation") { @@ -119,9 +118,9 @@ static CHIP_ERROR addParameter(SetupPayload & setupPayload, const SetupPayloadPa ChipLogDetail(SetupPayload, "Loaded productID: %u", (uint16_t) parameter.uintValue); setupPayload.productID = static_cast(parameter.uintValue); break; - case SetupPayloadKey_RequiresCustomFlowTrue: - ChipLogDetail(SetupPayload, "Requires custom flow was set to true"); - setupPayload.requiresCustomFlow = true; + case SetupPayloadKey_CommissioningFlow: + ChipLogDetail(SetupPayload, "Commissioning flow: %u", (uint8_t) parameter.uintValue); + setupPayload.commissioningFlow = static_cast(parameter.uintValue); break; case SetupPayloadKey_RendezVousInformation: ChipLogDetail(SetupPayload, "Loaded rendezvousInfo: %u", (uint16_t) parameter.uintValue); diff --git a/src/setup_payload/java/SetupPayloadParser-JNI.cpp b/src/setup_payload/java/SetupPayloadParser-JNI.cpp index 456eb7d777e14c..c91360f2c6169b 100644 --- a/src/setup_payload/java/SetupPayloadParser-JNI.cpp +++ b/src/setup_payload/java/SetupPayloadParser-JNI.cpp @@ -88,17 +88,17 @@ jobject TransformSetupPayload(JNIEnv * env, SetupPayload & payload) jmethodID setupConstr = env->GetMethodID(setupPayloadClass, "", "()V"); jobject setupPayload = env->NewObject(setupPayloadClass, setupConstr); - jfieldID version = env->GetFieldID(setupPayloadClass, "version", "I"); - jfieldID vendorId = env->GetFieldID(setupPayloadClass, "vendorId", "I"); - jfieldID productId = env->GetFieldID(setupPayloadClass, "productId", "I"); - jfieldID requiresCustomFlow = env->GetFieldID(setupPayloadClass, "requiresCustomFlow", "Z"); - jfieldID discriminator = env->GetFieldID(setupPayloadClass, "discriminator", "I"); - jfieldID setUpPinCode = env->GetFieldID(setupPayloadClass, "setupPinCode", "J"); + jfieldID version = env->GetFieldID(setupPayloadClass, "version", "I"); + jfieldID vendorId = env->GetFieldID(setupPayloadClass, "vendorId", "I"); + jfieldID productId = env->GetFieldID(setupPayloadClass, "productId", "I"); + jfieldID commissioningFlow = env->GetFieldID(setupPayloadClass, "commissioningFlow", "I"); + jfieldID discriminator = env->GetFieldID(setupPayloadClass, "discriminator", "I"); + jfieldID setUpPinCode = env->GetFieldID(setupPayloadClass, "setupPinCode", "J"); env->SetIntField(setupPayload, version, payload.version); env->SetIntField(setupPayload, vendorId, payload.vendorID); env->SetIntField(setupPayload, productId, payload.productID); - env->SetBooleanField(setupPayload, requiresCustomFlow, payload.requiresCustomFlow); + env->SetIntField(setupPayload, commissioningFlow, static_cast(payload.commissioningFlow)); env->SetIntField(setupPayload, discriminator, payload.discriminator); env->SetLongField(setupPayload, setUpPinCode, payload.setUpPINCode); diff --git a/src/setup_payload/java/src/chip/setuppayload/SetupPayload.java b/src/setup_payload/java/src/chip/setuppayload/SetupPayload.java index 5d6eddd1b1e04e..2cd33ffc377462 100644 --- a/src/setup_payload/java/src/chip/setuppayload/SetupPayload.java +++ b/src/setup_payload/java/src/chip/setuppayload/SetupPayload.java @@ -11,8 +11,8 @@ public class SetupPayload { public int vendorId; /** The CHIP device product ID */ public int productId; - /** Boolean indicating if the CHIP device needs custom flow */ - public boolean requiresCustomFlow; + /** Commissioning flow: 0 = standard, 1 = requires user action, 2 = custom */ + public int commissioningFlow; /** The CHIP device supported rendezvous flags */ public int rendezvousInformation; /** The CHIP device discriminator */ @@ -30,14 +30,14 @@ public SetupPayload( int version, int vendorId, int productId, - boolean requiresCustomFlow, + int commissioningFlow, int rendezvousInfo, int discriminator, long setupPinCode) { this.version = version; this.vendorId = vendorId; this.productId = productId; - this.requiresCustomFlow = requiresCustomFlow; + this.commissioningFlow = commissioningFlow; this.rendezvousInformation = rendezvousInfo; this.discriminator = discriminator; this.setupPinCode = setupPinCode; diff --git a/src/setup_payload/tests/TestHelpers.h b/src/setup_payload/tests/TestHelpers.h index 4f35b0482587e1..37e4fdedc47b9a 100644 --- a/src/setup_payload/tests/TestHelpers.h +++ b/src/setup_payload/tests/TestHelpers.h @@ -36,6 +36,8 @@ const uint32_t kOptionalDefaultIntValue = 12; const char * kSerialNumberDefaultStringValue = "123456789"; const uint32_t kSerialNumberDefaultUInt32Value = 123456789; +constexpr const char * kDefaultPayloadQRCode = "MT:R5L90MP500K64J00000"; + inline SetupPayload GetDefaultPayload() { SetupPayload payload; @@ -43,7 +45,7 @@ inline SetupPayload GetDefaultPayload() payload.version = 5; payload.vendorID = 12; payload.productID = 1; - payload.requiresCustomFlow = 0; + payload.commissioningFlow = CommissioningFlow::kStandard; payload.rendezvousInformation = RendezvousInformationFlags(RendezvousInformationFlag::kSoftAP); payload.discriminator = 128; payload.setUpPINCode = 2048; @@ -97,7 +99,7 @@ inline std::string toBinaryRepresentation(std::string base38Result) pos -= kProductIDFieldLengthInBits; binaryResult.insert(pos, " "); - pos -= kCustomFlowRequiredFieldLengthInBits; + pos -= kCommissioningFlowFieldLengthInBits; binaryResult.insert(pos, " "); pos -= kRendezvousInfoFieldLengthInBits; @@ -120,7 +122,7 @@ inline bool CompareBinary(SetupPayload & payload, std::string & expectedBinary) QRCodeSetupPayloadGenerator generator(payload); std::string result; - uint8_t optionalInfo[kDefaultBufferSizeInBytes]; + uint8_t optionalInfo[kDefaultBufferSizeInBytes] = {}; generator.payloadBase38Representation(result, optionalInfo, sizeof(optionalInfo)); std::string resultBinary = toBinaryRepresentation(result); @@ -132,12 +134,12 @@ inline bool CheckWriteRead(SetupPayload & inPayload) SetupPayload outPayload; std::string result; - QRCodeSetupPayloadGenerator generator(inPayload); uint8_t optionalInfo[kDefaultBufferSizeInBytes]; - generator.payloadBase38Representation(result, optionalInfo, sizeof(optionalInfo)); + memset(optionalInfo, 0xFF, sizeof(optionalInfo)); + QRCodeSetupPayloadGenerator(inPayload).payloadBase38Representation(result, optionalInfo, sizeof(optionalInfo)); - QRCodeSetupPayloadParser parser = QRCodeSetupPayloadParser(result); - parser.populatePayload(outPayload); + outPayload = {}; + QRCodeSetupPayloadParser(result).populatePayload(outPayload); return inPayload == outPayload; } diff --git a/src/setup_payload/tests/TestManualCode.cpp b/src/setup_payload/tests/TestManualCode.cpp index 67577b30b2b419..5f8232a8fa26ae 100644 --- a/src/setup_payload/tests/TestManualCode.cpp +++ b/src/setup_payload/tests/TestManualCode.cpp @@ -78,8 +78,8 @@ void TestDecimalRepresentation_PartialPayload(nlTestSuite * inSuite, void * inCo void TestDecimalRepresentation_PartialPayload_RequiresCustomFlow(nlTestSuite * inSuite, void * inContext) { - SetupPayload payload = GetDefaultPayload(); - payload.requiresCustomFlow = true; + SetupPayload payload = GetDefaultPayload(); + payload.commissioningFlow = CommissioningFlow::kCustom; std::string expectedResult = "63610875350000000000"; @@ -88,10 +88,10 @@ void TestDecimalRepresentation_PartialPayload_RequiresCustomFlow(nlTestSuite * i void TestDecimalRepresentation_FullPayloadWithZeros(nlTestSuite * inSuite, void * inContext) { - SetupPayload payload = GetDefaultPayload(); - payload.requiresCustomFlow = true; - payload.vendorID = 1; - payload.productID = 1; + SetupPayload payload = GetDefaultPayload(); + payload.commissioningFlow = CommissioningFlow::kCustom; + payload.vendorID = 1; + payload.productID = 1; std::string expectedResult = "63610875350000100001"; @@ -100,10 +100,10 @@ void TestDecimalRepresentation_FullPayloadWithZeros(nlTestSuite * inSuite, void void TestDecimalRepresentation_FullPayloadWithoutZeros(nlTestSuite * inSuite, void * inContext) { - SetupPayload payload = GetDefaultPayload(); - payload.requiresCustomFlow = true; - payload.vendorID = 45367; - payload.productID = 14526; + SetupPayload payload = GetDefaultPayload(); + payload.commissioningFlow = CommissioningFlow::kCustom; + payload.vendorID = 45367; + payload.productID = 14526; std::string expectedResult = "63610875354536714526"; @@ -135,11 +135,11 @@ void TestDecimalRepresentation_AllZeros(nlTestSuite * inSuite, void * inContext) void TestDecimalRepresentation_AllOnes(nlTestSuite * inSuite, void * inContext) { SetupPayload payload; - payload.setUpPINCode = 0x7FFFFFF; - payload.discriminator = 0xFFF; - payload.requiresCustomFlow = true; - payload.vendorID = 65535; - payload.productID = 65535; + payload.setUpPINCode = 0x7FFFFFF; + payload.discriminator = 0xFFF; + payload.commissioningFlow = CommissioningFlow::kCustom; + payload.vendorID = 65535; + payload.productID = 65535; std::string expectedResult = "76553581916553565535"; @@ -168,9 +168,8 @@ void assertPayloadValues(nlTestSuite * inSuite, CHIP_ERROR actualError, CHIP_ERR void TestGenerateAndParser_ManualSetupCodeWithLongDiscriminator(nlTestSuite * inSuite, void * inContext) { - SetupPayload payload = GetDefaultPayload(); - payload.requiresCustomFlow = false; - payload.discriminator = 0xa1f; + SetupPayload payload = GetDefaultPayload(); + payload.discriminator = 0xa1f; { // Test short 11 digit code @@ -184,10 +183,10 @@ void TestGenerateAndParser_ManualSetupCodeWithLongDiscriminator(nlTestSuite * in payload.productID); } - payload.vendorID = 1; - payload.productID = 1; - payload.requiresCustomFlow = true; - payload.discriminator = 0xb1f; + payload.vendorID = 1; + payload.productID = 1; + payload.commissioningFlow = CommissioningFlow::kCustom; + payload.discriminator = 0xb1f; { // Test long 21 digit code @@ -233,10 +232,10 @@ void TestPayloadParser_FullPayload(nlTestSuite * inSuite, void * inContext) void TestGenerateAndParser_FullPayload(nlTestSuite * inSuite, void * inContext) { - SetupPayload payload = GetDefaultPayload(); - payload.vendorID = 1; - payload.productID = 1; - payload.requiresCustomFlow = true; + SetupPayload payload = GetDefaultPayload(); + payload.vendorID = 1; + payload.productID = 1; + payload.commissioningFlow = CommissioningFlow::kCustom; ManualSetupPayloadGenerator generator(payload); std::string result; @@ -323,10 +322,10 @@ void TestShortCodeReadWrite(nlTestSuite * inSuite, void * context) void TestLongCodeReadWrite(nlTestSuite * inSuite, void * context) { - SetupPayload inPayload = GetDefaultPayload(); - inPayload.requiresCustomFlow = true; - inPayload.vendorID = 1; - inPayload.productID = 1; + SetupPayload inPayload = GetDefaultPayload(); + inPayload.commissioningFlow = CommissioningFlow::kCustom; + inPayload.vendorID = 1; + inPayload.productID = 1; SetupPayload outPayload; std::string result; diff --git a/src/setup_payload/tests/TestQRCode.cpp b/src/setup_payload/tests/TestQRCode.cpp index f1c7cfb8545cba..786908e6c6dd09 100644 --- a/src/setup_payload/tests/TestQRCode.cpp +++ b/src/setup_payload/tests/TestQRCode.cpp @@ -63,11 +63,42 @@ void TestRendezvousFlags(nlTestSuite * inSuite, void * inContext) NL_TEST_ASSERT(inSuite, CheckWriteRead(inPayload)); } +void TestCommissioningFlow(nlTestSuite * inSuite, void * inContext) +{ + SetupPayload inPayload = GetDefaultPayload(); + + inPayload.commissioningFlow = CommissioningFlow::kStandard; + NL_TEST_ASSERT(inSuite, CheckWriteRead(inPayload)); + + inPayload.commissioningFlow = CommissioningFlow::kUserActionRequired; + NL_TEST_ASSERT(inSuite, CheckWriteRead(inPayload)); + + inPayload.commissioningFlow = CommissioningFlow::kCustom; + NL_TEST_ASSERT(inSuite, CheckWriteRead(inPayload)); +} + +void TestMaximumValues(nlTestSuite * inSuite, void * inContext) +{ + SetupPayload inPayload = GetDefaultPayload(); + + inPayload.version = static_cast((1 << kVersionFieldLengthInBits) - 1); + inPayload.vendorID = 0xFFFF; + inPayload.productID = 0xFFFF; + inPayload.commissioningFlow = CommissioningFlow::kCustom; + inPayload.rendezvousInformation = RendezvousInformationFlags( + RendezvousInformationFlag::kBLE, RendezvousInformationFlag::kSoftAP, RendezvousInformationFlag::kOnNetwork); + inPayload.discriminator = static_cast((1 << kPayloadDiscriminatorFieldLengthInBits) - 1); + inPayload.setUpPINCode = static_cast((1 << kSetupPINCodeFieldLengthInBits) - 1); + + NL_TEST_ASSERT(inSuite, inPayload.isValidQRCodePayload()); + NL_TEST_ASSERT(inSuite, CheckWriteRead(inPayload)); +} + void TestPayloadByteArrayRep(nlTestSuite * inSuite, void * inContext) { SetupPayload payload = GetDefaultPayload(); - string expected = " 00000 000000000000000100000000000 000010000000 00000001 0 0000000000000001 0000000000001100 101"; + string expected = " 0000 000000000000000100000000000 000010000000 00000001 00 0000000000000001 0000000000001100 101"; NL_TEST_ASSERT(inSuite, CompareBinary(payload, expected)); } @@ -81,8 +112,7 @@ void TestPayloadBase38Rep(nlTestSuite * inSuite, void * inContext) bool didSucceed = err == CHIP_NO_ERROR; NL_TEST_ASSERT(inSuite, didSucceed == true); - string expected = "CH:R5L90UV200A3L900000"; - NL_TEST_ASSERT(inSuite, result == expected); + NL_TEST_ASSERT(inSuite, result == kDefaultPayloadQRCode); } void TestBase38(nlTestSuite * inSuite, void * inContext) @@ -105,8 +135,7 @@ void TestBase38(nlTestSuite * inSuite, void * inContext) input[2] = 255; NL_TEST_ASSERT(inSuite, base38Encode(input, 3) == "Q-M08"); - // testing optimized encoding - // verify that we can't optimize a low value using less characters + // verify chunks of 1,2 and 3 bytes result in fixed-length strings padded with '0' // for 1 byte we need always 2 characters input[0] = 35; NL_TEST_ASSERT(inSuite, base38Encode(input, 1) == "Z0"); @@ -120,7 +149,7 @@ void TestBase38(nlTestSuite * inSuite, void * inContext) input[2] = 0; NL_TEST_ASSERT(inSuite, base38Encode(input, 3) == "81000"); - // verify maximal available values for each chunk size to check selecting proper characters number + // verify maximum available values for each chunk size to check selecting proper characters number // for 1 byte we need 2 characters input[0] = 255; NL_TEST_ASSERT(inSuite, base38Encode(input, 1) == "R6"); @@ -156,13 +185,11 @@ void TestBase38(nlTestSuite * inSuite, void * inContext) NL_TEST_ASSERT(inSuite, base38Decode("", decoded) == CHIP_NO_ERROR); NL_TEST_ASSERT(inSuite, decoded.empty()); - // outside valid chars + // test invalid characters NL_TEST_ASSERT(inSuite, base38Decode("0\001", decoded) == CHIP_ERROR_INVALID_INTEGER_VALUE); NL_TEST_ASSERT(inSuite, base38Decode("\0010", decoded) == CHIP_ERROR_INVALID_INTEGER_VALUE); NL_TEST_ASSERT(inSuite, base38Decode("[0", decoded) == CHIP_ERROR_INVALID_INTEGER_VALUE); NL_TEST_ASSERT(inSuite, base38Decode("0[", decoded) == CHIP_ERROR_INVALID_INTEGER_VALUE); - - // BOGUS chars NL_TEST_ASSERT(inSuite, base38Decode(" 0", decoded) == CHIP_ERROR_INVALID_INTEGER_VALUE); NL_TEST_ASSERT(inSuite, base38Decode("!0", decoded) == CHIP_ERROR_INVALID_INTEGER_VALUE); NL_TEST_ASSERT(inSuite, base38Decode("\"0", decoded) == CHIP_ERROR_INVALID_INTEGER_VALUE); @@ -182,13 +209,20 @@ void TestBase38(nlTestSuite * inSuite, void * inContext) NL_TEST_ASSERT(inSuite, base38Decode(">0", decoded) == CHIP_ERROR_INVALID_INTEGER_VALUE); NL_TEST_ASSERT(inSuite, base38Decode("@0", decoded) == CHIP_ERROR_INVALID_INTEGER_VALUE); - // odd byte(s) cases - NL_TEST_ASSERT(inSuite, base38Decode("R6", decoded) == CHIP_NO_ERROR); // this is 255 - NL_TEST_ASSERT(inSuite, decoded.size() == 1 && decoded[0] == 255); - NL_TEST_ASSERT(inSuite, base38Decode("S600", decoded) == CHIP_NO_ERROR); // this is 256, needs 2 output bytes - NL_TEST_ASSERT(inSuite, decoded.size() == 2 && decoded[0] + decoded[1] * 256 == 256); - NL_TEST_ASSERT(inSuite, base38Decode("..00", decoded) == CHIP_NO_ERROR); // this is (38*38)-1, or 1443, needs 2 output bytes - NL_TEST_ASSERT(inSuite, decoded.size() == 2 && decoded[0] + decoded[1] * 256 == (kRadix * kRadix) - 1); + // test strings that encode maximum values + NL_TEST_ASSERT(inSuite, base38Decode("R6", decoded) == CHIP_NO_ERROR); // this is 0xFF + NL_TEST_ASSERT(inSuite, decoded == std::vector({ 255 })); + NL_TEST_ASSERT(inSuite, base38Decode("S6", decoded) == CHIP_ERROR_INVALID_ARGUMENT); // trying to encode 0xFF + 1 in 2 chars + NL_TEST_ASSERT(inSuite, base38Decode("S600", decoded) == CHIP_NO_ERROR); // this is 0xFF + 1, needs 4 chars + NL_TEST_ASSERT(inSuite, decoded == std::vector({ 0, 1 })); + NL_TEST_ASSERT(inSuite, base38Decode("NE71", decoded) == CHIP_NO_ERROR); // this is 0xFFFF + NL_TEST_ASSERT(inSuite, decoded == std::vector({ 255, 255 })); + NL_TEST_ASSERT(inSuite, base38Decode("OE71", decoded) == CHIP_ERROR_INVALID_ARGUMENT); // trying to encode 0xFFFF + 1 in 4 chars + NL_TEST_ASSERT(inSuite, base38Decode("OE710", decoded) == CHIP_NO_ERROR); // this is 0xFFFF + 1, needs 5 chars + NL_TEST_ASSERT(inSuite, decoded == std::vector({ 0, 0, 1 })); + NL_TEST_ASSERT(inSuite, base38Decode("PLS18", decoded) == CHIP_NO_ERROR); // this is 0xFFFFFF + NL_TEST_ASSERT(inSuite, decoded == std::vector({ 255, 255, 255 })); + NL_TEST_ASSERT(inSuite, base38Decode("QLS18", decoded) == CHIP_ERROR_INVALID_ARGUMENT); // trying to encode 0xFFFFFF + 1 } void TestBitsetLen(nlTestSuite * inSuite, void * inContext) @@ -201,21 +235,24 @@ void TestSetupPayloadVerify(nlTestSuite * inSuite, void * inContext) SetupPayload payload = GetDefaultPayload(); NL_TEST_ASSERT(inSuite, payload.isValidQRCodePayload() == true); - // test invalid version - SetupPayload test_payload = payload; - test_payload.version = 1 << kVersionFieldLengthInBits; + // test invalid commissioning flow + SetupPayload test_payload = payload; + test_payload.commissioningFlow = CommissioningFlow::kCustom; + NL_TEST_ASSERT(inSuite, test_payload.isValidQRCodePayload()); + + test_payload.commissioningFlow = static_cast(1 << kCommissioningFlowFieldLengthInBits); NL_TEST_ASSERT(inSuite, test_payload.isValidQRCodePayload() == false); - // test invalid rendezvousInformation - test_payload = payload; - test_payload.rendezvousInformation = static_cast(1 << kRendezvousInfoFieldLengthInBits); + // test invalid version + test_payload = payload; + test_payload.version = 1 << kVersionFieldLengthInBits; NL_TEST_ASSERT(inSuite, test_payload.isValidQRCodePayload() == false); // test invalid rendezvousInformation test_payload = payload; RendezvousInformationFlags invalid = RendezvousInformationFlags( RendezvousInformationFlag::kBLE, RendezvousInformationFlag::kSoftAP, RendezvousInformationFlag::kOnNetwork); - invalid.SetRaw(static_cast(invalid.Raw() + 1)); + invalid.SetRaw(static_cast(invalid.Raw() + 1)); test_payload.rendezvousInformation = invalid; NL_TEST_ASSERT(inSuite, test_payload.isValidQRCodePayload() == false); @@ -232,7 +269,8 @@ void TestSetupPayloadVerify(nlTestSuite * inSuite, void * inContext) void TestInvalidQRCodePayload_WrongCharacterSet(nlTestSuite * inSuite, void * inContext) { - string invalidString = "adas12AA"; + string invalidString = kDefaultPayloadQRCode; + invalidString.back() = ' '; // space is not contained in the base38 alphabet QRCodeSetupPayloadParser parser = QRCodeSetupPayloadParser(invalidString); SetupPayload payload; @@ -244,7 +282,9 @@ void TestInvalidQRCodePayload_WrongCharacterSet(nlTestSuite * inSuite, void * in void TestInvalidQRCodePayload_WrongLength(nlTestSuite * inSuite, void * inContext) { - string invalidString = "AA12"; + string invalidString = kDefaultPayloadQRCode; + invalidString.pop_back(); + QRCodeSetupPayloadParser parser = QRCodeSetupPayloadParser(invalidString); SetupPayload payload; CHIP_ERROR err = parser.populatePayload(payload); @@ -258,8 +298,7 @@ void TestPayloadEquality(nlTestSuite * inSuite, void * inContext) SetupPayload payload = GetDefaultPayload(); SetupPayload equalPayload = GetDefaultPayload(); - bool result = payload == equalPayload; - NL_TEST_ASSERT(inSuite, result == true); + NL_TEST_ASSERT(inSuite, payload == equalPayload); } void TestPayloadInEquality(nlTestSuite * inSuite, void * inContext) @@ -270,8 +309,7 @@ void TestPayloadInEquality(nlTestSuite * inSuite, void * inContext) unequalPayload.discriminator = 28; unequalPayload.setUpPINCode = 121233; - bool result = payload == unequalPayload; - NL_TEST_ASSERT(inSuite, result == false); + NL_TEST_ASSERT(inSuite, !(payload == unequalPayload)); } void TestQRCodeToPayloadGeneration(nlTestSuite * inSuite, void * inContext) @@ -298,22 +336,22 @@ void TestQRCodeToPayloadGeneration(nlTestSuite * inSuite, void * inContext) void TestExtractPayload(nlTestSuite * inSuite, void * inContext) { - NL_TEST_ASSERT(inSuite, extractPayload(string("CH:ABC")) == string("ABC")); - NL_TEST_ASSERT(inSuite, extractPayload(string("CH:")) == string("")); + NL_TEST_ASSERT(inSuite, extractPayload(string("MT:ABC")) == string("ABC")); + NL_TEST_ASSERT(inSuite, extractPayload(string("MT:")) == string("")); NL_TEST_ASSERT(inSuite, extractPayload(string("H:")) == string("")); - NL_TEST_ASSERT(inSuite, extractPayload(string("ASCH:")) == string("")); - NL_TEST_ASSERT(inSuite, extractPayload(string("Z%CH:ABC%")) == string("ABC")); - NL_TEST_ASSERT(inSuite, extractPayload(string("Z%CH:ABC")) == string("ABC")); - NL_TEST_ASSERT(inSuite, extractPayload(string("%Z%CH:ABC")) == string("ABC")); - NL_TEST_ASSERT(inSuite, extractPayload(string("%Z%CH:ABC%")) == string("ABC")); - NL_TEST_ASSERT(inSuite, extractPayload(string("%Z%CH:ABC%DDD")) == string("ABC")); - NL_TEST_ASSERT(inSuite, extractPayload(string("CH:ABC%DDD")) == string("ABC")); - NL_TEST_ASSERT(inSuite, extractPayload(string("CH:ABC%")) == string("ABC")); - NL_TEST_ASSERT(inSuite, extractPayload(string("%CH:")) == string("")); - NL_TEST_ASSERT(inSuite, extractPayload(string("%CH:%")) == string("")); + NL_TEST_ASSERT(inSuite, extractPayload(string("ASMT:")) == string("")); + NL_TEST_ASSERT(inSuite, extractPayload(string("Z%MT:ABC%")) == string("ABC")); + NL_TEST_ASSERT(inSuite, extractPayload(string("Z%MT:ABC")) == string("ABC")); + NL_TEST_ASSERT(inSuite, extractPayload(string("%Z%MT:ABC")) == string("ABC")); + NL_TEST_ASSERT(inSuite, extractPayload(string("%Z%MT:ABC%")) == string("ABC")); + NL_TEST_ASSERT(inSuite, extractPayload(string("%Z%MT:ABC%DDD")) == string("ABC")); + NL_TEST_ASSERT(inSuite, extractPayload(string("MT:ABC%DDD")) == string("ABC")); + NL_TEST_ASSERT(inSuite, extractPayload(string("MT:ABC%")) == string("ABC")); + NL_TEST_ASSERT(inSuite, extractPayload(string("%MT:")) == string("")); + NL_TEST_ASSERT(inSuite, extractPayload(string("%MT:%")) == string("")); NL_TEST_ASSERT(inSuite, extractPayload(string("A%")) == string("")); - NL_TEST_ASSERT(inSuite, extractPayload(string("CH:%")) == string("")); - NL_TEST_ASSERT(inSuite, extractPayload(string("%CH:ABC")) == string("ABC")); + NL_TEST_ASSERT(inSuite, extractPayload(string("MT:%")) == string("")); + NL_TEST_ASSERT(inSuite, extractPayload(string("%MT:ABC")) == string("ABC")); NL_TEST_ASSERT(inSuite, extractPayload(string("ABC")) == string("")); } @@ -326,6 +364,8 @@ void TestExtractPayload(nlTestSuite * inSuite, void * inContext) const nlTest sTests[] = { NL_TEST_DEF("Test Rendezvous Flags", TestRendezvousFlags), + NL_TEST_DEF("Test Commissioning Flow", TestCommissioningFlow), + NL_TEST_DEF("Test Maximum Values", TestMaximumValues), NL_TEST_DEF("Test Base 38", TestBase38), NL_TEST_DEF("Test Bitset Length", TestBitsetLen), NL_TEST_DEF("Test Payload Byte Array Representation", TestPayloadByteArrayRep),