diff --git a/examples/chip-tool/BUILD.gn b/examples/chip-tool/BUILD.gn index 17ed976ef3b89e..e5695118783442 100644 --- a/examples/chip-tool/BUILD.gn +++ b/examples/chip-tool/BUILD.gn @@ -27,7 +27,8 @@ executable("chip-tool") { "commands/common/NetworkCommand.cpp", "commands/echo/EchoCommand.cpp", "commands/pairing/PairingCommand.cpp", - "commands/payload/ParseCommand.cpp", + "commands/payload/QRCodeParseCommand.cpp", + "commands/payload/AdditionalDataParseCommand.cpp", "config/PersistentStorage.cpp", "main.cpp", ] diff --git a/examples/chip-tool/commands/payload/AdditionalDataParseCommand.cpp b/examples/chip-tool/commands/payload/AdditionalDataParseCommand.cpp new file mode 100644 index 00000000000000..2b0030c57253f6 --- /dev/null +++ b/examples/chip-tool/commands/payload/AdditionalDataParseCommand.cpp @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "AdditionalDataParseCommand.h" + +#include +#include + +using namespace ::chip; + +CHIP_ERROR AdditionalDataParseCommand::Run(PersistentStorage & storage, NodeId localId, NodeId remoteId) +{ + std::string payload(mPayload); + AdditionalDataPayload resultPayload; + CHIP_ERROR err = CHIP_NO_ERROR; + SuccessOrExit(err); + ChipLogProgress(chipTool, "AdditionalDataParseCommand, payload=%s", payload.c_str()); + + err = AdditionalDataPayloadParser(payload).populatePayload(resultPayload); +exit: + return err; +} diff --git a/examples/chip-tool/commands/payload/AdditionalDataParseCommand.h b/examples/chip-tool/commands/payload/AdditionalDataParseCommand.h new file mode 100644 index 00000000000000..5b4ff7592505cf --- /dev/null +++ b/examples/chip-tool/commands/payload/AdditionalDataParseCommand.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2020 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#pragma once + +#include "../common/Command.h" + +class AdditionalDataParseCommand : public Command +{ +public: + AdditionalDataParseCommand() : Command("parse-additional-data") { AddArgument("payload", &mPayload); } + CHIP_ERROR Run(PersistentStorage & storage, NodeId localId, NodeId remoteId) override; + +private: + char * mPayload; +}; diff --git a/examples/chip-tool/commands/payload/Commands.h b/examples/chip-tool/commands/payload/Commands.h index 83c1124af44910..8cf2a223a8f1ed 100644 --- a/examples/chip-tool/commands/payload/Commands.h +++ b/examples/chip-tool/commands/payload/Commands.h @@ -18,13 +18,15 @@ #pragma once -#include "ParseCommand.h" +#include "QRCodeParseCommand.h" +#include "AdditionalDataParseCommand.h" void registerCommandsPayload(Commands & commands) { const char * clusterName = "Payload"; commands_list clusterCommands = { - make_unique(), + make_unique(), + make_unique() }; commands.Register(clusterName, clusterCommands); diff --git a/examples/chip-tool/commands/payload/QRCodeParseCommand.cpp b/examples/chip-tool/commands/payload/QRCodeParseCommand.cpp new file mode 100644 index 00000000000000..7f35a7a84ea58a --- /dev/null +++ b/examples/chip-tool/commands/payload/QRCodeParseCommand.cpp @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2020 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "QRCodeParseCommand.h" +#include +#include +#include + +using namespace ::chip; + +CHIP_ERROR QRCodeParseCommand::Run(PersistentStorage & storage, NodeId localId, NodeId remoteId) +{ + std::string codeString(mCode); + SetupPayload payload; + + CHIP_ERROR err = CHIP_NO_ERROR; + err = Parse(codeString, payload); + SuccessOrExit(err); + + err = Print(payload); + SuccessOrExit(err); +exit: + return err; +} + +CHIP_ERROR QRCodeParseCommand::Print(chip::SetupPayload payload) +{ + std::string serialNumber; + std::vector optionalVendorData; + CHIP_ERROR err = CHIP_NO_ERROR; + + ChipLogProgress(SetupPayload, "RequiresCustomFlow: %u", payload.requiresCustomFlow); + ChipLogProgress(SetupPayload, "VendorID: %u", payload.vendorID); + ChipLogProgress(SetupPayload, "Version: %u", payload.version); + ChipLogProgress(SetupPayload, "ProductID: %u", payload.productID); + ChipLogProgress(SetupPayload, "Discriminator: %u", payload.discriminator); + ChipLogProgress(SetupPayload, "SetUpPINCode: %u", payload.setUpPINCode); + ChipLogProgress(SetupPayload, "RendezvousInformation: %u", payload.rendezvousInformation); + + if (payload.getSerialNumber(serialNumber) == CHIP_NO_ERROR) + { + ChipLogProgress(SetupPayload, "SerialNumber: %s", serialNumber.c_str()); + } + + optionalVendorData = payload.getAllOptionalVendorData(); + for (const OptionalQRCodeInfo & info : optionalVendorData) + { + if (info.type == optionalQRCodeInfoTypeString) + { + ChipLogProgress(SetupPayload, "OptionalQRCodeInfo: tag=%u,string value=%s", info.tag, info.data.c_str()); + } + else if (info.type == optionalQRCodeInfoTypeInt32) + { + ChipLogProgress(SetupPayload, "OptionalQRCodeInfo: tag=%u,int value=%u", info.tag, info.int32); + } + else + { + err = CHIP_ERROR_INVALID_ARGUMENT; + } + } + + SuccessOrExit(err); + +exit: + return err; +} + +CHIP_ERROR QRCodeParseCommand::Parse(std::string codeString, chip::SetupPayload & payload) +{ + + CHIP_ERROR err = CHIP_NO_ERROR; + if (IsQRCode(codeString)) + { + ChipLogDetail(SetupPayload, "Parsing base41Representation: %s", codeString.c_str()); + err = QRCodeSetupPayloadParser(codeString).populatePayload(payload); + } + else + { + ChipLogDetail(SetupPayload, "Parsing decimalRepresentation: %s", codeString.c_str()); + err = ManualSetupPayloadParser(codeString).populatePayload(payload); + } + + return err; +} + +bool QRCodeParseCommand::IsQRCode(std::string codeString) +{ + return codeString.rfind(QRCODE_PREFIX) == 0; +} diff --git a/examples/chip-tool/commands/payload/QRCodeParseCommand.h b/examples/chip-tool/commands/payload/QRCodeParseCommand.h new file mode 100644 index 00000000000000..3cc00d1b6bec45 --- /dev/null +++ b/examples/chip-tool/commands/payload/QRCodeParseCommand.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2020 Project CHIP Authors + * All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#pragma once + +#include "../common/Command.h" +#include + +class QRCodeParseCommand : public Command +{ +public: + QRCodeParseCommand() : Command("parse-qr-code") { AddArgument("code", &mCode); } + CHIP_ERROR Run(PersistentStorage & storage, NodeId localId, NodeId remoteId) override; + +private: + char * mCode; + 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/src/ble/BLEEndPoint.cpp b/src/ble/BLEEndPoint.cpp index fd3d59f71bb2a4..fec8eccad656b2 100644 --- a/src/ble/BLEEndPoint.cpp +++ b/src/ble/BLEEndPoint.cpp @@ -415,6 +415,13 @@ void BLEEndPoint::FinalizeClose(uint8_t oldState, uint8_t flags, BLE_ERROR err) // If unsubscribe fails, release BLE connection and free end point immediately. Free(); } + if (!mBle->mPlatformDelegate->UnsubscribeCharacteristic(mConnObj, &CHIP_BLE_SVC_ID, &mBle->CHIP_BLE_CHAR_3_ID)) + { + ChipLogError(Ble, "BtpEngine unsub failed"); + + // If unsubscribe fails, release BLE connection and free end point immediately. + Free(); + } else if (mConnObj != BLE_CONNECTION_UNINITIALIZED) { // Unsubscribe request was sent successfully, and a confirmation wasn't spontaneously generated or diff --git a/src/ble/BleLayer.cpp b/src/ble/BleLayer.cpp index 2a7ebf0af5cda0..240173c75d5643 100644 --- a/src/ble/BleLayer.cpp +++ b/src/ble/BleLayer.cpp @@ -163,6 +163,10 @@ const ChipBleUUID BleLayer::CHIP_BLE_CHAR_2_ID = { { // 18EE2EF5-263D-4559-959F- 0x18, 0xEE, 0x2E, 0xF5, 0x26, 0x3D, 0x45, 0x59, 0x95, 0x9F, 0x4F, 0x9C, 0x42, 0x9F, 0x9D, 0x12 } }; +const ChipBleUUID BleLayer::CHIP_BLE_CHAR_3_ID = { { // 18EE2EF5-263D-4559-959F-4F9C429F9D13 + 0x18, 0xEE, 0x2E, 0xF5, 0x26, 0x3D, 0x45, 0x59, 0x95, 0x9F, 0x4F, 0x9C, 0x42, + 0x9F, 0x9D, 0x13 } }; + void BleLayerObject::Release() { // Decrement the ref count. When it reaches zero, NULL out the pointer to the chip::System::Layer @@ -600,7 +604,7 @@ bool BleLayer::HandleSubscribeReceived(BLE_CONNECTION_OBJECT connObj, const Chip return false; } - if (UUIDsMatch(&CHIP_BLE_CHAR_2_ID, charId)) + if (UUIDsMatch(&CHIP_BLE_CHAR_2_ID, charId) || UUIDsMatch(&CHIP_BLE_CHAR_3_ID, charId)) { // Find end point already associated with BLE connection, if any. BLEEndPoint * endPoint = sBLEEndPointPool.Find(connObj); @@ -625,7 +629,7 @@ bool BleLayer::HandleSubscribeComplete(BLE_CONNECTION_OBJECT connObj, const Chip return false; } - if (UUIDsMatch(&CHIP_BLE_CHAR_2_ID, charId)) + if (UUIDsMatch(&CHIP_BLE_CHAR_2_ID, charId) || UUIDsMatch(&CHIP_BLE_CHAR_3_ID, charId)) { BLEEndPoint * endPoint = sBLEEndPointPool.Find(connObj); @@ -649,7 +653,7 @@ bool BleLayer::HandleUnsubscribeReceived(BLE_CONNECTION_OBJECT connObj, const Ch return false; } - if (UUIDsMatch(&CHIP_BLE_CHAR_2_ID, charId)) + if (UUIDsMatch(&CHIP_BLE_CHAR_2_ID, charId) || UUIDsMatch(&CHIP_BLE_CHAR_3_ID, charId)) { // Find end point already associated with BLE connection, if any. BLEEndPoint * endPoint = sBLEEndPointPool.Find(connObj); @@ -674,7 +678,7 @@ bool BleLayer::HandleUnsubscribeComplete(BLE_CONNECTION_OBJECT connObj, const Ch return false; } - if (UUIDsMatch(&CHIP_BLE_CHAR_2_ID, charId)) + if (UUIDsMatch(&CHIP_BLE_CHAR_2_ID, charId) || UUIDsMatch(&CHIP_BLE_CHAR_3_ID, charId)) { // Find end point already associated with BLE connection, if any. BLEEndPoint * endPoint = sBLEEndPointPool.Find(connObj); diff --git a/src/ble/BleLayer.h b/src/ble/BleLayer.h index 3117bdeb310f3d..7724d5ce42946c 100644 --- a/src/ble/BleLayer.h +++ b/src/ble/BleLayer.h @@ -334,6 +334,8 @@ class DLL_EXPORT BleLayer static const ChipBleUUID CHIP_BLE_CHAR_1_ID; // UUID of CHIP service characteristic used for peripheral indications. static const ChipBleUUID CHIP_BLE_CHAR_2_ID; + // UUID of CHIP service charadteristic used for additional data + static const ChipBleUUID CHIP_BLE_CHAR_3_ID; BleConnectionDelegate * mConnectionDelegate; BlePlatformDelegate * mPlatformDelegate; diff --git a/src/lib/core/CHIPTLVReader.cpp b/src/lib/core/CHIPTLVReader.cpp index 222a33d4378a74..6ffbd708e168b2 100644 --- a/src/lib/core/CHIPTLVReader.cpp +++ b/src/lib/core/CHIPTLVReader.cpp @@ -1353,7 +1353,6 @@ CHIP_ERROR TLVReader::ReadElement() mElemLenOrVal = LittleEndian::Read64(p); break; } - return VerifyElement(); } @@ -1368,13 +1367,15 @@ CHIP_ERROR TLVReader::VerifyElement() } else { - if (mElemTag == UnknownImplicitTag) + if (mElemTag == UnknownImplicitTag) { return CHIP_ERROR_UNKNOWN_IMPLICIT_TLV_TAG; + } switch (mContainerType) { case kTLVType_NotSpecified: - if (IsContextTag(mElemTag)) + if (IsContextTag(mElemTag)) { return CHIP_ERROR_INVALID_TLV_TAG; + } break; case kTLVType_Structure: if (mElemTag == AnonymousTag) diff --git a/src/lib/mdns/DiscoveryManager.cpp b/src/lib/mdns/DiscoveryManager.cpp index 40c6cf25169a78..4fcc59bf8b9e1b 100644 --- a/src/lib/mdns/DiscoveryManager.cpp +++ b/src/lib/mdns/DiscoveryManager.cpp @@ -170,9 +170,10 @@ CHIP_ERROR DiscoveryManager::PublishUnprovisionedDevice(chip::Inet::IPAddressTyp char discriminatorBuf[5]; // hex representation of 16-bit discriminator char vendorProductBuf[10]; // "FFFF+FFFF" // TODO: The text entry will be updated in the spec, update accordingly. - TextEntry entries[2] = { + TextEntry entries[3] = { { "D", nullptr, 0 }, { "VP", nullptr, 0 }, + { "RI", nullptr, 0} }; VerifyOrExit(mMdnsInitialized, error = CHIP_ERROR_INCORRECT_STATE); @@ -189,6 +190,11 @@ CHIP_ERROR DiscoveryManager::PublishUnprovisionedDevice(chip::Inet::IPAddressTyp entries[0].mDataSize = strnlen(discriminatorBuf, sizeof(discriminatorBuf)); entries[1].mData = reinterpret_cast(vendorProductBuf); entries[1].mDataSize = strnlen(discriminatorBuf, sizeof(vendorProductBuf)); + // Rotating Device ID + entries[2].mData = reinterpret_cast("112233445566"); + entries[2].mDataSize = strnlen("112233445566", sizeof("112233445566")); + + service.mTextEntryies = entries; service.mTextEntrySize = sizeof(entries) / sizeof(TextEntry); service.mPort = CHIP_PORT; diff --git a/src/lib/support/logging/CHIPLogging.h b/src/lib/support/logging/CHIPLogging.h index 75c8cac2fec70b..118185bef807ff 100644 --- a/src/lib/support/logging/CHIPLogging.h +++ b/src/lib/support/logging/CHIPLogging.h @@ -109,6 +109,7 @@ enum LogModule kLogModule_Shell, kLogModule_DeviceLayer, kLogModule_SetupPayload, + kLogModule_AdditionalDataPayload, kLogModule_AppServer, kLogModule_Discovery, diff --git a/src/platform/Linux/CHIPBluezHelper.cpp b/src/platform/Linux/CHIPBluezHelper.cpp index 8d786e7e83ac10..d561ada8926b53 100644 --- a/src/platform/Linux/CHIPBluezHelper.cpp +++ b/src/platform/Linux/CHIPBluezHelper.cpp @@ -695,6 +695,11 @@ static void BluezConnectionInit(BluezConnection * apConn) { apConn->mpC2 = char1; } + else if ((BluezIsCharOnService(char1, apConn->mpService) == TRUE) && + (strcmp(bluez_gatt_characteristic1_get_uuid(char1), CHIP_PLAT_BLE_UUID_C3_STRING) == 0)) + { + apConn->mpC3 = char1; + } else { g_object_unref(char1); @@ -1256,11 +1261,50 @@ void BluezObjectsCleanup(BluezEndpoint * apEndpoint) EndpointCleanup(apEndpoint); } +static void UpdateAdditionalDataCharacteristic(BluezGattCharacteristic1 * characteristic) +{ + // Construct the TLV for the additional data + GVariant * cValue = nullptr; + unsigned long err = 0; + TLVWriter writer; + chip::System::PacketBufferHandle bufferHandle = chip::System::PacketBuffer::New(); + chip::System::PacketBuffer * buffer = bufferHandle.Get_ForNow(); + char testRotatingDeviceId[] = "1122334455667788"; + + writer.Init(buffer); + TLVType containerType; + err = writer.StartContainer(AnonymousTag, kTLVType_Structure, containerType); + SuccessOrExit(err); + + // Adding the rotating device id to the TLV data + err = writer.PutString(CommonTag(0), testRotatingDeviceId); + SuccessOrExit(err); + + err = writer.EndContainer(containerType); + SuccessOrExit(err); + + writer.Finalize(); + + cValue = g_variant_new_from_data(G_VARIANT_TYPE("ay"), buffer->Start(), buffer->DataLength(), TRUE, NULL, NULL); + bluez_gatt_characteristic1_set_value(characteristic, cValue); + + ChipLogDetail(DeviceLayer, "Set Characteristics value to %s", g_variant_get_string(cValue, NULL)); + return; + +exit: + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "Failed to generate TLV encoded Additional Data", __func__); + } + return; +} + static void BluezPeripheralObjectsSetup(gpointer apClosure) { static const char * const c1_flags[] = { "write", nullptr }; static const char * const c2_flags[] = { "read", "indicate", nullptr }; + static const char * const c3_flags[] = { "read", nullptr }; BluezEndpoint * endpoint = static_cast(apClosure); VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__)); @@ -1290,8 +1334,23 @@ static void BluezPeripheralObjectsSetup(gpointer apClosure) g_signal_connect(endpoint->mpC2, "handle-stop-notify", G_CALLBACK(BluezCharacteristicStopNotify), apClosure); g_signal_connect(endpoint->mpC2, "handle-confirm", G_CALLBACK(BluezCharacteristicConfirm), apClosure); + // Additional data characteristics + endpoint->mpC3 = + BluezCharacteristicCreate(endpoint->mpService, g_strdup("c3"), g_strdup(CHIP_PLAT_BLE_UUID_C3_STRING), endpoint->mpRoot); + bluez_gatt_characteristic1_set_flags(endpoint->mpC3, c3_flags); + g_signal_connect(endpoint->mpC3, "handle-read-value", G_CALLBACK(BluezCharacteristicReadValue), apClosure); + g_signal_connect(endpoint->mpC3, "handle-write-value", G_CALLBACK(BluezCharacteristicWriteValueError), NULL); + g_signal_connect(endpoint->mpC3, "handle-acquire-write", G_CALLBACK(BluezCharacteristicAcquireWriteError), NULL); + g_signal_connect(endpoint->mpC3, "handle-acquire-notify", G_CALLBACK(BluezCharacteristicAcquireNotify), apClosure); + g_signal_connect(endpoint->mpC3, "handle-start-notify", G_CALLBACK(BluezCharacteristicStartNotify), apClosure); + g_signal_connect(endpoint->mpC3, "handle-stop-notify", G_CALLBACK(BluezCharacteristicStopNotify), apClosure); + g_signal_connect(endpoint->mpC3, "handle-confirm", G_CALLBACK(BluezCharacteristicConfirm), apClosure); + // update the characteristic value + UpdateAdditionalDataCharacteristic(endpoint->mpC3); + ChipLogDetail(DeviceLayer, "CHIP BTP C1 %s", bluez_gatt_characteristic1_get_service(endpoint->mpC1)); ChipLogDetail(DeviceLayer, "CHIP BTP C2 %s", bluez_gatt_characteristic1_get_service(endpoint->mpC2)); + ChipLogDetail(DeviceLayer, "CHIP BTP C3 %s", bluez_gatt_characteristic1_get_service(endpoint->mpC3)); exit: return; diff --git a/src/platform/Linux/CHIPBluezHelper.h b/src/platform/Linux/CHIPBluezHelper.h index 03ab1b2d825e6e..fcfc7989b79c72 100644 --- a/src/platform/Linux/CHIPBluezHelper.h +++ b/src/platform/Linux/CHIPBluezHelper.h @@ -75,6 +75,7 @@ namespace Internal { #define CHIP_PLAT_BLE_UUID_C1_STRING "18ee2ef5-263d-4559-959f-4f9c429f9d11" #define CHIP_PLAT_BLE_UUID_C2_STRING "18ee2ef5-263d-4559-959f-4f9c429f9d12" +#define CHIP_PLAT_BLE_UUID_C3_STRING "18ee2ef5-263d-4559-959f-4f9c429f9d13" #define CHIP_BLE_BASE_SERVICE_UUID_STRING "-0000-1000-8000-00805f9b34fb" #define CHIP_BLE_SERVICE_PREFIX_LENGTH 8 @@ -161,6 +162,8 @@ struct BluezEndpoint BluezGattService1 * mpService; BluezGattCharacteristic1 * mpC1; BluezGattCharacteristic1 * mpC2; + // additional data characteristics + BluezGattCharacteristic1 * mpC3; // map device path to the connection GHashTable * mpConnMap; @@ -185,6 +188,9 @@ struct BluezConnection BluezGattService1 * mpService; BluezGattCharacteristic1 * mpC1; BluezGattCharacteristic1 * mpC2; + // additional data characteristics + BluezGattCharacteristic1 * mpC3; + bool mIsNotify; uint16_t mMtu; struct IOChannel mC1Channel; diff --git a/src/setup_payload/AdditionalDataPayload.h b/src/setup_payload/AdditionalDataPayload.h new file mode 100644 index 00000000000000..10e1e3e2f78494 --- /dev/null +++ b/src/setup_payload/AdditionalDataPayload.h @@ -0,0 +1,42 @@ +/* + * + * Copyright (c) 2020 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * This file describes a Additional Data Payload class to hold + * data enumerated from a byte stream + */ + +#ifndef ADDITIONAL_DATA_PAYLOAD_H +#define ADDITIONAL_DATA_PAYLOAD_H + +#include + +namespace chip { + +const uint8_t kRotatingDeviceIdTag = 0x01; +const uint32_t kTag_AdditionalDataExensionDescriptor = 0x00; + +class AdditionalDataPayload +{ +public: + std::vector rotatingDeviceId; +}; + +} // namespace chip + +#endif // ADDITIONAL_DATA_PAYLOAD_H diff --git a/src/setup_payload/AdditionalDataPayloadParser.cpp b/src/setup_payload/AdditionalDataPayloadParser.cpp new file mode 100644 index 00000000000000..e917217b5bba64 --- /dev/null +++ b/src/setup_payload/AdditionalDataPayloadParser.cpp @@ -0,0 +1,289 @@ +/** + * + * Copyright (c) 2020 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * This file describes a AdditionalData Payload parser based on the + * CHIP specification. + */ + +#include "AdditionalDataPayloadParser.h" +#include "Base41.h" + +#include +#include +#include +#include +#include +#include + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace chip; +using namespace std; +using namespace chip::TLV; +using namespace chip::TLV::Utilities; + +static CHIP_ERROR octetStringDecode(string octetString, vector & result) { + result.clear(); + size_t len = octetString.length(); + + for(size_t i = 0; i < len; i += 2) { + auto str = octetString.substr(i, 2); + uint8_t x = (uint8_t)stoi(str, 0, 16); + result.push_back(x); + } + return CHIP_NO_ERROR; +} + +static CHIP_ERROR openTLVContainer(TLVReader & reader, TLVType type, uint64_t tag, TLVReader & containerReader) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + VerifyOrExit(reader.GetType() == type, err = CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrExit(reader.GetTag() == tag, err = CHIP_ERROR_INVALID_ARGUMENT); + VerifyOrExit(reader.GetLength() == 0, err = CHIP_ERROR_INVALID_ARGUMENT); + + err = reader.OpenContainer(containerReader); + SuccessOrExit(err); + + VerifyOrExit(containerReader.GetContainerType() == type, err = CHIP_ERROR_INVALID_ARGUMENT); +exit: + return err; +} + +CHIP_ERROR AdditionalDataPayloadParser::populatePayload(AdditionalDataPayload & outPayload) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + uint8_t * payload = nullptr; + size_t payloadLength = 0; + + // Decoding input + err = DecodeInput(&payload, payloadLength); + + // Generate Dummy payload + //err = GenerateSamplePayload(&payload, payloadLength); + // Dump the payload TLV structure + // DebugPrettyPrint(payload, payloadLength); + + //std::cout <<"Dummy:" << payloadLength << ":"; + for(uint8_t i=0; i buf; + // TLV parsing + size_t index = 0; + size_t bitsLeftToRead; + size_t tlvBytesLength; + chip::Platform::ScopedMemoryBuffer tlvArray; + + VerifyOrExit(mPayload.length() != 0, err = CHIP_ERROR_INVALID_ARGUMENT); + + // convert the octet string to buf + err = octetStringDecode(mPayload, buf); + SuccessOrExit(err); + + // convert the buff to TLV buffer + bitsLeftToRead = (buf.size() * 8) - index; + tlvBytesLength = (bitsLeftToRead + 7) / 8; // ceil(bitsLeftToRead/8) + SuccessOrExit(tlvBytesLength == 0); + tlvArray.Alloc(tlvBytesLength); + VerifyOrExit(tlvArray, err = CHIP_ERROR_NO_MEMORY); + + *output = new uint8_t[tlvBytesLength]; + for (size_t i = 0; i < tlvBytesLength; i++) + { + uint64_t dest = buf[i]; + (*output)[i] = static_cast(dest); + tlvArray[i] = static_cast(dest); + } + + // returning data + //*output = tlvArray.Get(); + tlvDataLengthInBytes = tlvBytesLength; + +exit: + return err; +} + +CHIP_ERROR AdditionalDataPayloadParser::parseTLVFields2(chip::AdditionalDataPayload & outPayload, uint8_t * tlvDataStart, size_t tlvDataLengthInBytes) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + chip::TLV::TLVReader reader; + chip::TLV::TLVReader innerReader; + // Outter Reader + for(size_t i=0; i< tlvDataLengthInBytes; i++) + { + } + reader.Init(tlvDataStart, (uint32_t)tlvDataLengthInBytes); + reader.ImplicitProfileId = chip::Protocols::kProtocol_ServiceProvisioning; + err = reader.Next(); + SuccessOrExit(err); + + // Open the container + err = reader.OpenContainer(innerReader); + SuccessOrExit(err); + + err = innerReader.Next(); + SuccessOrExit(err); + + // Get the value of the rotating device id + char rotatingDeviceId[256]; + err = innerReader.GetString(rotatingDeviceId, sizeof(rotatingDeviceId)+1); + ChipLogProgress(AdditionalDataPayload, "AdditonalData - Parsing: parseTLVFields, rotatingDeviceId:%s", rotatingDeviceId); +exit: + return err; +} + +CHIP_ERROR AdditionalDataPayloadParser::parseTLVFields(chip::AdditionalDataPayload & outPayload, uint8_t * tlvDataStart, size_t tlvDataLengthInBytes) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + if (!CanCastTo(tlvDataLengthInBytes)) + { + return CHIP_ERROR_INVALID_ARGUMENT; + } + + TLVReader rootReader; + rootReader.Init(tlvDataStart, static_cast(tlvDataLengthInBytes)); + rootReader.ImplicitProfileId = chip::Protocols::kProtocol_ServiceProvisioning; + err = rootReader.Next(); + SuccessOrExit(err); + + if (rootReader.GetType() == kTLVType_Structure) + { + TLVReader innerStructureReader; + err = openTLVContainer(rootReader, kTLVType_Structure, + ProfileTag(rootReader.ImplicitProfileId, kTag_AdditionalDataExensionDescriptor), + innerStructureReader); + SuccessOrExit(err); + err = innerStructureReader.Next(); + SuccessOrExit(err); + //err = retrieveOptionalInfos(outPayload, innerStructureReader); + } + else + { + return CHIP_ERROR_INVALID_ARGUMENT; + } + + if (err == CHIP_END_OF_TLV) + { + err = CHIP_NO_ERROR; + } +exit: + return err; +} + +static void TLVPrettyPrinter(const char * aFormat, ...) +{ + va_list args; + + va_start(args, aFormat); + + vprintf(aFormat, args); + + va_end(args); +} + +CHIP_ERROR AdditionalDataPayloadParser::DebugPrettyPrint(uint8_t * input, size_t & tlvDataLengthInBytes) +{ + chip::System::PacketBufferHandle bufferHandle = chip::System::PacketBuffer::New(); + chip::System::PacketBuffer * buffer = bufferHandle.Get_ForNow(); + + buffer->SetStart(input); + buffer->SetDataLength((uint16_t)tlvDataLengthInBytes); + CHIP_ERROR err = CHIP_NO_ERROR; + chip::TLV::TLVReader reader; + reader.Init(buffer); + err = reader.Next(); + ChipLogProgress(DataManagement, "DebugPrettyPrint Start:"); + chip::TLV::Debug::Dump(reader, TLVPrettyPrinter); + ChipLogProgress(DataManagement, "DebugPrettyPrint End"); + + if (CHIP_NO_ERROR != err) + { + ChipLogProgress(DataManagement, "DebugPrettyPrint fails with err %d", err); + } + + return err; +} + +CHIP_ERROR AdditionalDataPayloadParser::GenerateSamplePayload(uint8_t ** output, size_t & tlvDataLengthInBytes) +{ + CHIP_ERROR err = CHIP_NO_ERROR; + TLVWriter rootWriter; + chip::System::PacketBufferHandle bufferHandle = chip::System::PacketBuffer::New(); + chip::System::PacketBuffer * buffer = bufferHandle.Get_ForNow(); + + char testRotatingDeviceId[] = "1122334455667788"; + rootWriter.Init(buffer); + rootWriter.ImplicitProfileId = chip::Protocols::kProtocol_ServiceProvisioning; + + TLVWriter innerStructureWriter; + err = rootWriter.OpenContainer(ProfileTag(rootWriter.ImplicitProfileId, kTag_AdditionalDataExensionDescriptor), + kTLVType_Structure, + innerStructureWriter); + + SuccessOrExit(err); + err = innerStructureWriter.PutString(ProfileTag(rootWriter.ImplicitProfileId, kRotatingDeviceIdTag), + testRotatingDeviceId); + SuccessOrExit(err); + + err = rootWriter.CloseContainer(innerStructureWriter); + SuccessOrExit(err); + + err = rootWriter.Finalize(); + SuccessOrExit(err); + + *output = buffer->Start(); + tlvDataLengthInBytes = rootWriter.GetLengthWritten(); + //std::cout <<"Dummy:" << tlvDataLengthInBytes << ":"; + for(size_t i=0; iStart()[i]; + } + //std::cout << std::endl; +exit: + return err; +} diff --git a/src/setup_payload/AdditionalDataPayloadParser.h b/src/setup_payload/AdditionalDataPayloadParser.h new file mode 100644 index 00000000000000..f41406eb2e75cb --- /dev/null +++ b/src/setup_payload/AdditionalDataPayloadParser.h @@ -0,0 +1,56 @@ +/** + * + * Copyright (c) 2020 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file + * This file describes a AdditionalData Payload parser based on the + * CHIP specification. + */ + +#include "AdditionalDataPayload.h" + +#include +#include + +#include +#include + +namespace chip { + +/** + * @class AdditionalDataPayloadParser + * A class that can be used to convert a base41 encoded payload to a AdditionalDataPayload object + * */ +class AdditionalDataPayloadParser +{ +private: + std::string mPayload; + +public: + AdditionalDataPayloadParser(std::string payload) : mPayload(std::move(payload)) {} + CHIP_ERROR populatePayload(AdditionalDataPayload & outPayload); + +private: + CHIP_ERROR DecodeInput(uint8_t ** output, size_t & tlvDataLengthInBytes); + CHIP_ERROR parseTLVFields(chip::AdditionalDataPayload & outPayload, uint8_t * tlvDataStart, size_t tlvDataLengthInBytes); + CHIP_ERROR parseTLVFields2(chip::AdditionalDataPayload & outPayload, uint8_t * tlvDataStart, size_t tlvDataLengthInBytes); + CHIP_ERROR DebugPrettyPrint(uint8_t * input, size_t & tlvDataLengthInBytes); + CHIP_ERROR GenerateSamplePayload(uint8_t ** output, size_t & tlvDataLengthInBytes); + +}; + +} // namespace chip diff --git a/src/setup_payload/BUILD.gn b/src/setup_payload/BUILD.gn index 63c9bb1d828df6..40cd63eb2a27c6 100644 --- a/src/setup_payload/BUILD.gn +++ b/src/setup_payload/BUILD.gn @@ -32,6 +32,9 @@ static_library("setup_payload") { "QRCodeSetupPayloadGenerator.h", "QRCodeSetupPayloadParser.cpp", "QRCodeSetupPayloadParser.h", + "AdditionalDataPayload.h", + "AdditionalDataPayloadParser.h", + "AdditionalDataPayloadParser.cpp", "SetupPayload.cpp", "SetupPayload.h", "SetupPayloadHelper.cpp",