blob: e4349b31bd1f09325e1f7651413bcaaf84b219fa [file] [log] [blame]
/*
*
* 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 <string>
#include <controller/CHIPDeviceController.h>
#include <controller/python/chip/native/PyChipError.h>
#include <json/json.h>
#include <lib/core/CHIPError.h>
#include <lib/core/TLV.h>
#include <lib/dnssd/Resolver.h>
#include <setup_payload/ManualSetupPayloadGenerator.h>
#include <setup_payload/SetupPayload.h>
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<Dnssd::DiscoveryFilterType>(filterType));
switch (static_cast<Dnssd::DiscoveryFilterType>(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<uint64_t>(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);
}
}