|
|
|
@@ -1,6 +1,7 @@
|
|
|
|
|
#include "gateway_matter.hpp"
|
|
|
|
|
|
|
|
|
|
#include <algorithm>
|
|
|
|
|
#include <array>
|
|
|
|
|
#include <cmath>
|
|
|
|
|
#include <cstdio>
|
|
|
|
|
#include <cstring>
|
|
|
|
@@ -19,9 +20,14 @@
|
|
|
|
|
#include "esp_heap_caps.h"
|
|
|
|
|
#include "esp_log.h"
|
|
|
|
|
#include "freertos/task.h"
|
|
|
|
|
#include "mbedtls/base64.h"
|
|
|
|
|
#include "mbedtls/md.h"
|
|
|
|
|
#include "mbedtls/sha256.h"
|
|
|
|
|
#include "mbedtls/x509_crt.h"
|
|
|
|
|
#include "nvs.h"
|
|
|
|
|
#include "nvs_flash.h"
|
|
|
|
|
#include "platform/CHIPDeviceLayer.h"
|
|
|
|
|
#include "sdkconfig.h"
|
|
|
|
|
|
|
|
|
|
namespace gateway {
|
|
|
|
|
namespace {
|
|
|
|
@@ -29,6 +35,19 @@ namespace {
|
|
|
|
|
constexpr char kTag[] = "gateway_matter";
|
|
|
|
|
constexpr char kBindingNamespace[] = "dali_matter";
|
|
|
|
|
constexpr char kConfigurationNamespace[] = "matter_cfg";
|
|
|
|
|
constexpr char kFactoryNamespace[] = "chip-factory";
|
|
|
|
|
constexpr char kFactoryProfile[] = "matter-test-paa";
|
|
|
|
|
constexpr char kFactoryInstallConfirmation[] =
|
|
|
|
|
"install-matter-test-factory-data";
|
|
|
|
|
constexpr char kFactoryPaiSha256[] =
|
|
|
|
|
"27cf4e8cbf73f8fac2b9ab78b7d0fe59a10100b8e9a2df136a85b41a5d271bae";
|
|
|
|
|
constexpr char kFactoryCertificationDeclarationSha256[] =
|
|
|
|
|
"867e7710cf20307e4b4ae08a8a1b98fac93a7f716071dd8ae10dc1575366a1bf";
|
|
|
|
|
constexpr uint32_t kFactoryVendorId = 0xFFF2;
|
|
|
|
|
constexpr uint32_t kFactoryProductId = 0x8001;
|
|
|
|
|
constexpr uint32_t kFactoryDiscriminator = 3840;
|
|
|
|
|
constexpr uint32_t kFactoryIterationCount = 10000;
|
|
|
|
|
constexpr uint32_t kFactorySetupPasscode = 20202021;
|
|
|
|
|
constexpr uint8_t kBindingVersion = 2;
|
|
|
|
|
constexpr uint8_t kConfigurationVersion = 1;
|
|
|
|
|
constexpr uint16_t kAllDaliDeviceTypesMask = 0x01FF;
|
|
|
|
@@ -73,6 +92,108 @@ struct PersistedChannelConfiguration {
|
|
|
|
|
uint8_t group_color_methods[16];
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
bool JsonStringValue(cJSON* root, const char* key, size_t min_length,
|
|
|
|
|
size_t max_length, std::string* value) {
|
|
|
|
|
const cJSON* item = cJSON_GetObjectItemCaseSensitive(root, key);
|
|
|
|
|
if (!cJSON_IsString(item) || item->valuestring == nullptr) return false;
|
|
|
|
|
const size_t length = std::strlen(item->valuestring);
|
|
|
|
|
if (length < min_length || length > max_length) return false;
|
|
|
|
|
*value = item->valuestring;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool JsonUint32Value(cJSON* root, const char* key, uint32_t minimum,
|
|
|
|
|
uint32_t maximum, uint32_t* value) {
|
|
|
|
|
const cJSON* item = cJSON_GetObjectItemCaseSensitive(root, key);
|
|
|
|
|
if (!cJSON_IsNumber(item) || !std::isfinite(item->valuedouble) ||
|
|
|
|
|
std::floor(item->valuedouble) != item->valuedouble ||
|
|
|
|
|
item->valuedouble < minimum || item->valuedouble > maximum) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
*value = static_cast<uint32_t>(item->valuedouble);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool DecodeBase64Value(cJSON* root, const char* key, size_t minimum,
|
|
|
|
|
size_t maximum, std::vector<uint8_t>* value,
|
|
|
|
|
std::string* encoded = nullptr) {
|
|
|
|
|
std::string input;
|
|
|
|
|
if (!JsonStringValue(root, key, 1, ((maximum + 2) / 3) * 4 + 4,
|
|
|
|
|
&input)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
std::vector<uint8_t> decoded(maximum);
|
|
|
|
|
size_t decoded_length = 0;
|
|
|
|
|
const int result = mbedtls_base64_decode(
|
|
|
|
|
decoded.data(), decoded.size(), &decoded_length,
|
|
|
|
|
reinterpret_cast<const unsigned char*>(input.data()), input.size());
|
|
|
|
|
if (result != 0 || decoded_length < minimum || decoded_length > maximum) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
decoded.resize(decoded_length);
|
|
|
|
|
*value = std::move(decoded);
|
|
|
|
|
if (encoded != nullptr) *encoded = std::move(input);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string Sha256Hex(const std::vector<uint8_t>& data) {
|
|
|
|
|
std::array<unsigned char, 32> digest{};
|
|
|
|
|
if (mbedtls_sha256(data.data(), data.size(), digest.data(), 0) != 0) {
|
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
constexpr char kHex[] = "0123456789abcdef";
|
|
|
|
|
std::string result(64, '0');
|
|
|
|
|
for (size_t index = 0; index < digest.size(); ++index) {
|
|
|
|
|
result[index * 2] = kHex[digest[index] >> 4];
|
|
|
|
|
result[index * 2 + 1] = kHex[digest[index] & 0x0F];
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool VerifyDacSignature(const std::vector<uint8_t>& dac_der,
|
|
|
|
|
const std::vector<uint8_t>& pai_der) {
|
|
|
|
|
mbedtls_x509_crt dac;
|
|
|
|
|
mbedtls_x509_crt pai;
|
|
|
|
|
mbedtls_x509_crt_init(&dac);
|
|
|
|
|
mbedtls_x509_crt_init(&pai);
|
|
|
|
|
bool verified =
|
|
|
|
|
mbedtls_x509_crt_parse_der(&dac, dac_der.data(), dac_der.size()) == 0 &&
|
|
|
|
|
mbedtls_x509_crt_parse_der(&pai, pai_der.data(), pai_der.size()) == 0 &&
|
|
|
|
|
dac.issuer_raw.len == pai.subject_raw.len &&
|
|
|
|
|
std::memcmp(dac.issuer_raw.p, pai.subject_raw.p, dac.issuer_raw.len) == 0;
|
|
|
|
|
if (verified) {
|
|
|
|
|
const auto md_type = dac.MBEDTLS_PRIVATE(sig_md);
|
|
|
|
|
const mbedtls_md_info_t* md_info = mbedtls_md_info_from_type(md_type);
|
|
|
|
|
std::array<unsigned char, MBEDTLS_MD_MAX_SIZE> digest{};
|
|
|
|
|
const size_t digest_length =
|
|
|
|
|
md_info == nullptr ? 0 : mbedtls_md_get_size(md_info);
|
|
|
|
|
verified = md_info != nullptr && digest_length > 0 &&
|
|
|
|
|
mbedtls_md(md_info, dac.tbs.p, dac.tbs.len, digest.data()) == 0 &&
|
|
|
|
|
mbedtls_pk_verify(&pai.pk, md_type, digest.data(),
|
|
|
|
|
digest_length, dac.MBEDTLS_PRIVATE(sig).p,
|
|
|
|
|
dac.MBEDTLS_PRIVATE(sig).len) == 0;
|
|
|
|
|
}
|
|
|
|
|
mbedtls_x509_crt_free(&dac);
|
|
|
|
|
mbedtls_x509_crt_free(&pai);
|
|
|
|
|
return verified;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool HasNvsBlob(nvs_handle_t handle, const char* key) {
|
|
|
|
|
size_t length = 0;
|
|
|
|
|
return nvs_get_blob(handle, key, nullptr, &length) == ESP_OK && length > 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string ReadNvsString(nvs_handle_t handle, const char* key) {
|
|
|
|
|
size_t length = 0;
|
|
|
|
|
if (nvs_get_str(handle, key, nullptr, &length) != ESP_OK || length <= 1) {
|
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
std::string result(length, '\0');
|
|
|
|
|
if (nvs_get_str(handle, key, result.data(), &length) != ESP_OK) return {};
|
|
|
|
|
result.resize(length > 0 ? length - 1 : 0);
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string BindingKey(uint16_t endpoint_id) {
|
|
|
|
|
char key[16] = {};
|
|
|
|
|
std::snprintf(key, sizeof(key), "b%04x", endpoint_id);
|
|
|
|
@@ -854,6 +975,133 @@ esp_err_t GatewayMatterBridge::resetConfiguration(uint8_t gateway_id) {
|
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
esp_err_t GatewayMatterBridge::installFactoryData(std::string_view payload) {
|
|
|
|
|
cJSON* root = cJSON_ParseWithLength(payload.data(), payload.size());
|
|
|
|
|
if (root == nullptr || !cJSON_IsObject(root)) {
|
|
|
|
|
cJSON_Delete(root);
|
|
|
|
|
return ESP_ERR_INVALID_ARG;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint32_t schema_version = 0;
|
|
|
|
|
uint32_t discriminator = 0;
|
|
|
|
|
uint32_t iteration_count = 0;
|
|
|
|
|
uint32_t vendor_id = 0;
|
|
|
|
|
uint32_t product_id = 0;
|
|
|
|
|
uint32_t hardware_version = 0;
|
|
|
|
|
std::string profile;
|
|
|
|
|
std::string confirmation;
|
|
|
|
|
std::string serial_number;
|
|
|
|
|
std::string vendor_name;
|
|
|
|
|
std::string product_name;
|
|
|
|
|
std::string hardware_version_string;
|
|
|
|
|
std::string salt_base64;
|
|
|
|
|
std::string verifier_base64;
|
|
|
|
|
std::string requested_dac_sha256;
|
|
|
|
|
std::vector<uint8_t> salt;
|
|
|
|
|
std::vector<uint8_t> verifier;
|
|
|
|
|
std::vector<uint8_t> dac_certificate;
|
|
|
|
|
std::vector<uint8_t> dac_private_key;
|
|
|
|
|
std::vector<uint8_t> dac_public_key;
|
|
|
|
|
std::vector<uint8_t> pai_certificate;
|
|
|
|
|
std::vector<uint8_t> certification_declaration;
|
|
|
|
|
|
|
|
|
|
const bool valid =
|
|
|
|
|
JsonUint32Value(root, "schemaVersion", 1, 1, &schema_version) &&
|
|
|
|
|
JsonStringValue(root, "profile", 1, 32, &profile) &&
|
|
|
|
|
profile == kFactoryProfile &&
|
|
|
|
|
JsonStringValue(root, "confirm", 1, 64, &confirmation) &&
|
|
|
|
|
confirmation == kFactoryInstallConfirmation &&
|
|
|
|
|
JsonStringValue(root, "serialNumber", 1, 32, &serial_number) &&
|
|
|
|
|
JsonUint32Value(root, "discriminator", kFactoryDiscriminator,
|
|
|
|
|
kFactoryDiscriminator, &discriminator) &&
|
|
|
|
|
JsonUint32Value(root, "iterationCount", kFactoryIterationCount,
|
|
|
|
|
kFactoryIterationCount, &iteration_count) &&
|
|
|
|
|
JsonUint32Value(root, "vendorId", kFactoryVendorId, kFactoryVendorId,
|
|
|
|
|
&vendor_id) &&
|
|
|
|
|
JsonStringValue(root, "vendorName", 1, 32, &vendor_name) &&
|
|
|
|
|
JsonUint32Value(root, "productId", kFactoryProductId,
|
|
|
|
|
kFactoryProductId, &product_id) &&
|
|
|
|
|
JsonStringValue(root, "productName", 1, 32, &product_name) &&
|
|
|
|
|
JsonUint32Value(root, "hardwareVersion", 1, 65535,
|
|
|
|
|
&hardware_version) &&
|
|
|
|
|
JsonStringValue(root, "hardwareVersionString", 1, 64,
|
|
|
|
|
&hardware_version_string) &&
|
|
|
|
|
DecodeBase64Value(root, "salt", 32, 32, &salt, &salt_base64) &&
|
|
|
|
|
DecodeBase64Value(root, "verifier", 97, 97, &verifier,
|
|
|
|
|
&verifier_base64) &&
|
|
|
|
|
DecodeBase64Value(root, "dacCertificate", 128, 2048,
|
|
|
|
|
&dac_certificate) &&
|
|
|
|
|
DecodeBase64Value(root, "dacPrivateKey", 32, 32, &dac_private_key) &&
|
|
|
|
|
DecodeBase64Value(root, "dacPublicKey", 65, 65, &dac_public_key) &&
|
|
|
|
|
dac_public_key.front() == 0x04 &&
|
|
|
|
|
DecodeBase64Value(root, "paiCertificate", 128, 2048,
|
|
|
|
|
&pai_certificate) &&
|
|
|
|
|
DecodeBase64Value(root, "certificationDeclaration", 64, 2048,
|
|
|
|
|
&certification_declaration) &&
|
|
|
|
|
Sha256Hex(pai_certificate) == kFactoryPaiSha256 &&
|
|
|
|
|
Sha256Hex(certification_declaration) ==
|
|
|
|
|
kFactoryCertificationDeclarationSha256 &&
|
|
|
|
|
VerifyDacSignature(dac_certificate, pai_certificate) &&
|
|
|
|
|
JsonStringValue(root, "dacCertificateSha256", 64, 64,
|
|
|
|
|
&requested_dac_sha256) &&
|
|
|
|
|
requested_dac_sha256 == Sha256Hex(dac_certificate);
|
|
|
|
|
cJSON_Delete(root);
|
|
|
|
|
if (!valid) return ESP_ERR_INVALID_ARG;
|
|
|
|
|
|
|
|
|
|
nvs_handle_t handle = 0;
|
|
|
|
|
esp_err_t err = nvs_open_from_partition(
|
|
|
|
|
CONFIG_CHIP_FACTORY_NAMESPACE_PARTITION_LABEL, kFactoryNamespace,
|
|
|
|
|
NVS_READWRITE, &handle);
|
|
|
|
|
if (err != ESP_OK) return err;
|
|
|
|
|
|
|
|
|
|
err = nvs_set_u32(handle, "discriminator", discriminator);
|
|
|
|
|
if (err == ESP_OK) err = nvs_set_u32(handle, "iteration-count", iteration_count);
|
|
|
|
|
if (err == ESP_OK) err = nvs_set_str(handle, "salt", salt_base64.c_str());
|
|
|
|
|
if (err == ESP_OK) err = nvs_set_str(handle, "verifier", verifier_base64.c_str());
|
|
|
|
|
if (err == ESP_OK) err = nvs_set_u32(handle, "vendor-id", vendor_id);
|
|
|
|
|
if (err == ESP_OK) err = nvs_set_str(handle, "vendor-name", vendor_name.c_str());
|
|
|
|
|
if (err == ESP_OK) err = nvs_set_u32(handle, "product-id", product_id);
|
|
|
|
|
if (err == ESP_OK) err = nvs_set_str(handle, "product-name", product_name.c_str());
|
|
|
|
|
if (err == ESP_OK) err = nvs_set_u32(handle, "hardware-ver", hardware_version);
|
|
|
|
|
if (err == ESP_OK) {
|
|
|
|
|
err = nvs_set_str(handle, "hw-ver-str", hardware_version_string.c_str());
|
|
|
|
|
}
|
|
|
|
|
if (err == ESP_OK) err = nvs_set_str(handle, "serial-num", serial_number.c_str());
|
|
|
|
|
if (err == ESP_OK) err = nvs_set_str(handle, "dm-profile", profile.c_str());
|
|
|
|
|
if (err == ESP_OK) {
|
|
|
|
|
err = nvs_set_str(handle, "dm-dac-sha", requested_dac_sha256.c_str());
|
|
|
|
|
}
|
|
|
|
|
if (err == ESP_OK) {
|
|
|
|
|
err = nvs_set_blob(handle, "dac-cert", dac_certificate.data(),
|
|
|
|
|
dac_certificate.size());
|
|
|
|
|
}
|
|
|
|
|
if (err == ESP_OK) {
|
|
|
|
|
err = nvs_set_blob(handle, "dac-key", dac_private_key.data(),
|
|
|
|
|
dac_private_key.size());
|
|
|
|
|
}
|
|
|
|
|
if (err == ESP_OK) {
|
|
|
|
|
err = nvs_set_blob(handle, "dac-pub-key", dac_public_key.data(),
|
|
|
|
|
dac_public_key.size());
|
|
|
|
|
}
|
|
|
|
|
if (err == ESP_OK) {
|
|
|
|
|
err = nvs_set_blob(handle, "pai-cert", pai_certificate.data(),
|
|
|
|
|
pai_certificate.size());
|
|
|
|
|
}
|
|
|
|
|
if (err == ESP_OK) {
|
|
|
|
|
err = nvs_set_blob(handle, "cert-dclrn", certification_declaration.data(),
|
|
|
|
|
certification_declaration.size());
|
|
|
|
|
}
|
|
|
|
|
if (err == ESP_OK) err = nvs_commit(handle);
|
|
|
|
|
nvs_close(handle);
|
|
|
|
|
if (err == ESP_OK) {
|
|
|
|
|
factory_restart_required_.store(true, std::memory_order_release);
|
|
|
|
|
ESP_LOGW(kTag,
|
|
|
|
|
"installed development Matter factory data serial=%s; restart required",
|
|
|
|
|
serial_number.c_str());
|
|
|
|
|
}
|
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string GatewayMatterBridge::statusJson(std::optional<uint8_t> gateway_id) const {
|
|
|
|
|
bool commissioning_window_open =
|
|
|
|
|
commissioning_window_open_.load(std::memory_order_acquire);
|
|
|
|
@@ -899,6 +1147,43 @@ std::string GatewayMatterBridge::statusJson(std::optional<uint8_t> gateway_id) c
|
|
|
|
|
config_.wifi_provision_long_press_ms);
|
|
|
|
|
cJSON_AddStringToObject(matter, "storage", "plainNvs");
|
|
|
|
|
cJSON_AddStringToObject(matter, "networkPreference", "ethernet");
|
|
|
|
|
cJSON* factory_data = cJSON_CreateObject();
|
|
|
|
|
if (factory_data != nullptr) {
|
|
|
|
|
bool present = false;
|
|
|
|
|
std::string profile;
|
|
|
|
|
std::string serial_number;
|
|
|
|
|
std::string dac_sha256;
|
|
|
|
|
uint32_t vendor_id = 0;
|
|
|
|
|
uint32_t product_id = 0;
|
|
|
|
|
nvs_handle_t handle = 0;
|
|
|
|
|
if (nvs_open_from_partition(CONFIG_CHIP_FACTORY_NAMESPACE_PARTITION_LABEL,
|
|
|
|
|
kFactoryNamespace, NVS_READONLY,
|
|
|
|
|
&handle) == ESP_OK) {
|
|
|
|
|
profile = ReadNvsString(handle, "dm-profile");
|
|
|
|
|
serial_number = ReadNvsString(handle, "serial-num");
|
|
|
|
|
dac_sha256 = ReadNvsString(handle, "dm-dac-sha");
|
|
|
|
|
present = !serial_number.empty() && HasNvsBlob(handle, "dac-cert") &&
|
|
|
|
|
HasNvsBlob(handle, "dac-key") &&
|
|
|
|
|
HasNvsBlob(handle, "dac-pub-key") &&
|
|
|
|
|
HasNvsBlob(handle, "pai-cert") &&
|
|
|
|
|
HasNvsBlob(handle, "cert-dclrn") &&
|
|
|
|
|
nvs_get_u32(handle, "vendor-id", &vendor_id) == ESP_OK &&
|
|
|
|
|
nvs_get_u32(handle, "product-id", &product_id) == ESP_OK;
|
|
|
|
|
nvs_close(handle);
|
|
|
|
|
}
|
|
|
|
|
cJSON_AddBoolToObject(factory_data, "present", present);
|
|
|
|
|
cJSON_AddStringToObject(factory_data, "profile", profile.c_str());
|
|
|
|
|
cJSON_AddStringToObject(factory_data, "serialNumber",
|
|
|
|
|
serial_number.c_str());
|
|
|
|
|
cJSON_AddNumberToObject(factory_data, "vendorId", vendor_id);
|
|
|
|
|
cJSON_AddNumberToObject(factory_data, "productId", product_id);
|
|
|
|
|
cJSON_AddStringToObject(factory_data, "dacCertificateSha256",
|
|
|
|
|
dac_sha256.c_str());
|
|
|
|
|
cJSON_AddBoolToObject(
|
|
|
|
|
factory_data, "restartRequired",
|
|
|
|
|
factory_restart_required_.load(std::memory_order_acquire));
|
|
|
|
|
cJSON_AddItemToObject(matter, "factoryData", factory_data);
|
|
|
|
|
}
|
|
|
|
|
if (!last_apply_error_.empty()) {
|
|
|
|
|
cJSON_AddStringToObject(matter, "lastApplyError", last_apply_error_.c_str());
|
|
|
|
|
} else {
|
|
|
|
@@ -1061,8 +1346,8 @@ std::string GatewayMatterBridge::onboardingJson() const {
|
|
|
|
|
chip::MutableCharSpan manual_span(manual_buffer, sizeof(manual_buffer));
|
|
|
|
|
const auto flags = chip::RendezvousInformationFlags(
|
|
|
|
|
chip::RendezvousInformationFlag::kBLE);
|
|
|
|
|
const CHIP_ERROR qr_err = GetQRCode(qr_span, flags);
|
|
|
|
|
const CHIP_ERROR manual_err = GetManualPairingCode(manual_span, flags);
|
|
|
|
|
CHIP_ERROR qr_err = CHIP_ERROR_INCORRECT_STATE;
|
|
|
|
|
CHIP_ERROR manual_err = CHIP_ERROR_INCORRECT_STATE;
|
|
|
|
|
uint16_t vendor_id = 0;
|
|
|
|
|
uint16_t product_id = 0;
|
|
|
|
|
auto* provider = chip::DeviceLayer::GetDeviceInstanceInfoProvider();
|
|
|
|
@@ -1074,6 +1359,29 @@ std::string GatewayMatterBridge::onboardingJson() const {
|
|
|
|
|
provider->GetVendorId(vendor_id);
|
|
|
|
|
provider->GetProductId(product_id);
|
|
|
|
|
}
|
|
|
|
|
std::string factory_profile;
|
|
|
|
|
nvs_handle_t factory_handle = 0;
|
|
|
|
|
if (nvs_open_from_partition(CONFIG_CHIP_FACTORY_NAMESPACE_PARTITION_LABEL,
|
|
|
|
|
kFactoryNamespace, NVS_READONLY,
|
|
|
|
|
&factory_handle) == ESP_OK) {
|
|
|
|
|
factory_profile = ReadNvsString(factory_handle, "dm-profile");
|
|
|
|
|
nvs_close(factory_handle);
|
|
|
|
|
}
|
|
|
|
|
if (factory_profile == kFactoryProfile && vendor_id == kFactoryVendorId &&
|
|
|
|
|
product_id == kFactoryProductId) {
|
|
|
|
|
chip::PayloadContents payload;
|
|
|
|
|
payload.version = 0;
|
|
|
|
|
payload.rendezvousInformation.SetValue(flags);
|
|
|
|
|
payload.setUpPINCode = kFactorySetupPasscode;
|
|
|
|
|
payload.discriminator.SetLongValue(kFactoryDiscriminator);
|
|
|
|
|
payload.vendorID = vendor_id;
|
|
|
|
|
payload.productID = product_id;
|
|
|
|
|
qr_err = GetQRCode(qr_span, payload);
|
|
|
|
|
manual_err = GetManualPairingCode(manual_span, payload);
|
|
|
|
|
} else {
|
|
|
|
|
qr_err = GetQRCode(qr_span, flags);
|
|
|
|
|
manual_err = GetManualPairingCode(manual_span, flags);
|
|
|
|
|
}
|
|
|
|
|
cJSON* root = cJSON_CreateObject();
|
|
|
|
|
cJSON* onboarding = cJSON_CreateObject();
|
|
|
|
|
cJSON_AddItemToObject(root, "matterOnboarding", onboarding);
|
|
|
|
|