From 523346ced3ff7e97720ec86a2754248d75c4406c Mon Sep 17 00:00:00 2001 From: kangping Date: Wed, 3 Feb 2021 22:00:57 +0800 Subject: [PATCH] [example] add Minimum Thread Commissioner example --- example/BUILDING.md | 32 +++++ example/CMakeLists.txt | 41 +++++++ example/README.md | 83 +++++++++++++ example/mini_commissioner.cpp | 218 ++++++++++++++++++++++++++++++++++ 4 files changed, 374 insertions(+) create mode 100644 example/BUILDING.md create mode 100644 example/CMakeLists.txt create mode 100644 example/README.md create mode 100644 example/mini_commissioner.cpp diff --git a/example/BUILDING.md b/example/BUILDING.md new file mode 100644 index 000000000..c0b287347 --- /dev/null +++ b/example/BUILDING.md @@ -0,0 +1,32 @@ +# Build Minimum Thread Commissioner + +## CMake Build + +```shell +cd ~/ot-commissioner/example +mkdir -p build && cd build +cmake -GNinja .. +ninja +``` + +A `mini_commissioner` binary will be generated in `build/`. + +## Standalone build + +Build and install the OT Commissioner library: + +```c++ +cd ~/ot-commissioner +mkdir -p build && cd build +cmake -GNinja .. +sudo ninja install +``` + +Build the `mini_commissioner` app: + +```c++ +cd ~/ot-commissioner/example +clang++ -std=c++11 -Wall -g mini_commissioner.cpp -o mini_commissioner -lcommissioner +``` + +The `mini_commissioner` binary will be generated in current directory. diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt new file mode 100644 index 000000000..45b348086 --- /dev/null +++ b/example/CMakeLists.txt @@ -0,0 +1,41 @@ +# +# Copyright (c) 2021, The OpenThread Commissioner 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. +# + +project(mini-commissioner VERSION 0.0.1) + +add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/.. + ${CMAKE_CURRENT_BINARY_DIR}/commissioner +) + +add_executable(mini_commissioner mini_commissioner.cpp) + +target_link_libraries(mini_commissioner PRIVATE commissioner) + +install(TARGETS mini_commissioner + RUNTIME DESTINATION bin +) diff --git a/example/README.md b/example/README.md new file mode 100644 index 000000000..e2c3caaa8 --- /dev/null +++ b/example/README.md @@ -0,0 +1,83 @@ +# Minimum Thread Commissioner + +This directory includes an example of building a minimum Thread Commissioner with the OT Commissioner library. The minimum Thread Commissioner petitions to given Border Router, enables MeshCoP for all joiners and commissions joiners. + +## Build + +See [BUILDING.md](./BUILDING.md) for building this mini Commissioner program. You can find details about the Border Router (`ot-daemon`) and simulation devices in this [codelab](https://openthread.io/codelabs/openthread-simulation-posix). + +## Run the Commissioner + +### Start the BR (ot-daemon) + +See the [codelab](https://openthread.io/codelabs/openthread-simulation-posix). + +### Start the Mini Commissioner + +After a successful build, we should get a `mini_commissioner` binary which can be started with four arguments: + +```shell +./mini_commissioner ::1 49191 00112233445566778899aabbccddeeff ABCDEF +``` + +You can get the usage by starting `mini_commissioner` with no arguments: + +```shell +./minim_commissioner +usage: + mini_commissioner +``` + +> Note: the WiFi/ethernet interface address of the BR should be used but not the Thread interface address. + +If everything go smooth, we will get outputs like below: + +```shell +./mini_commissioner ::1 49191 ca117352886a861cce8a91021e65dd1c ABCDEF +=================================================== +[Border Router address] : ::1 +[Border Router port] : 49191 +[PSKc] : ca117352886a861cce8a91021e65dd1c +[PSKd] : ABCDEF +=================================================== + +=================================================== +type CRTL + C to quit! +=================================================== + +petitioning to [::1]:49191 +the commissioner is active: true +enabling MeshCoP for all joiners +waiting for joiners +``` + +> Note: you are free to quit at any time with `CTRL+C`. + +### Start the joiner + +See the [codelab](https://openthread.io/codelabs/openthread-simulation-posix). + +if everything go smooth, we will get output like below for two times of joining: + +```shell +joiner "5ab1f2745b625c90" is requesting join the Thread network +joiner "5ab1f2745b625c90" is connected: OK +joiner "5ab1f2745b625c90" is commissioned +[Vendor Name] : OPENTHREAD +[Vendor Model] : NRF52840 +[Vendor SW Version] : 20191113-01632-g +[Vendor Stack Version] : f4ce36000010 +[Provisioning URL] : +[Vendor Data] : + +joiner "5ab1f2745b625c90" is requesting join the Thread network +joiner "5ab1f2745b625c90" is connected: OK +joiner "5ab1f2745b625c90" is commissioned +[Vendor Name] : OPENTHREAD +[Vendor Model] : NRF52840 +[Vendor SW Version] : 20191113-01632-g +[Vendor Stack Version] : f4ce36000010 +[Provisioning URL] : +[Vendor Data] : + +``` diff --git a/example/mini_commissioner.cpp b/example/mini_commissioner.cpp new file mode 100644 index 000000000..79c9dca0a --- /dev/null +++ b/example/mini_commissioner.cpp @@ -0,0 +1,218 @@ +/* + * Copyright (c) 2021, The OpenThread Commissioner 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. + */ + +/** + * @file + * The file implements the minimum Thread Commissioner example app. + */ + +#include +#include + +#include +#include +#include + +#include + +#include + +using namespace ot::commissioner; + +static std::string ToHexString(const ByteArray &aBytes) +{ + std::string str; + + for (uint8_t byte : aBytes) + { + char buf[3]; + + sprintf(buf, "%02x", byte); + str.append(buf); + } + + return str; +} + +static ByteArray FromHexString(const std::string &aHex) +{ + assert(aHex.size() % 2 == 0); + + ByteArray bytes; + + for (size_t i = 0; i < aHex.size(); i += 2) + { + assert(isxdigit(aHex[i])); + assert(isxdigit(aHex[i + 1])); + + uint8_t x = isdigit(aHex[i]) ? (aHex[i] - '0') : (tolower(aHex[i]) - 'a' + 10); + uint8_t y = isdigit(aHex[i + 1]) ? (aHex[i + 1] - '0') : (tolower(aHex[i + 1]) - 'a' + 10); + + bytes.push_back((x << 4) | y); + } + return bytes; +} + +class MyCommissionerHandler : public CommissionerHandler +{ +public: + MyCommissionerHandler(const std::string &aPskd) + : mPskd(aPskd) + { + } + + std::string OnJoinerRequest(const ByteArray &aJoinerId) override + { + auto joinerId = ToHexString(aJoinerId); + + printf("\n"); + printf("joiner \"%s\" is requesting join the Thread network\n", joinerId.c_str()); + + return mPskd; + } + + void OnJoinerConnected(const ByteArray &aJoinerId, Error aError) override + { + auto joinerId = ToHexString(aJoinerId); + + printf("joiner \"%s\" is connected: %s\n", joinerId.c_str(), aError.ToString().c_str()); + } + + bool OnJoinerFinalize(const ByteArray & aJoinerId, + const std::string &aVendorName, + const std::string &aVendorModel, + const std::string &aVendorSwVersion, + const ByteArray & aVendorStackVersion, + const std::string &aProvisioningUrl, + const ByteArray & aVendorData) override + { + printf("joiner \"%s\" is commissioned\n", ToHexString(aJoinerId).c_str()); + printf("[Vendor Name] : %s\n", aVendorName.c_str()); + printf("[Vendor Model] : %s\n", aVendorModel.c_str()); + printf("[Vendor SW Version] : %s\n", aVendorSwVersion.c_str()); + printf("[Vendor Stack Version] : %s\n", ToHexString(aVendorStackVersion).c_str()); + printf("[Provisioning URL] : %s\n", aProvisioningUrl.c_str()); + printf("[Vendor Data] : %s\n", ToHexString(aVendorData).c_str()); + + return true; + } + +private: + std::string mPskd; +}; + +std::shared_ptr commissioner; + +void SignalHandler(int signal) +{ + if (commissioner != nullptr) + { + printf("\nResigning the commissioner\n"); + commissioner->Resign(); + } + + exit(0); +} + +int main(int argc, const char *argv[]) +{ + if (argc != 5) + { + printf("usage:\n"); + printf(" mini_commissioner \n"); + return -1; + } + + std::string brAddr = argv[1]; + uint16_t brPort = std::stoul(argv[2]); + ByteArray pskc = FromHexString(argv[3]); + std::string pskd = argv[4]; + + printf("===================================================\n"); + printf("[Border Router address] : %s\n", brAddr.c_str()); + printf("[Border Router port] : %hu\n", brPort); + printf("[PSKc] : %s\n", ToHexString(pskc).c_str()); + printf("[PSKd] : %s\n", pskd.c_str()); + printf("===================================================\n\n"); + + MyCommissionerHandler myHandler{pskd}; + commissioner = Commissioner::Create(myHandler); + + signal(SIGINT, SignalHandler); + printf("===================================================\n"); + printf("type CRTL + C to quit!\n"); + printf("===================================================\n\n"); + + Config config; + config.mEnableCcm = false; + config.mPSKc = pskc; + + Error error; + + if ((error = commissioner->Init(config)) != ErrorCode::kNone) + { + printf("failed to initialize the commissioner: %s\n", error.ToString().c_str()); + return -1; + } + + std::string existingCommissionerId; + + printf("petitioning to [%s]:%hu\n", brAddr.c_str(), brPort); + error = commissioner->Petition(existingCommissionerId, brAddr, brPort); + if (error != ErrorCode::kNone) + { + printf("failed to petition to BR at [%s]:%hu: %s\n", brAddr.c_str(), brPort, error.ToString().c_str()); + return -1; + } + + // Check if we are active now. + printf("the commissioner is active: %s\n", commissioner->IsActive() ? "true" : "false"); + assert(commissioner->IsActive()); + + CommissionerDataset dataset; + + printf("enabling MeshCoP for all joiners\n"); + dataset.mPresentFlags |= CommissionerDataset::kSteeringDataBit; + dataset.mSteeringData = {0xFF}; // Set the steeering data to all-ones to allow all joiners. + error = commissioner->SetCommissionerDataset(dataset); + if (error != ErrorCode::kNone) + { + printf("failed to enable MeshCop for all joiners: %s\n", error.ToString().c_str()); + return -1; + } + + printf("waiting for joiners\n"); + while (true) + { + sleep(1); + } + + commissioner->Resign().IgnoreError(); + + return 0; +}