/* * * Copyright (c) 2022 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. */ /** * @file * Implementation of the native methods expected by the Python * version of Chip Device Manager. * */ #include #include #include #include #include #include #include #include #include using namespace chip; typedef void (*IterateDiscoveredCommissionableNodesFunct)(const char * deviceInfoJson, size_t deviceInfoLen); extern "C" { bool pychip_DeviceController_HasDiscoveredCommissionableNode(Controller::DeviceCommissioner * devCtrl) { for (int i = 0; i < devCtrl->GetMaxCommissionableNodesSupported(); ++i) { const Dnssd::CommissionNodeData * dnsSdInfo = devCtrl->GetDiscoveredDevice(i); if (dnsSdInfo == nullptr) { continue; } return true; } return false; } PyChipError pychip_DeviceController_DiscoverCommissionableNodes(Controller::DeviceCommissioner * devCtrl, const uint8_t filterType, const char * filterParam) { Dnssd::DiscoveryFilter filter(static_cast(filterType)); switch (static_cast(filterType)) { case Dnssd::DiscoveryFilterType::kNone: break; case Dnssd::DiscoveryFilterType::kShortDiscriminator: case Dnssd::DiscoveryFilterType::kLongDiscriminator: case Dnssd::DiscoveryFilterType::kCompressedFabricId: case Dnssd::DiscoveryFilterType::kVendorId: case Dnssd::DiscoveryFilterType::kDeviceType: { // For any numerical filter, convert the string to a filter value errno = 0; unsigned long long int numericalArg = strtoull(filterParam, nullptr, 0); if ((numericalArg == ULLONG_MAX) && (errno == ERANGE)) { return ToPyChipError(CHIP_ERROR_INVALID_ARGUMENT); } filter.code = static_cast(numericalArg); break; } case Dnssd::DiscoveryFilterType::kCommissioningMode: break; case Dnssd::DiscoveryFilterType::kCommissioner: filter.code = 1; break; case Dnssd::DiscoveryFilterType::kInstanceName: filter.code = 0; filter.instanceName = filterParam; break; default: return ToPyChipError(CHIP_ERROR_INVALID_ARGUMENT); } return ToPyChipError(devCtrl->DiscoverCommissionableNodes(filter)); } PyChipError pychip_DeviceController_StopCommissionableDiscovery(Controller::DeviceCommissioner * devCtrl) { return ToPyChipError(devCtrl->StopCommissionableDiscovery()); } void pychip_DeviceController_IterateDiscoveredCommissionableNodes(Controller::DeviceCommissioner * devCtrl, IterateDiscoveredCommissionableNodesFunct cb) { VerifyOrReturn(cb != nullptr); for (int i = 0; i < devCtrl->GetMaxCommissionableNodesSupported(); ++i) { const Dnssd::CommissionNodeData * dnsSdInfo = devCtrl->GetDiscoveredDevice(i); if (dnsSdInfo == nullptr) { continue; } Json::Value jsonVal; char rotatingId[Dnssd::kMaxRotatingIdLen * 2 + 1] = ""; Encoding::BytesToUppercaseHexString(dnsSdInfo->rotatingId, dnsSdInfo->rotatingIdLen, rotatingId, sizeof(rotatingId)); ChipLogProgress(Discovery, "Commissionable Node %d", i); jsonVal["instanceName"] = dnsSdInfo->instanceName; jsonVal["hostName"] = dnsSdInfo->hostName; jsonVal["port"] = dnsSdInfo->port; jsonVal["longDiscriminator"] = dnsSdInfo->longDiscriminator; jsonVal["vendorId"] = dnsSdInfo->vendorId; jsonVal["productId"] = dnsSdInfo->productId; jsonVal["commissioningMode"] = dnsSdInfo->commissioningMode; jsonVal["deviceType"] = dnsSdInfo->deviceType; jsonVal["deviceName"] = dnsSdInfo->deviceName; jsonVal["pairingInstruction"] = dnsSdInfo->pairingInstruction; jsonVal["pairingHint"] = dnsSdInfo->pairingHint; auto idleInterval = dnsSdInfo->GetMrpRetryIntervalIdle(); if (idleInterval.has_value()) { jsonVal["mrpRetryIntervalIdle"] = idleInterval->count(); } auto activeInterval = dnsSdInfo->GetMrpRetryIntervalActive(); if (activeInterval.has_value()) { jsonVal["mrpRetryIntervalActive"] = activeInterval->count(); } auto activeThreshold = dnsSdInfo->GetMrpRetryActiveThreshold(); if (activeThreshold.has_value()) { jsonVal["mrpRetryActiveThreshold"] = activeThreshold->count(); } jsonVal["supportsTcpClient"] = dnsSdInfo->supportsTcpClient; jsonVal["supportsTcpServer"] = dnsSdInfo->supportsTcpServer; { Json::Value addresses; for (unsigned j = 0; j < dnsSdInfo->numIPs; ++j) { char buf[Inet::IPAddress::kMaxStringLength]; dnsSdInfo->ipAddress[j].ToString(buf); addresses[j] = buf; } jsonVal["addresses"] = addresses; } if (dnsSdInfo->isICDOperatingAsLIT.has_value()) { jsonVal["isICDOperatingAsLIT"] = *(dnsSdInfo->isICDOperatingAsLIT); } if (dnsSdInfo->rotatingIdLen > 0) { jsonVal["rotatingId"] = rotatingId; } { auto str = jsonVal.toStyledString(); cb(str.c_str(), str.size()); } } } bool pychip_DeviceController_GetIPForDiscoveredDevice(Controller::DeviceCommissioner * devCtrl, int idx, char * addrStr, uint32_t len) { const Dnssd::CommissionNodeData * dnsSdInfo = devCtrl->GetDiscoveredDevice(idx); if (dnsSdInfo == nullptr) { return false; } // TODO(cecille): Select which one we actually want. if (dnsSdInfo->ipAddress[0].ToString(addrStr, len) == addrStr) { return true; } return false; } PyChipError pychip_CreateManualCode(uint16_t longDiscriminator, uint32_t passcode, char * manualCodeBuffer, size_t inBufSize, size_t * outBufSize) { SetupPayload payload; SetupDiscriminator discriminator; discriminator.SetLongValue(longDiscriminator); payload.discriminator = discriminator; payload.setUpPINCode = passcode; std::string setupManualCode; *outBufSize = 0; CHIP_ERROR err = ManualSetupPayloadGenerator(payload).payloadDecimalStringRepresentation(setupManualCode); if (err == CHIP_NO_ERROR) { MutableCharSpan span(manualCodeBuffer, inBufSize); // Plus 1 so we copy the null terminator CopyCharSpanToMutableCharSpan(CharSpan(setupManualCode.c_str(), setupManualCode.length() + 1), span); *outBufSize = span.size(); if (*outBufSize == 0) { err = CHIP_ERROR_NO_MEMORY; } } return ToPyChipError(err); } }