Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[controller] Add IP rendezvous feature to CHIP Device controller #4050

Merged
merged 16 commits into from
Dec 9, 2020
Merged
26 changes: 20 additions & 6 deletions src/controller/CHIPDeviceController.cpp
Original file line number Diff line number Diff line change
@@ -473,25 +473,39 @@ CHIP_ERROR DeviceCommissioner::PairDevice(NodeId remoteDeviceId, RendezvousParam
VerifyOrExit(mState == State::Initialized, err = CHIP_ERROR_INCORRECT_STATE);
VerifyOrExit(mDeviceBeingPaired == kNumMaxActiveDevices, err = CHIP_ERROR_INCORRECT_STATE);

#if CONFIG_DEVICE_LAYER && CONFIG_NETWORK_LAYER_BLE
if (!params.HasBleLayer())
// TODO: We need to specify the peer address for BLE transport in bindings.
if (params.GetPeerAddress().GetTransportType() == Transport::Type::kBle ||
params.GetPeerAddress().GetTransportType() == Transport::Type::kUndefined)
{
params.SetBleLayer(DeviceLayer::ConnectivityMgr().GetBleLayer());
params.SetPeerAddress(Transport::PeerAddress::BLE());
}
#if CONFIG_DEVICE_LAYER && CONFIG_NETWORK_LAYER_BLE
if (!params.HasBleLayer())
{
params.SetBleLayer(DeviceLayer::ConnectivityMgr().GetBleLayer());
params.SetPeerAddress(Transport::PeerAddress::BLE());
}
#endif // CONFIG_DEVICE_LAYER && CONFIG_NETWORK_LAYER_BLE
}

mDeviceBeingPaired = GetInactiveDeviceIndex();
VerifyOrExit(mDeviceBeingPaired < kNumMaxActiveDevices, err = CHIP_ERROR_NO_MEMORY);
device = &mActiveDevices[mDeviceBeingPaired];

mIsIPRendezvous = (params.GetPeerAddress().GetTransportType() != Transport::Type::kBle);
mRendezvousSession = chip::Platform::New<RendezvousSession>(this);
VerifyOrExit(mRendezvousSession != nullptr, err = CHIP_ERROR_NO_MEMORY);
err = mRendezvousSession->Init(params.SetLocalNodeId(mLocalDeviceId).SetRemoteNodeId(remoteDeviceId), mTransportMgr);
SuccessOrExit(err);

device->Init(mTransportMgr, mSessionManager, mInetLayer, remoteDeviceId, remotePort, interfaceId);

// TODO: BLE rendezvous and IP rendezvous should have same logic in the future after BLE becomes a transport and network
// provisiong cluster is ready.
if (params.GetPeerAddress().GetTransportType() != Transport::Type::kBle)
{
device->SetAddress(params.GetPeerAddress().GetIPAddress());
mRendezvousSession->OnRendezvousConnectionOpened();
}

exit:
if (err != CHIP_NO_ERROR)
{
@@ -675,7 +689,7 @@ void DeviceCommissioner::OnRendezvousStatusUpdate(RendezvousSessionDelegate::Sta
ChipLogDetail(Controller, "Remote device completed SPAKE2+ handshake\n");
mRendezvousSession->GetPairingSession().ToSerializable(device->GetPairing());

if (mPairingDelegate != nullptr)
if (!mIsIPRendezvous && mPairingDelegate != nullptr)
{
mPairingDelegate->OnNetworkCredentialsRequested(mRendezvousSession);
}
4 changes: 4 additions & 0 deletions src/controller/CHIPDeviceController.h
Original file line number Diff line number Diff line change
@@ -297,6 +297,10 @@ class DLL_EXPORT DeviceCommissioner : public DeviceController, public Rendezvous
If no device is currently being paired, this value will be kNumMaxPairedDevices. */
uint16_t mDeviceBeingPaired;

/* This is a temporary flag, when using IP rendezvous, we need to disable network provisioning.
In the future, network provisioning will no longer be a part of rendezvous procedure. */
bool mIsIPRendezvous;

/* This field is true when device pairing information changes, e.g. a new device is paired, or
the pairing for a device is removed. The DeviceCommissioner uses this to decide when to
persist the device list */
3 changes: 3 additions & 0 deletions src/controller/CHIPDeviceController_deprecated.cpp
Original file line number Diff line number Diff line change
@@ -113,6 +113,9 @@ CHIP_ERROR ChipDeviceController::ConnectDevice(NodeId remoteDeviceId, Rendezvous
mOnComplete.Response = onMessageReceived;
mOnError = onError;

// TODO: Should call mOnNewConnected when rendezvous completed
mOnNewConnection(this, nullptr, mAppReqState);

exit:
return err;
}
1 change: 1 addition & 0 deletions src/controller/python/BUILD.gn
Original file line number Diff line number Diff line change
@@ -41,6 +41,7 @@ shared_library("ChipDeviceCtrl") {
"ChipDeviceController-ScriptBinding.cpp",
"ChipDeviceController-ScriptDevicePairingDelegate.cpp",
"ChipDeviceController-ScriptDevicePairingDelegate.h",
"ChipDeviceController-StorageDelegate.h",
]

public_deps = [
38 changes: 30 additions & 8 deletions src/controller/python/ChipDeviceController-ScriptBinding.cpp
Original file line number Diff line number Diff line change
@@ -44,13 +44,16 @@
#endif /* CONFIG_NETWORK_LAYER_BLE */

#include "ChipDeviceController-ScriptDevicePairingDelegate.h"
#include "ChipDeviceController-StorageDelegate.h"

#include <controller/CHIPDeviceController_deprecated.h>
#include <support/CHIPMem.h>
#include <support/CodeUtils.h>
#include <support/DLLUtil.h>
#include <support/ReturnMacros.h>
#include <support/logging/CHIPLogging.h>

using namespace chip;
using namespace chip::Ble;
using namespace chip::DeviceController;

@@ -125,6 +128,7 @@ class BleDisconnectEvent : public BleEventBase

static chip::System::Layer sSystemLayer;
static chip::Inet::InetLayer sInetLayer;
static chip::Controller::PythonPersistentStorageDelegate sStorageDelegate;

// 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
@@ -170,6 +174,9 @@ CHIP_ERROR nl_Chip_DeviceController_DeleteDeviceController(chip::DeviceControlle
CHIP_ERROR nl_Chip_DeviceController_Connect(chip::DeviceController::ChipDeviceController * devCtrl, BLE_CONNECTION_OBJECT connObj,
uint32_t setupPinCode, OnConnectFunct onConnect, OnMessageFunct onMessage,
OnErrorFunct onError);
CHIP_ERROR nl_Chip_DeviceController_ConnectIP(chip::DeviceController::ChipDeviceController * devCtrl, const char * peerAddrStr,
uint32_t setupPINCode, OnConnectFunct onConnect, OnMessageFunct onMessage,
OnErrorFunct onError);

// Network Provisioning
CHIP_ERROR
@@ -204,7 +211,7 @@ CHIP_ERROR nl_Chip_DeviceController_NewDeviceController(chip::DeviceController::
*outDevCtrl = new chip::DeviceController::ChipDeviceController();
VerifyOrExit(*outDevCtrl != NULL, err = CHIP_ERROR_NO_MEMORY);

err = (*outDevCtrl)->Init(kLocalDeviceId, &sSystemLayer, &sInetLayer);
err = (*outDevCtrl)->Init(kLocalDeviceId, &sSystemLayer, &sInetLayer, nullptr, &sStorageDelegate);
SuccessOrExit(err);

exit:
@@ -531,14 +538,29 @@ CHIP_ERROR nl_Chip_DeviceController_Connect(chip::DeviceController::ChipDeviceCo
uint32_t setupPINCode, OnConnectFunct onConnect, OnMessageFunct onMessage,
OnErrorFunct onError)
{
CHIP_ERROR err = CHIP_NO_ERROR;
chip::RendezvousParameters params =
chip::RendezvousParameters().SetSetupPINCode(setupPINCode).SetConnectionObject(connObj).SetBleLayer(&sBle);
err = devCtrl->ConnectDevice(kRemoteDeviceId, params, (void *) devCtrl, onConnect, onMessage, onError);
SuccessOrExit(err);
return devCtrl->ConnectDevice(kRemoteDeviceId,
chip::RendezvousParameters()
.SetPeerAddress(Transport::PeerAddress(Transport::Type::kBle))
.SetSetupPINCode(setupPINCode)
.SetConnectionObject(connObj)
.SetBleLayer(&sBle),
(void *) devCtrl, onConnect, onMessage, onError);
}

exit:
return err;
CHIP_ERROR nl_Chip_DeviceController_ConnectIP(chip::DeviceController::ChipDeviceController * devCtrl, const char * peerAddrStr,
uint32_t setupPINCode, OnConnectFunct onConnect, OnMessageFunct onMessage,
OnErrorFunct onError)
{
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->ConnectDevice(kRemoteDeviceId, params, (void *) devCtrl, onConnect, onMessage, onError);
}

CHIP_ERROR
45 changes: 45 additions & 0 deletions src/controller/python/ChipDeviceController-StorageDelegate.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
*
* 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 <controller/CHIPPersistentStorageDelegate.h>

class PythonPersistentStorageDelegate;

typedef void (*GetKeyValueFunct)(const uint8_t * key, uint8_t * value, uint16_t * size);
typedef void (*SetKeyValueFunct)(const uint8_t * key, const uint8_t * value);
typedef void (*DeleteKeyValueFunct)(const uint8_t * key);

namespace chip {
namespace Controller {

// TODO: Implement this.
class PythonPersistentStorageDelegate : public PersistentStorageDelegate
{
public:
PythonPersistentStorageDelegate() {}
void SetDelegate(PersistentStorageResultDelegate * delegate) override {}
void GetKeyValue(const char * key) override {}
CHIP_ERROR GetKeyValue(const char * key, char * value, uint16_t & size) override { return CHIP_ERROR_NOT_IMPLEMENTED; }
void SetKeyValue(const char * key, const char * value) override {}
void DeleteKeyValue(const char * key) override {}
};

} // namespace Controller
} // namespace chip
15 changes: 10 additions & 5 deletions src/controller/python/chip-device-ctrl.py
Original file line number Diff line number Diff line change
@@ -365,7 +365,8 @@ def do_btpconnect(self, line):

def do_connect(self, line):
"""
connect (via BLE) <setup pin code>
connect -ip <ip address> <setup pin code>
connect -ble <setup pin code>

connect command is used for establishing a rendezvous session to the device.
currently, only connect using setupPinCode is supported.
@@ -376,14 +377,18 @@ def do_connect(self, line):

try:
args = shlex.split(line)
if not args:
if len(args) <= 1:
print("Usage:")
self.do_help("connect SetupPinCode")
return
if len(args) > 1:
print("Unexpected argument: " + args[1])
if args[0] == "-ip" and len(args) == 3:
self.devCtrl.ConnectIP(args[1].encode("utf-8"), int(args[2]))
elif args[0] == "-ble" and len(args) == 2:
self.devCtrl.Connect(FAKE_CONN_OBJ_VALUE, int(args[1]))
else:
print("Usage:")
self.do_help("connect SetupPinCode")
return
self.devCtrl.Connect(FAKE_CONN_OBJ_VALUE, int(args[0]))
except ChipStack.ChipStackException as ex:
print(str(ex))
return
47 changes: 34 additions & 13 deletions src/controller/python/chip/ChipDeviceCtrl.py
Original file line number Diff line number Diff line change
@@ -94,12 +94,12 @@ def __init__(self, startNetworkThread=True):
res = self._dmLib.nl_Chip_DeviceController_NewDeviceController(pointer(devCtrl))
if res != 0:
raise self._ChipStack.ErrorToException(res)

pairingDelegate = c_void_p(None)
res = self._dmLib.nl_Chip_ScriptDevicePairingDelegate_NewPairingDelegate(pointer(pairingDelegate))
if res != 0:
raise self._ChipStack.ErrorToException(res)

res = self._dmLib.nl_Chip_DeviceController_SetDevicePairingDelegate(devCtrl, pairingDelegate)
if res != 0:
raise self._ChipStack.ErrorToException(res)
@@ -108,27 +108,29 @@ def __init__(self, startNetworkThread=True):
self.pairingDelegate = pairingDelegate
self._ChipStack.devCtrl = devCtrl

self.blockingCB = None # set by other modules(BLE) that require service by thread while thread blocks.
# set by other modules(BLE) that require service by thread while thread blocks.
self.blockingCB = None
self.cbHandleBleEvent = (
None # set by other modules (BLE) that provide event callback to Chip.
# set by other modules (BLE) that provide event callback to Chip.
None
)
self.cbHandleBleWriteChar = None
self.cbHandleBleSubscribeChar = None
self.cbHandleBleClose = None

def DeviceCtrlHandleMessage(appReqState, buffer):
pass

self.cbHandleMessage = _OnMessageFunct(DeviceCtrlHandleMessage)

def HandleRendezvousError(appState, reqState, err, devStatusPtr):
if self.state == DCState.RENDEZVOUS_ONGOING:
print("Failed to connect to device: {}".format(err))
self._ChipStack.callbackRes = True
self._ChipStack.completeEvent.set()
elif self.state == DCState.RENDEZVOUS_CONNECTED:
print("Disconnected from device")

self.cbHandleRendezvousError = _OnRendezvousErrorFunct(HandleRendezvousError)

if startNetworkThread:
@@ -202,19 +204,33 @@ def ConnectBle(self, bleConnection):
self._ChipStack.cbHandleError,
)
)

def Connect(self, connObj, setupPinCode):
def HandleComplete(dc, connState, appState):
print("Rendezvoud Complete")
print("Rendezvous Complete")
self.state = DCState.RENDEZVOUS_CONNECTED
self._ChipStack.callbackRes = True
self._ChipStack.completeEvent.set()
onConnectFunct = _OnConnectFunct(HandleComplete)

self.state = DCState.RENDEZVOUS_ONGOING
return self._ChipStack.CallAsync(
lambda: self._dmLib.nl_Chip_DeviceController_Connect(
self.devCtrl, connObj, setupPinCode, onConnectFunct, self.cbHandleMessage, self.cbHandleRendezvousError)
)

def ConnectIP(self, ipaddr, setupPinCode):
def HandleComplete(dc, connState, appState):
print("Rendezvous Complete")
self.state = DCState.RENDEZVOUS_CONNECTED
self._ChipStack.callbackRes = True
self._ChipStack.completeEvent.set()

onConnectFunct = _OnConnectFunct(HandleComplete)

self.state = DCState.RENDEZVOUS_ONGOING
return self._ChipStack.CallAsync(
lambda: self._dmLib.nl_Chip_DeviceController_Connect(self.devCtrl, connObj, setupPinCode, onConnectFunct, self.cbHandleMessage, self.cbHandleRendezvousError)
lambda: self._dmLib.nl_Chip_DeviceController_ConnectIP(
self.devCtrl, ipaddr, setupPinCode, onConnectFunct, self.cbHandleMessage, self.cbHandleRendezvousError)
)

def Close(self):
@@ -237,7 +253,7 @@ def GetLogFilter(self):

def SetBlockingCB(self, blockingCB):
self._ChipStack.blockingCB = blockingCB

def SetWifiCredential(self, ssid, password):
ret = self._dmLib.nl_Chip_ScriptDevicePairingDelegate_SetWifiCredential(self.pairingDelegate, ssid.encode("utf-8"), password.encode("utf-8"))
if ret != 0:
@@ -308,9 +324,14 @@ def _InitLib(self):
self._dmLib.nl_Chip_DeviceController_SetLogFilter.argtypes = [c_uint8]
self._dmLib.nl_Chip_DeviceController_SetLogFilter.restype = None

self._dmLib.nl_Chip_DeviceController_Connect.argtypes = [c_void_p, c_void_p, c_uint32, _OnConnectFunct, _OnMessageFunct, _OnRendezvousErrorFunct]
self._dmLib.nl_Chip_DeviceController_Connect.argtypes = [
c_void_p, c_void_p, c_uint32, _OnConnectFunct, _OnMessageFunct, _OnRendezvousErrorFunct]
self._dmLib.nl_Chip_DeviceController_Connect.restype = c_uint32

self._dmLib.nl_Chip_DeviceController_ConnectIP.argtypes = [
c_void_p, c_char_p, c_uint32, _OnConnectFunct, _OnMessageFunct, _OnRendezvousErrorFunct]
self._dmLib.nl_Chip_DeviceController_ConnectIP.restype = c_uint32

self._dmLib.nl_Chip_ScriptDevicePairingDelegate_NewPairingDelegate.argtypes = [POINTER(c_void_p)]
self._dmLib.nl_Chip_ScriptDevicePairingDelegate_NewPairingDelegate.restype = c_uint32

2 changes: 1 addition & 1 deletion src/test_driver/linux-cirque/OnOffClusterTest.sh
Original file line number Diff line number Diff line change
@@ -39,7 +39,7 @@ function build_chip_lighting() {
source "$REPO_DIR/scripts/activate.sh" >/dev/null
set -x
cd "$chip_light_dir"
gn gen --check --fail-on-unused-args out/debug --args='chip_bypass_rendezvous=true'
gn gen --check --fail-on-unused-args out/debug
run_ninja -C out/debug
docker build -t chip_server -f Dockerfile . 2>&1
set +x
Loading