blob: dcc5f3ee18206ca62eee795827a57ff0a6fd74d1 [file] [log] [blame]
/*
*
* Copyright (c) 2020-2021 Project CHIP Authors
* Copyright (c) 2019-2020 Google LLC.
* Copyright (c) 2013-2018 Nest Labs, Inc.
* 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 <errno.h>
#include <fcntl.h>
#include <memory>
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <unistd.h>
#include <system/SystemError.h>
#include <system/SystemLayer.h>
#include <inttypes.h>
#include <net/if.h>
#include "ChipDeviceController-ScriptDeviceAddressUpdateDelegate.h"
#include "ChipDeviceController-ScriptDevicePairingDelegate.h"
#include "ChipDeviceController-StorageDelegate.h"
#include "chip/interaction_model/Delegate.h"
#include <app/CommandSender.h>
#include <app/InteractionModelEngine.h>
#include <controller/CHIPDevice.h>
#include <controller/CHIPDeviceController.h>
#include <controller/ExampleOperationalCredentialsIssuer.h>
#include <inet/IPAddress.h>
#include <mdns/Resolver.h>
#include <setup_payload/QRCodeSetupPayloadParser.h>
#include <support/CHIPMem.h>
#include <support/CodeUtils.h>
#include <support/DLLUtil.h>
#include <support/logging/CHIPLogging.h>
using namespace chip;
using namespace chip::Ble;
using namespace chip::Controller;
extern "C" {
typedef void (*ConstructBytesArrayFunct)(const uint8_t * dataBuf, uint32_t dataLen);
typedef void (*LogMessageFunct)(uint64_t time, uint64_t timeUS, const char * moduleName, uint8_t category, const char * msg);
}
namespace {
chip::Controller::PythonPersistentStorageDelegate sStorageDelegate;
chip::Controller::ScriptDevicePairingDelegate sPairingDelegate;
chip::Controller::ScriptDeviceAddressUpdateDelegate sDeviceAddressUpdateDelegate;
chip::Controller::ExampleOperationalCredentialsIssuer sOperationalCredentialsIssuer;
} // namespace
// NOTE: Remote device ID is in sync with the echo server device id
// At some point, we may want to add an option to connect to a device without
// knowing its id, because the ID can be learned on the first response that is received.
chip::NodeId kDefaultLocalDeviceId = chip::kTestControllerNodeId;
chip::NodeId kRemoteDeviceId = chip::kTestDeviceNodeId;
extern "C" {
CHIP_ERROR pychip_DeviceController_NewDeviceController(chip::Controller::DeviceCommissioner ** outDevCtrl,
chip::NodeId localDeviceId);
CHIP_ERROR pychip_DeviceController_DeleteDeviceController(chip::Controller::DeviceCommissioner * devCtrl);
CHIP_ERROR
pychip_DeviceController_GetAddressAndPort(chip::Controller::DeviceCommissioner * devCtrl, chip::NodeId nodeId, char * outAddress,
uint64_t maxAddressLen, uint16_t * outPort);
// Rendezvous
CHIP_ERROR pychip_DeviceController_ConnectBLE(chip::Controller::DeviceCommissioner * devCtrl, uint16_t discriminator,
uint32_t setupPINCode, chip::NodeId nodeid);
CHIP_ERROR pychip_DeviceController_ConnectIP(chip::Controller::DeviceCommissioner * devCtrl, const char * peerAddrStr,
uint32_t setupPINCode, chip::NodeId nodeid);
CHIP_ERROR pychip_DeviceController_DiscoverCommissioningLongDiscriminator(chip::Controller::DeviceCommissioner * devCtrl,
uint16_t long_discriminator);
CHIP_ERROR pychip_DeviceController_DiscoverAllCommissioning(chip::Controller::DeviceCommissioner * devCtrl);
void pychip_DeviceController_PrintDiscoveredDevices(chip::Controller::DeviceCommissioner * devCtrl);
bool pychip_DeviceController_GetIPForDiscoveredDevice(chip::Controller::DeviceCommissioner * devCtrl, int idx, char * addrStr,
uint32_t len);
// Pairing Delegate
CHIP_ERROR
pychip_ScriptDevicePairingDelegate_SetKeyExchangeCallback(chip::Controller::DeviceCommissioner * devCtrl,
chip::Controller::DevicePairingDelegate_OnPairingCompleteFunct callback);
void pychip_ScriptDeviceAddressUpdateDelegate_SetOnAddressUpdateComplete(
chip::Controller::DeviceAddressUpdateDelegate_OnUpdateComplete callback);
CHIP_ERROR pychip_Resolver_ResolveNode(uint64_t fabricid, chip::NodeId nodeid);
// BLE
CHIP_ERROR pychip_DeviceCommissioner_CloseBleConnection(chip::Controller::DeviceCommissioner * devCtrl);
uint8_t pychip_DeviceController_GetLogFilter();
void pychip_DeviceController_SetLogFilter(uint8_t category);
CHIP_ERROR pychip_Stack_Init();
CHIP_ERROR pychip_Stack_Shutdown();
const char * pychip_Stack_ErrorToString(CHIP_ERROR err);
const char * pychip_Stack_StatusReportToString(uint32_t profileId, uint16_t statusCode);
void pychip_Stack_SetLogFunct(LogMessageFunct logFunct);
CHIP_ERROR pychip_GetDeviceByNodeId(chip::Controller::DeviceCommissioner * devCtrl, chip::NodeId nodeId,
chip::Controller::Device ** device);
uint64_t pychip_GetCommandSenderHandle(chip::Controller::Device * device);
// CHIP Stack objects
CHIP_ERROR pychip_BLEMgrImpl_ConfigureBle(uint32_t bluetoothAdapterId);
}
CHIP_ERROR pychip_DeviceController_NewDeviceController(chip::Controller::DeviceCommissioner ** outDevCtrl,
chip::NodeId localDeviceId)
{
CHIP_ERROR err = CHIP_NO_ERROR;
CommissionerInitParams initParams;
*outDevCtrl = new chip::Controller::DeviceCommissioner();
VerifyOrExit(*outDevCtrl != NULL, err = CHIP_ERROR_NO_MEMORY);
if (localDeviceId == chip::kUndefinedNodeId)
{
localDeviceId = kDefaultLocalDeviceId;
}
ReturnErrorOnFailure(sOperationalCredentialsIssuer.Initialize());
initParams.storageDelegate = &sStorageDelegate;
initParams.mDeviceAddressUpdateDelegate = &sDeviceAddressUpdateDelegate;
initParams.pairingDelegate = &sPairingDelegate;
initParams.operationalCredentialsDelegate = &sOperationalCredentialsIssuer;
initParams.imDelegate = &PythonInteractionModelDelegate::Instance();
SuccessOrExit(err = (*outDevCtrl)->Init(localDeviceId, initParams));
SuccessOrExit(err = (*outDevCtrl)->ServiceEvents());
exit:
return err;
}
CHIP_ERROR pychip_DeviceController_DeleteDeviceController(chip::Controller::DeviceCommissioner * devCtrl)
{
if (devCtrl != NULL)
{
devCtrl->Shutdown();
delete devCtrl;
}
return CHIP_NO_ERROR;
}
CHIP_ERROR pychip_DeviceController_GetAddressAndPort(chip::Controller::DeviceCommissioner * devCtrl, chip::NodeId nodeId,
char * outAddress, uint64_t maxAddressLen, uint16_t * outPort)
{
Device * device;
ReturnErrorOnFailure(devCtrl->GetDevice(nodeId, &device));
Inet::IPAddress address;
VerifyOrReturnError(device->GetAddress(address, *outPort), CHIP_ERROR_INCORRECT_STATE);
VerifyOrReturnError(address.ToString(outAddress, maxAddressLen), CHIP_ERROR_BUFFER_TOO_SMALL);
return CHIP_NO_ERROR;
}
const char * pychip_DeviceController_ErrorToString(CHIP_ERROR err)
{
return chip::ErrorStr(err);
}
const char * pychip_DeviceController_StatusReportToString(uint32_t profileId, uint16_t statusCode)
{
// return chip::StatusReportStr(profileId, statusCode);
return NULL;
}
uint8_t pychip_DeviceController_GetLogFilter()
{
#if _CHIP_USE_LOGGING
return chip::Logging::GetLogFilter();
#else
return chip::Logging::kLogCategory_None;
#endif
}
void pychip_DeviceController_SetLogFilter(uint8_t category)
{
#if _CHIP_USE_LOGGING
chip::Logging::SetLogFilter(category);
#endif
}
CHIP_ERROR pychip_DeviceController_ConnectBLE(chip::Controller::DeviceCommissioner * devCtrl, uint16_t discriminator,
uint32_t setupPINCode, chip::NodeId nodeid)
{
return devCtrl->PairDevice(nodeid,
chip::RendezvousParameters()
.SetPeerAddress(Transport::PeerAddress(Transport::Type::kBle))
.SetSetupPINCode(setupPINCode)
.SetDiscriminator(discriminator));
}
CHIP_ERROR pychip_DeviceController_ConnectIP(chip::Controller::DeviceCommissioner * devCtrl, const char * peerAddrStr,
uint32_t setupPINCode, chip::NodeId nodeid)
{
CHIP_ERROR err = CHIP_NO_ERROR;
chip::Inet::IPAddress peerAddr;
chip::Transport::PeerAddress addr;
chip::RendezvousParameters params = chip::RendezvousParameters().SetSetupPINCode(setupPINCode);
VerifyOrReturnError(chip::Inet::IPAddress::FromString(peerAddrStr, peerAddr), err = CHIP_ERROR_INVALID_ARGUMENT);
// TODO: IP rendezvous should use TCP connection.
addr.SetTransportType(chip::Transport::Type::kUdp).SetIPAddress(peerAddr);
params.SetPeerAddress(addr).SetDiscriminator(0);
return devCtrl->PairDevice(nodeid, params);
}
CHIP_ERROR pychip_DeviceController_DiscoverAllCommissioning(chip::Controller::DeviceCommissioner * devCtrl)
{
return devCtrl->DiscoverAllCommissioning();
}
CHIP_ERROR pychip_DeviceController_DiscoverCommissioningLongDiscriminator(chip::Controller::DeviceCommissioner * devCtrl,
uint16_t long_discriminator)
{
return devCtrl->DiscoverCommissioningLongDiscriminator(long_discriminator);
}
void pychip_DeviceController_PrintDiscoveredDevices(chip::Controller::DeviceCommissioner * devCtrl)
{
for (int i = 0; i < devCtrl->GetMaxCommissionableNodesSupported(); ++i)
{
const chip::Mdns::CommissionableNodeData * dnsSdInfo = devCtrl->GetDiscoveredDevice(i);
if (dnsSdInfo == nullptr)
{
continue;
}
ChipLogProgress(Discovery, "Device %d", i);
ChipLogProgress(Discovery, "\tHost name:\t\t%s", dnsSdInfo->hostName);
ChipLogProgress(Discovery, "\tLong discriminator:\t%u", dnsSdInfo->longDiscriminator);
ChipLogProgress(Discovery, "\tVendor ID:\t\t%u", dnsSdInfo->vendorId);
ChipLogProgress(Discovery, "\tProduct ID:\t\t%u", dnsSdInfo->productId);
for (int j = 0; j < dnsSdInfo->numIPs; ++j)
{
char buf[chip::Inet::kMaxIPAddressStringLength];
dnsSdInfo->ipAddress[j].ToString(buf);
ChipLogProgress(Discovery, "\tAddress %d:\t\t%s", j, buf);
}
}
}
bool pychip_DeviceController_GetIPForDiscoveredDevice(chip::Controller::DeviceCommissioner * devCtrl, int idx, char * addrStr,
uint32_t len)
{
const chip::Mdns::CommissionableNodeData * 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;
}
CHIP_ERROR
pychip_ScriptDevicePairingDelegate_SetKeyExchangeCallback(chip::Controller::DeviceCommissioner * devCtrl,
chip::Controller::DevicePairingDelegate_OnPairingCompleteFunct callback)
{
sPairingDelegate.SetKeyExchangeCallback(callback);
return CHIP_NO_ERROR;
}
void pychip_ScriptDeviceAddressUpdateDelegate_SetOnAddressUpdateComplete(
chip::Controller::DeviceAddressUpdateDelegate_OnUpdateComplete callback)
{
sDeviceAddressUpdateDelegate.SetOnAddressUpdateComplete(callback);
}
CHIP_ERROR pychip_Resolver_ResolveNode(uint64_t fabricid, chip::NodeId nodeid)
{
return Mdns::Resolver::Instance().ResolveNodeId(PeerId().SetNodeId(nodeid).SetFabricId(fabricid), Inet::kIPAddressType_Any);
}
CHIP_ERROR pychip_Stack_Init()
{
CHIP_ERROR err = CHIP_NO_ERROR;
err = chip::Platform::MemoryInit();
SuccessOrExit(err);
#if !CHIP_SYSTEM_CONFIG_USE_SOCKETS
ExitNow(err = CHIP_ERROR_NOT_IMPLEMENTED);
#else /* CHIP_SYSTEM_CONFIG_USE_SOCKETS */
#endif /* CHIP_SYSTEM_CONFIG_USE_SOCKETS */
exit:
if (err != CHIP_NO_ERROR)
pychip_Stack_Shutdown();
return err;
}
CHIP_ERROR pychip_Stack_Shutdown()
{
return CHIP_NO_ERROR;
}
const char * pychip_Stack_ErrorToString(CHIP_ERROR err)
{
return chip::ErrorStr(err);
}
const char * pychip_Stack_StatusReportToString(uint32_t profileId, uint16_t statusCode)
{
// return chip::StatusReportStr(profileId, statusCode);
return NULL;
}
CHIP_ERROR pychip_GetDeviceByNodeId(chip::Controller::DeviceCommissioner * devCtrl, chip::NodeId nodeId,
chip::Controller::Device ** device)
{
VerifyOrReturnError(devCtrl != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
return devCtrl->GetDevice(nodeId, device);
}
CHIP_ERROR pychip_DeviceCommissioner_CloseBleConnection(chip::Controller::DeviceCommissioner * devCtrl)
{
#if CONFIG_NETWORK_LAYER_BLE
return devCtrl->CloseBleConnection();
#else
return CHIP_ERROR_UNSUPPORTED_CHIP_FEATURE;
#endif
}
uint64_t pychip_GetCommandSenderHandle(chip::Controller::Device * device)
{
chip::app::CommandSender * sender = device->GetCommandSender();
return sender == nullptr ? 0 : reinterpret_cast<uint64_t>(sender);
}
void pychip_Stack_SetLogFunct(LogMessageFunct logFunct)
{
// TODO: determine if log redirection is supposed to be functioning in CHIP
//
// Background: original log baseline supported 'redirect logs to this
// function' however CHIP does not currently provide this.
//
// Ideally log redirection should work so that python code can do things
// like using the log module.
}