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

[WIP][linux] add ThreadStackManager for Linux Device layer #1147

Closed
wants to merge 2 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -29,6 +29,7 @@ third_party/nlunit-test/
third_party/mbedtls/
examples/common/m5stack-tft/
examples/common/QRCode/repo/
third_party/ot-br-posix/repo

# Example specific rules
examples/**/sdkconfig
58 changes: 58 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
@@ -1773,6 +1773,63 @@ if test "${nl_cv_build_tests}" = "yes"; then
fi
fi

#
# otbr-client
#

NL_WITH_PACKAGE(
[otbrclient],
[OTBRCLIENT],
[otbrclient],
[],
[
OTBRCLIENT_CPPFLAGS=
OTBRCLIENT_LDFLAGS=
OTBRCLIENT_LIBS=
],
[
AC_LANG_PUSH([C++])
AC_LANG_POP([C++])
]
)

AC_MSG_NOTICE("nl_with_otbrclient=${nl_with_otbrclient}")

# Depending on whether nlfaultinjection has been configured for an internal
# location, its directory stem within this package needs to be set
# accordingly. In addition, if the location is internal, then we need
# to attempt to pull it down using the bootstrap makefile.

if test "${nl_with_otbrclient}" = "internal"; then
maybe_otbrclient_dirstem="ot-br-posix"
otbrclient_dirstem="third_party/${maybe_otbrclient_dirstem}/repo"

AC_MSG_NOTICE([attempting to create internal ${otbrclient_dirstem}])

${MAKE-make} --no-print-directory -C ${srcdir} -f Makefile-bootstrap ${otbrclient_dirstem}

if test $? -ne 0; then
AC_MSG_ERROR([failed to create ${otbrclient_dirstem}. Please check your network connection or the correctness of 'repos.conf'])
fi

# otbrclient requires dbus
PKG_CHECK_MODULES(DBUS, dbus-1 >= 1.4)
AC_SUBST([DBUS_CFLAGS])
AC_SUBST([DBUS_LIBS])
else
AC_MSG_ERROR("not copying!! nl_with_otbrclient=${nl_with_otbrclient}")
maybe_otbrclient_dirstem=""
fi

AC_SUBST(OTBRCLIENT_SUBDIRS, [${maybe_otbrclient_dirstem}])
AM_CONDITIONAL([CHIP_WITH_OTBRCLIENT], [test "${nl_with_otbrclient}" != "no"])
AM_CONDITIONAL([CHIP_WITH_OTBRCLIENT_INTERNAL], [test "${nl_with_otbrclient}" = "internal"])

if test "${nl_with_otbrclient}" = "no"; then
AC_DEFINE([CHIP_WITH_OTBRCLIENT], [0], [Define to 1 to build CHIP with otbr client features])
else
AC_DEFINE([CHIP_WITH_OTBRCLIENT], [1], [Define to 1 to build CHIP with otbr client features])
fi

#
# Nlunit-test
@@ -2102,6 +2159,7 @@ examples/Makefile
third_party/Makefile
third_party/lwip/Makefile
third_party/mbedtls/Makefile
third_party/ot-br-posix/Makefile
src/Makefile
src/include/Makefile
src/app/Makefile
5 changes: 5 additions & 0 deletions repos.conf
Original file line number Diff line number Diff line change
@@ -33,3 +33,8 @@
url = https://github.com/jeremyjh/ESP32_TFT_library.git
branch = master
update = none
[submodule "ot-br-posix"]
path = third_party/ot-br-posix/repo
url = https://github.com/openthread/ot-br-posix.git
branch = master
update = none
1 change: 1 addition & 0 deletions scripts/setup/linux/install_packages.sh
Original file line number Diff line number Diff line change
@@ -22,6 +22,7 @@ apt-get install -fy \
libssl-dev \
unzip \
wget \
libdbus-1-dev \
libmbedtls-dev

if [[ ! -f 'ci-cache-persistent/openssl/open_ssl_1.1.1f_installed' ]]; then
2 changes: 2 additions & 0 deletions src/include/platform/PlatformManager.h
Original file line number Diff line number Diff line change
@@ -46,6 +46,7 @@ class PlatformManagerImpl;
class ConnectivityManagerImpl;
class ConfigurationManagerImpl;
class TraitManager;
class ThreadStackManagerImpl;
class TimeSyncManager;
namespace Internal {
class FabricProvisioningServer;
@@ -97,6 +98,7 @@ class PlatformManager
friend class ConnectivityManagerImpl;
friend class ConfigurationManagerImpl;
friend class TraitManager;
friend class ThreadStackManagerImpl;
friend class TimeSyncManager;
friend class Internal::FabricProvisioningServer;
friend class Internal::ServiceProvisioningServer;
2 changes: 1 addition & 1 deletion src/include/platform/ThreadStackManager.h
Original file line number Diff line number Diff line change
@@ -67,7 +67,7 @@ class ThreadStackManager
void LockThreadStack(void);
bool TryLockThreadStack(void);
void UnlockThreadStack(void);
bool HaveRouteToAddress(const IPAddress & destAddr);
bool HaveRouteToAddress(const Inet::IPAddress & destAddr);
CHIP_ERROR GetAndLogThreadStatsCounters(void);
CHIP_ERROR GetAndLogThreadTopologyMinimal(void);
CHIP_ERROR GetAndLogThreadTopologyFull(void);
74 changes: 74 additions & 0 deletions src/include/platform/internal/DeviceNetworkInfo.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/*
*
* Copyright (c) 2020 Project CHIP Authors
* Copyright (c) 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.
*/

#ifndef DEVICE_NETWORK_INFO_H
#define DEVICE_NETWORK_INFO_H

#include <stdint.h>

namespace chip {
namespace DeviceLayer {
namespace Internal {

/**
* Ids for well-known network provision types.
*/
enum
{
kThreadNetworkId = 1,
kWiFiStationNetworkId = 2,
kMaxThreadNetworkNameLength = 16,
kThreadExtendedPANIdLength = 8,
kThreadMeshPrefixLength = 8,
kThreadNetworkKeyLength = 16,
kThreadPSKcLength = 16,
kThreadChannel_NotSpecified = UINT8_MAX,
kThreadPANId_NotSpecified = UINT16_MAX,
};

class DeviceNetworkInfo
{
public:
// ---- Thread-specific Fields ----
char ThreadNetworkName[kMaxThreadNetworkNameLength + 1];
/**< The Thread network name as a NULL-terminated string. */
uint8_t ThreadExtendedPANId[kThreadExtendedPANIdLength];
/**< The Thread extended PAN ID. */
uint8_t ThreadMeshPrefix[kThreadMeshPrefixLength];
/**< The Thread mesh prefix. */
uint8_t ThreadNetworkKey[kThreadNetworkKeyLength];
/**< The Thread master network key (NOT NULL-terminated). */
uint8_t ThreadPSKc[kThreadPSKcLength];
/**< The Thread pre-shared commissioner key (NOT NULL-terminated). */
uint16_t ThreadPANId; /**< The 16-bit Thread PAN ID, or kThreadPANId_NotSpecified */
uint8_t ThreadChannel; /**< The Thread channel (currently [11..26]), or kThreadChannel_NotSpecified */

struct
{
bool ThreadExtendedPANId : 1;
bool ThreadMeshPrefix : 1;
bool ThreadPSKc : 1;
} FieldPresent;
};

} // namespace Internal
} // namespace DeviceLayer
} // namespace chip

#endif // DEVICE_NETWORK_INFO_H
34 changes: 30 additions & 4 deletions src/include/platform/internal/GenericPlatformManagerImpl_POSIX.h
Original file line number Diff line number Diff line change
@@ -27,14 +27,18 @@

#include <platform/internal/GenericPlatformManagerImpl.h>

#include <map>
#include <memory>
#include <queue>

#include <fcntl.h>
#include <pthread.h>
#include <sched.h>
#include <sys/select.h>
#include <sys/time.h>
#include <unistd.h>

#include <pthread.h>
#include <queue>
#include <dbus/dbus.h>

namespace chip {
namespace DeviceLayer {
@@ -51,6 +55,10 @@ namespace Internal {
template <class ImplClass>
class GenericPlatformManagerImpl_POSIX : public GenericPlatformManagerImpl<ImplClass>
{
public:
// ===== Public methods
DBusConnection &GetSystemDBusConnection();

protected:
// Members for select loop
int mMaxFd;
@@ -79,8 +87,6 @@ class GenericPlatformManagerImpl_POSIX : public GenericPlatformManagerImpl<ImplC
CHIP_ERROR _StartEventLoopTask(void);
CHIP_ERROR _StartChipTimer(uint32_t durationMS);

// ===== Methods available to the implementation subclass.

private:
// ===== Private members for use by this class only.

@@ -93,6 +99,26 @@ class GenericPlatformManagerImpl_POSIX : public GenericPlatformManagerImpl<ImplC
void ProcessDeviceEvents();

static void * EventLoopTaskMain(void * arg);

static dbus_bool_t AddDBusWatch(struct DBusWatch *aWatch, void *aContext);
static void RemoveDBusWatch(struct DBusWatch *aWatch, void *aContext);
static void ToggleDBusWatch(struct DBusWatch *aWatch, void *aContext);

void UpdateDBusFdSet();
void ProcessDBus();

struct DBusConnectionDeleter
{
void operator()(DBusConnection *aConnection) { dbus_connection_unref(aConnection); }
};
using UniqueDBusConnection = std::unique_ptr<DBusConnection, DBusConnectionDeleter>;
UniqueDBusConnection mDBusConnection;
/**
* This map is used to track DBusWatch-es.
*
*/
using WatchMap = std::map<DBusWatch *, bool>;
WatchMap mWatches;
};

// Instruct the compiler to instantiate the template only when explicitly told to do so.
138 changes: 134 additions & 4 deletions src/include/platform/internal/GenericPlatformManagerImpl_POSIX.ipp
Original file line number Diff line number Diff line change
@@ -24,8 +24,8 @@
#ifndef GENERIC_PLATFORM_MANAGER_IMPL_POSIX_IPP
#define GENERIC_PLATFORM_MANAGER_IMPL_POSIX_IPP

#include <platform/internal/CHIPDeviceLayerInternal.h>
#include <platform/PlatformManager.h>
#include <platform/internal/CHIPDeviceLayerInternal.h>
#include <platform/internal/GenericPlatformManagerImpl_POSIX.h>

// Include the non-inline definitions for the GenericPlatformManagerImpl<> template,
@@ -34,13 +34,13 @@

#include <system/SystemLayer.h>

#include <poll.h>
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <poll.h>
#include <sched.h>
#include <unistd.h>
#include <sys/select.h>
#include <unistd.h>

#define DEFAULT_MIN_SLEEP_PERIOD (60 * 60 * 24 * 30) // Month [sec]

@@ -55,6 +55,14 @@ template <class ImplClass>
CHIP_ERROR GenericPlatformManagerImpl_POSIX<ImplClass>::_InitChipStack(void)
{
CHIP_ERROR err = CHIP_NO_ERROR;
DBusError dbusError;

dbus_error_init(&dbusError);
mDBusConnection = UniqueDBusConnection(dbus_bus_get(DBUS_BUS_SYSTEM, &dbusError));
VerifyOrExit(mDBusConnection != nullptr, err = CHIP_ERROR_INTERNAL);
VerifyOrExit(dbus_bus_register(mDBusConnection.get(), &dbusError) == true, err = CHIP_ERROR_INTERNAL);
VerifyOrExit(
dbus_connection_set_watch_functions(mDBusConnection.get(), AddDBusWatch, RemoveDBusWatch, ToggleDBusWatch, this, NULL), err = CHIP_ERROR_INTERNAL);

mChipStackLock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;

@@ -63,6 +71,7 @@ CHIP_ERROR GenericPlatformManagerImpl_POSIX<ImplClass>::_InitChipStack(void)
SuccessOrExit(err);

exit:
dbus_error_free(&dbusError);
return err;
}

@@ -126,6 +135,7 @@ void GenericPlatformManagerImpl_POSIX<ImplClass>::SysUpdate()
mNextTimeout.tv_sec = DEFAULT_MIN_SLEEP_PERIOD;
mNextTimeout.tv_usec = 0;

UpdateDBusFdSet();
if (SystemLayer.State() == System::kLayerState_Initialized)
{
SystemLayer.PrepareSelect(mMaxFd, &mReadSet, &mWriteSet, &mErrorSet, mNextTimeout);
@@ -144,7 +154,6 @@ void GenericPlatformManagerImpl_POSIX<ImplClass>::SysProcess()
uint32_t nextTimeoutMs;

nextTimeoutMs = mNextTimeout.tv_sec * 1000 + mNextTimeout.tv_usec / 1000;
ChipLogDetail(DeviceLayer, "Timer: %ld", nextTimeoutMs);
_StartChipTimer(nextTimeoutMs);

Impl()->UnlockChipStack();
@@ -157,6 +166,8 @@ void GenericPlatformManagerImpl_POSIX<ImplClass>::SysProcess()
return;
}

ProcessDBus();

if (SystemLayer.State() == System::kLayerState_Initialized)
{
SystemLayer.HandleSelectResult(mMaxFd, &mReadSet, &mWriteSet, &mErrorSet);
@@ -209,6 +220,125 @@ exit:
return System::MapErrorPOSIX(err);
}

template <class ImplClass>
DBusConnection & GenericPlatformManagerImpl_POSIX<ImplClass>::GetSystemDBusConnection(void)
{
return *mDBusConnection.get();
}

template <class ImplClass>
dbus_bool_t GenericPlatformManagerImpl_POSIX<ImplClass>::AddDBusWatch(struct DBusWatch * aWatch, void * aContext)
{
static_cast<GenericPlatformManagerImpl_POSIX<ImplClass> *>(aContext)->mWatches[aWatch] = true;
return TRUE;
}

template <class ImplClass>
void GenericPlatformManagerImpl_POSIX<ImplClass>::RemoveDBusWatch(struct DBusWatch * aWatch, void * aContext)
{
static_cast<GenericPlatformManagerImpl_POSIX<ImplClass> *>(aContext)->mWatches.erase(aWatch);
}

template <class ImplClass>
void GenericPlatformManagerImpl_POSIX<ImplClass>::ToggleDBusWatch(struct DBusWatch * aWatch, void * aContext)
{
static_cast<GenericPlatformManagerImpl_POSIX<ImplClass> *>(aContext)->mWatches[aWatch] =
(dbus_watch_get_enabled(aWatch) ? true : false);
}

template <class ImplClass>
void GenericPlatformManagerImpl_POSIX<ImplClass>::UpdateDBusFdSet()
{
if (dbus_connection_get_dispatch_status(mDBusConnection.get()) == DBUS_DISPATCH_DATA_REMAINS)
{
mNextTimeout = { 0, 0 };
}

for (const auto & p : mWatches)
{
DBusWatch * watch = NULL;
unsigned int flags;
int fd;

if (!p.second)
{
continue;
}

watch = p.first;
flags = dbus_watch_get_flags(watch);
fd = dbus_watch_get_unix_fd(watch);

if (fd < 0)
{
continue;
}

if (flags & DBUS_WATCH_READABLE)
{
FD_SET(fd, &mReadSet);
}

if ((flags & DBUS_WATCH_WRITABLE) && dbus_connection_has_messages_to_send(mDBusConnection.get()))
{
FD_SET(fd, &mWriteSet);
}

FD_SET(fd, &mErrorSet);

if (fd > mMaxFd)
{
mMaxFd = fd;
}
}
}

template <class ImplClass>
void GenericPlatformManagerImpl_POSIX<ImplClass>::ProcessDBus()
{
for (const auto & p : mWatches)
{
DBusWatch * watch = NULL;
unsigned int flags;
int fd;

if (!p.second)
{
continue;
}

watch = p.first;
flags = dbus_watch_get_flags(watch);
fd = dbus_watch_get_unix_fd(watch);

if (fd < 0)
{
continue;
}

if ((flags & DBUS_WATCH_READABLE) && !FD_ISSET(fd, &mReadSet))
{
flags &= static_cast<unsigned int>(~DBUS_WATCH_READABLE);
}

if ((flags & DBUS_WATCH_WRITABLE) && !FD_ISSET(fd, &mWriteSet))
{
flags &= static_cast<unsigned int>(~DBUS_WATCH_WRITABLE);
}

if (FD_ISSET(fd, &mErrorSet))
{
flags |= DBUS_WATCH_ERROR;
}

dbus_watch_handle(watch, flags);
}

while (DBUS_DISPATCH_DATA_REMAINS == dbus_connection_get_dispatch_status(mDBusConnection.get()) &&
dbus_connection_read_write_dispatch(mDBusConnection.get(), 0))
;
}

} // namespace Internal
} // namespace DeviceLayer
} // namespace chip
405 changes: 405 additions & 0 deletions src/platform/Linux/ThreadStackManagerImpl.cpp

Large diffs are not rendered by default.

100 changes: 100 additions & 0 deletions src/platform/Linux/ThreadStackManagerImpl.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
/*
*
* Copyright (c) 2020 Project CHIP Authors
*
* 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.
*/

#ifndef CHIP_PLATFORM_LINUX_THREAD_STACK_MANAGER_IMPL_H
#define CHIP_PLATFORM_LINUX_THREAD_STACK_MANAGER_IMPL_H

#include <memory>

#include "platform/internal/CHIPDeviceLayerInternal.h"

#include "dbus/client/thread_api_dbus.hpp"
#include "platform/internal/DeviceNetworkInfo.h"

namespace chip {
namespace DeviceLayer {

class ThreadStackManagerImpl : public ThreadStackManager
{
public:
ThreadStackManagerImpl();

CHIP_ERROR _InitThreadStack();
CHIP_ERROR _ProcessThreadActivity();

CHIP_ERROR _StartThreadTask() { return CHIP_NO_ERROR; } // Intentionally left blank
CHIP_ERROR _LockThreadStack() { return CHIP_NO_ERROR; } // Intentionally left blank
CHIP_ERROR _TryLockThreadStack() { return CHIP_NO_ERROR; } // Intentionally left blank
CHIP_ERROR _UnlockThreadStack() { return CHIP_NO_ERROR; } // Intentionally left blank

bool _HaveRouteToAddress(const Inet::IPAddress & destAddr);

void _OnPlatformEvent(const ChipDeviceEvent * event);

CHIP_ERROR _GetThreadProvision(Internal::DeviceNetworkInfo & netInfo, bool includeCredentials);

CHIP_ERROR _SetThreadProvision(const Internal::DeviceNetworkInfo & netInfo);

void _ClearThreadProvision();

bool _IsThreadProvisioned();

bool _IsThreadEnabled();

bool _IsThreadAttached();

CHIP_ERROR _SetThreadEnabled(bool val);

ConnectivityManager::ThreadDeviceType _GetThreadDeviceType();

CHIP_ERROR _SetThreadDeviceType(ConnectivityManager::ThreadDeviceType deviceType);

void _GetThreadPollingConfig(ConnectivityManager::ThreadPollingConfig & pollingConfig);

CHIP_ERROR _SetThreadPollingConfig(const ConnectivityManager::ThreadPollingConfig & pollingConfig);

bool _HaveMeshConnectivity();

void _OnMessageLayerActivityChanged(bool messageLayerIsActive);

void _OnCHIPoBLEAdvertisingStart();

void _OnCHIPoBLEAdvertisingStop();

CHIP_ERROR _GetAndLogThreadStatsCounters();

CHIP_ERROR _GetAndLogThreadTopologyMinimal();

CHIP_ERROR _GetAndLogThreadTopologyFull();

CHIP_ERROR _GetPrimary802154MACAddress(uint8_t * buf);

~ThreadStackManagerImpl() = default;

private:
void _ThreadDevcieRoleChangedHandler(otbr::DBus::DeviceRole role);

std::unique_ptr<otbr::DBus::ThreadApiDBus> mThreadApi;
DBusConnection * mConnection;
Internal::DeviceNetworkInfo mNetworkInfo;
bool mAttached;
};

} // namespace DeviceLayer
} // namespace chip

#endif // CHIP_PLATFORM_LINUX_THREAD_STACK_MANAGER_IMPL_H
4 changes: 4 additions & 0 deletions src/platform/Linux/ThreadStackManagerTest.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
int main()
{
return 0;
}
188 changes: 188 additions & 0 deletions src/platform/Linux/otbr_client_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
/*
* Copyright (c) 2020, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/

#include <assert.h>
#include <stdio.h>
#include <string.h>

#include <memory>

#include <dbus/dbus.h>

#include "dbus/client/thread_api_dbus.hpp"
#include "dbus/common/constants.hpp"

using otbr::DBus::ActiveScanResult;
using otbr::DBus::ClientError;
using otbr::DBus::DeviceRole;
using otbr::DBus::ExternalRoute;
using otbr::DBus::Ip6Prefix;
using otbr::DBus::LinkModeConfig;
using otbr::DBus::OnMeshPrefix;
using otbr::DBus::ThreadApiDBus;

struct DBusConnectionDeleter
{
void operator()(DBusConnection *aConnection) { dbus_connection_unref(aConnection); }
};

using UniqueDBusConnection = std::unique_ptr<DBusConnection, DBusConnectionDeleter>;

static bool operator==(const otbr::DBus::Ip6Prefix &aLhs, const otbr::DBus::Ip6Prefix &aRhs)
{
bool prefixDataEquality = (aLhs.mPrefix.size() == aRhs.mPrefix.size()) &&
(memcmp(&aLhs.mPrefix[0], &aRhs.mPrefix[0], aLhs.mPrefix.size()) == 0);

return prefixDataEquality && aLhs.mLength == aRhs.mLength;
}

static void CheckExternalRoute(ThreadApiDBus *aApi, const Ip6Prefix &aPrefix)
{
ExternalRoute route;
std::vector<ExternalRoute> externalRouteTable;

route.mPrefix = aPrefix;
route.mStable = true;
route.mPreference = 0;

assert(aApi->AddExternalRoute(route) == OTBR_ERROR_NONE);
assert(aApi->GetExternalRoutes(externalRouteTable) == OTBR_ERROR_NONE);
assert(externalRouteTable.size() == 1);
assert(externalRouteTable[0].mPrefix == aPrefix);
assert(externalRouteTable[0].mPreference == 0);
assert(externalRouteTable[0].mStable);
assert(externalRouteTable[0].mNextHopIsThisDevice);
assert(aApi->RemoveExternalRoute(aPrefix) == OTBR_ERROR_NONE);
}

int main()
{
DBusError error;
UniqueDBusConnection connection;
std::unique_ptr<ThreadApiDBus> api;
uint64_t extpanid = 0xdead00beaf00cafe;

dbus_error_init(&error);
connection = UniqueDBusConnection(dbus_bus_get(DBUS_BUS_SYSTEM, &error));

VerifyOrExit(connection != nullptr);

VerifyOrExit(dbus_bus_register(connection.get(), &error) == true);

api = std::unique_ptr<ThreadApiDBus>(new ThreadApiDBus(connection.get()));

api->AddDeviceRoleHandler(
[](DeviceRole aRole) { printf("Device role changed to %d\n", static_cast<uint8_t>(aRole)); });

api->Scan([&api, extpanid](const std::vector<ActiveScanResult> &aResult) {
LinkModeConfig cfg = {true, true, false, true};

for (auto &&result : aResult)
{
printf("%s channel %d rssi %d\n", result.mNetworkName.c_str(), result.mChannel, result.mRssi);
}

api->SetLinkMode(cfg);
api->GetLinkMode(cfg);
printf("LinkMode %d %d %d %d\n", cfg.mRxOnWhenIdle, cfg.mSecureDataRequests, cfg.mDeviceType, cfg.mNetworkData);

cfg.mDeviceType = true;
api->SetLinkMode(cfg);

api->Attach("Test", 0x3456, extpanid, {}, {}, UINT32_MAX, [&api, extpanid](ClientError aError) {
printf("Attach result %d\n", static_cast<int>(aError));
uint64_t extpanidCheck;
if (aError == OTBR_ERROR_NONE)
{
std::string name;
uint64_t extAddress = 0;
uint16_t rloc16 = 0xffff;
uint8_t routerId;
std::vector<uint8_t> networkData;
std::vector<uint8_t> stableNetworkData;
otbr::DBus::LeaderData leaderData;
uint8_t leaderWeight;
int8_t rssi;
int8_t txPower;
std::vector<otbr::DBus::ChildInfo> childTable;
std::vector<otbr::DBus::NeighborInfo> neighborTable;
uint32_t partitionId;
Ip6Prefix prefix;
OnMeshPrefix onMeshPrefix = {};

prefix.mPrefix = {0xfd, 0xcd, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06};
prefix.mLength = 64;

onMeshPrefix.mPrefix = prefix;
onMeshPrefix.mPreference = 0;
onMeshPrefix.mStable = true;

assert(api->GetNetworkName(name) == OTBR_ERROR_NONE);
assert(api->GetExtPanId(extpanidCheck) == OTBR_ERROR_NONE);
assert(api->GetRloc16(rloc16) == OTBR_ERROR_NONE);
assert(api->GetExtendedAddress(extAddress) == OTBR_ERROR_NONE);
assert(api->GetRouterId(routerId) == OTBR_ERROR_NONE);
assert(api->GetLeaderData(leaderData) == OTBR_ERROR_NONE);
assert(api->GetNetworkData(networkData) == OTBR_ERROR_NONE);
assert(api->GetStableNetworkData(stableNetworkData) == OTBR_ERROR_NONE);
assert(api->GetLocalLeaderWeight(leaderWeight) == OTBR_ERROR_NONE);
assert(api->GetChildTable(childTable) == OTBR_ERROR_NONE);
assert(api->GetNeighborTable(neighborTable) == OTBR_ERROR_NONE);
assert(api->GetPartitionId(partitionId) == OTBR_ERROR_NONE);
assert(api->GetInstantRssi(rssi) == OTBR_ERROR_NONE);
assert(api->GetRadioTxPower(txPower) == OTBR_ERROR_NONE);
CheckExternalRoute(api.get(), prefix);
assert(api->AddOnMeshPrefix(onMeshPrefix) == OTBR_ERROR_NONE);
assert(api->RemoveOnMeshPrefix(onMeshPrefix.mPrefix) == OTBR_ERROR_NONE);
api->FactoryReset(nullptr);
assert(api->GetNetworkName(name) == OTBR_ERROR_NONE);
assert(rloc16 != 0xffff);
assert(extAddress != 0);
assert(routerId == leaderData.mLeaderRouterId);
assert(!networkData.empty());
assert(childTable.empty());
assert(neighborTable.empty());
}
if (aError != OTBR_ERROR_NONE || extpanidCheck != extpanid)
{
exit(-1);
}
api->Attach("Test", 0x3456, extpanid, {}, {}, UINT32_MAX,
[](ClientError aErr) { exit(static_cast<uint8_t>(aErr)); });
});
});

while (true)
{
dbus_connection_read_write_dispatch(connection.get(), 0);
}

exit:
dbus_error_free(&error);
return 0;
};
36 changes: 36 additions & 0 deletions src/platform/Makefile.am
Original file line number Diff line number Diff line change
@@ -130,6 +130,13 @@ libDeviceLayer_a_SOURCES += \
Linux/PosixConfig.cpp \
Linux/PlatformManagerImpl.cpp \
Linux/SystemTimeSupport.cpp \
Linux/ThreadStackManagerImpl.cpp \
$(NULL)

libDeviceLayer_a_CPPFLAGS += \
-I$(top_srcdir)/third_party/ot-br-posix/repo/include \
-I$(top_srcdir)/third_party/ot-br-posix/repo/src \
$(DBUS_CFLAGS) \
$(NULL)

endif # CHIP_DEVICE_LAYER_TARGET_LINUX
@@ -187,4 +194,33 @@ endif # CHIP_DEVICE_LAYER_TARGET_ESP32

endif # CONFIG_DEVICE_LAYER

bin_PROGRAMS = otbr_client_test

otbr_client_test_SOURCES = Linux/ThreadStackManagerTest.cpp

otbr_client_test_CPPFLAGS = \
-I$(top_srcdir)/src/include \
-I$(top_srcdir)/src/lib \
-I$(top_srcdir)/src/system \
-I$(top_srcdir)/src \
-I$(top_srcdir)/third_party/ot-br-posix/repo/include \
-I$(top_srcdir)/third_party/ot-br-posix/repo/src \
$(DBUS_CFLAGS) \
$(NLASSERT_CPPFLAGS) \
$(NLIO_CPPFLAGS) \
$(LWIP_CPPFLAGS) \
$(SOCKETS_CPPFLAGS) \
$(NULL)

otbr_client_test_LDADD = \
$(top_builddir)/src/platform/libDeviceLayer.a \
$(top_builddir)/src/inet/libInetLayer.a \
$(top_builddir)/src/system/libSystemLayer.a \
$(top_builddir)/src/lib/support/libSupportLayer.a \
$(NLFAULTINJECTION_LDFLAGS) $(NLFAULTINJECTION_LIBS)\
$(top_builddir)/third_party/ot-br-posix/libotbrclient.a \
$(DBUS_LIBS) \
-lpthread \
$(NULL)

include $(abs_top_nlbuild_autotools_dir)/automake/post.am
20 changes: 20 additions & 0 deletions src/platform/tests/Makefile.am
Original file line number Diff line number Diff line change
@@ -43,6 +43,7 @@ lib_LIBRARIES = \
libPlatformTests_a_SOURCES = \
TestPlatformMgr.cpp \
TestPlatformTime.cpp \
TestThreadStackMgr.cpp \
$(NULL)

libPlatformTests_adir = $(includedir)/platform
@@ -66,13 +67,28 @@ AM_CPPFLAGS = \
$(NLUNIT_TEST_CPPFLAGS) \
$(NULL)

if CHIP_DEVICE_LAYER_TARGET_LINUX
AM_CPPFLAGS += \
$(DBUS_CFLAGS) \
-I$(top_srcdir)/third_party/ot-br-posix/repo/include \
-I$(top_srcdir)/third_party/ot-br-posix/repo/src \
$(NULL)
endif

CHIP_LDADD = \
$(top_builddir)/src/platform/libDeviceLayer.a \
$(top_builddir)/src/inet/libInetLayer.a \
$(top_builddir)/src/system/libSystemLayer.a \
$(top_builddir)/src/lib/support/libSupportLayer.a \
$(NULL)

if CHIP_DEVICE_LAYER_TARGET_LINUX
CHIP_LDADD += \
$(DBUS_LIBS) \
$(top_builddir)/third_party/ot-br-posix/libotbrclient.a \
$(NULL)
endif

COMMON_LDADD = \
libPlatformTests.a \
$(CHIP_LDADD) \
@@ -88,6 +104,7 @@ COMMON_LDADD = \
check_PROGRAMS = \
TestPlatformTime \
TestPlatformMgr \
TestThreadStackMgr \
$(NULL)

# Test applications and scripts that should be built and run when the
@@ -111,6 +128,9 @@ TestPlatformTime_SOURCES = TestPlatformTimeDriver.cpp
TestPlatformMgr_LDADD = $(COMMON_LDADD)
TestPlatformMgr_SOURCES = TestPlatformMgrDriver.cpp

TestThreadStackMgr_LDADD = $(COMMON_LDADD)
TestThreadStackMgr_SOURCES = TestThreadStackMgrDriver.cpp

#
# Foreign make dependencies
#
32 changes: 32 additions & 0 deletions src/platform/tests/TestThreadStackMgr.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#include "platform/internal/CHIPDeviceLayerInternal.h"

#include "platform/ThreadStackManager.h"
#include "platform/PlatformManager.h"

int TestThreadStackManager(void)
{
chip::DeviceLayer::ThreadStackManagerImpl impl;
chip::DeviceLayer::Internal::DeviceNetworkInfo info;
uint16_t masterKey[16] = { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff };

strncpy(info.ThreadNetworkName, "CHIP-TEST", sizeof(info.ThreadNetworkName));
info.ThreadChannel = UINT8_MAX;
info.ThreadPANId = 0x3455;
info.FieldPresent.ThreadExtendedPANId = false;
info.FieldPresent.ThreadMeshPrefix = false;
info.FieldPresent.ThreadPSKc = false;
memcpy(&info.ThreadNetworkKey, &masterKey, sizeof(masterKey));

chip::DeviceLayer::PlatformMgrImpl().InitChipStack();

impl.InitThreadStack();
impl.StartThreadTask();
impl._SetThreadProvision(info);
impl._SetThreadEnabled(true);

printf("Start Thread task done\n");

//chip::DeviceLayer::PlatformMgrImpl().RunEventLoop();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we remove commented out code?

is there any way for this test to fail besides a SIGSEGV? I see it initializing a lot of things but never check any error codes. Can we make it a unit test instead or provide some instructions on how run the test?


return 0;
}
29 changes: 29 additions & 0 deletions src/platform/tests/TestThreadStackMgr.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
*
* Copyright (c) 2020 Project CHIP Authors
*
* 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
* This file declares test entry point for CHIP Platform Manager code unit tests.
*
*/

#ifndef CHIP_TEST_THREAD_STACK_MGR_H
#define CHIP_TEST_THREAD_STACK_MGR_H

int TestThreadStackManager(void);

#endif // CHIP_TEST_THREAD_STACK_MGR_H
6 changes: 6 additions & 0 deletions src/platform/tests/TestThreadStackMgrDriver.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#include "TestThreadStackMgr.h"

int main()
{
TestThreadStackManager();
}
4 changes: 3 additions & 1 deletion third_party/Makefile.am
Original file line number Diff line number Diff line change
@@ -33,6 +33,7 @@ EXTRA_DIST = \
DIST_SUBDIRS = \
lwip \
mbedtls \
ot-br-posix \
$(NULL)

# <any of the third-party packages listed in repos.conf>_SUBDIRS are
@@ -42,7 +43,7 @@ DIST_SUBDIRS = \
# of the 'distclean' target. Consequently, we conditionally include
# them in DIST_SUBDIRS on invocation of 'distclean-recursive'

distclean-recursive: DIST_SUBDIRS += $(NLASSERT_SUBDIRS) $(NLFAULTINJECTION_SUBDIRS) $(NLIO_SUBDIRS) $(NLUNIT_TEST_SUBDIRS) $(MBEDTLS_SUBDIRS)
distclean-recursive: DIST_SUBDIRS += $(NLASSERT_SUBDIRS) $(NLFAULTINJECTION_SUBDIRS) $(NLIO_SUBDIRS) $(NLUNIT_TEST_SUBDIRS) $(MBEDTLS_SUBDIRS) $(OTBRCLIENT_SUBDIRS)

# Always build (e.g. for 'make all') these subdirectories.
#
@@ -56,6 +57,7 @@ SUBDIRS = \
$(NLIO_SUBDIRS) \
$(NLUNIT_TEST_SUBDIRS) \
$(MBEDTLS_SUBDIRS) \
$(OTBRCLIENT_SUBDIRS) \
$(NULL)

include $(abs_top_nlbuild_autotools_dir)/automake/post.am
47 changes: 47 additions & 0 deletions third_party/ot-br-posix/Makefile.am
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#
# Copyright (c) 2020 Project CHIP Authors
#
# 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.


#
# Description:
# This file is the GNU automake template for the CHIP in-package,
# otbr clientlibrary.
#
#

include $(abs_top_nlbuild_autotools_dir)/automake/pre.am

if CHIP_WITH_OTBRCLIENT_INTERNAL

lib_LIBRARIES = libotbrclient.a

nodist_libotbrclient_a_SOURCES = \
repo/src/dbus/client/client_error.cpp \
repo/src/dbus/client/thread_api_dbus.cpp \
repo/src/dbus/common/error.cpp \
repo/src/dbus/common/dbus_message_helper.cpp \
repo/src/dbus/common/dbus_message_helper_openthread.cpp \
$(NULL)

libotbrclient_a_CPPFLAGS = \
-I$(top_srcdir)/third_party/ot-br-posix/repo/include \
-I$(top_srcdir)/third_party/ot-br-posix/repo/src \
$(OTBRCLIENT_CPPFLAGS) \
$(DBUS_CFLAGS) \
$(NULL)

endif # CHIP_WITH_OTBRCLIENT_INTERNAL

include $(abs_top_nlbuild_autotools_dir)/automake/post.am