From 2b85b54ed2a586eeb20b8d0a1aa6296aa8cee0e9 Mon Sep 17 00:00:00 2001 From: Kamil Kasperczyk <66371704+kkasperczyk-no@users.noreply.github.com> Date: Thu, 8 Oct 2020 20:26:30 +0200 Subject: [PATCH] [example/nrfconnect] Added support for sending UDP broadcast messages. (#3110) * [example/nrfconnect] Added support for sending UDP broadcast messages. nrfconnect platform doesn't support sending UDP broadcast messages periodically by PublishService as other platforms do (e.h. nrf5) * Added Service component with PublishService implementation to support sending UDP broadcast messages. * Restyled by clang-format Co-authored-by: Restyled.io --- .../lighting-app/nrfconnect/CMakeLists.txt | 3 +- .../lighting-app/nrfconnect/main/AppTask.cpp | 14 ++- examples/lock-app/nrfconnect/CMakeLists.txt | 3 +- examples/lock-app/nrfconnect/main/AppTask.cpp | 15 ++- examples/platform/nrfconnect/app/Service.cpp | 94 +++++++++++++++++++ .../platform/nrfconnect/app/include/Service.h | 23 +++++ 6 files changed, 148 insertions(+), 4 deletions(-) create mode 100644 examples/platform/nrfconnect/app/Service.cpp create mode 100644 examples/platform/nrfconnect/app/include/Service.h diff --git a/examples/lighting-app/nrfconnect/CMakeLists.txt b/examples/lighting-app/nrfconnect/CMakeLists.txt index cbc3cb12c685d6..3132d966ee75d4 100644 --- a/examples/lighting-app/nrfconnect/CMakeLists.txt +++ b/examples/lighting-app/nrfconnect/CMakeLists.txt @@ -26,7 +26,7 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CHIP_ROOT}/config/nrfconnect/) include(nrfconnect-app) project(chip-nrf52840-lighting-example) -target_include_directories(app PRIVATE main/include ${LIGHTING_COMMON} ${NRFCONNECT_COMMON}/util/include ${CHIP_APP_SERVER}/include) +target_include_directories(app PRIVATE main/include ${LIGHTING_COMMON} ${NRFCONNECT_COMMON}/util/include ${NRFCONNECT_COMMON}/app/include ${CHIP_APP_SERVER}/include) target_sources(app PRIVATE main/AppTask.cpp main/LightingManager.cpp @@ -37,6 +37,7 @@ target_sources(app PRIVATE ${LIGHTING_COMMON}/gen/znet-bookkeeping.c ${NRFCONNECT_COMMON}/util/LEDWidget.cpp ${NRFCONNECT_COMMON}/util/ThreadUtil.cpp + ${NRFCONNECT_COMMON}/app/Service.cpp ${CHIP_APP_SERVER}/DataModelHandler.cpp ${CHIP_APP_SERVER}/Server.cpp ${CHIP_APP_SERVER}/QRCodeUtil.cpp diff --git a/examples/lighting-app/nrfconnect/main/AppTask.cpp b/examples/lighting-app/nrfconnect/main/AppTask.cpp index ed618140bf52f1..a159bb867d8771 100644 --- a/examples/lighting-app/nrfconnect/main/AppTask.cpp +++ b/examples/lighting-app/nrfconnect/main/AppTask.cpp @@ -24,6 +24,7 @@ #include "LightingManager.h" #include "QRCodeUtil.h" #include "Server.h" +#include "Service.h" #include "ThreadUtil.h" #include @@ -47,6 +48,7 @@ constexpr int kAppEventQueueSize = 10; constexpr int kExampleVendorID = 0xabcd; constexpr uint8_t kButtonPushEvent = 1; constexpr uint8_t kButtonReleaseEvent = 0; +constexpr uint32_t kPublishServicePeriodUs = 5000000; K_MSGQ_DEFINE(sAppEventQueue, sizeof(AppEvent), kAppEventQueueSize, alignof(AppEvent)); k_timer sFunctionTimer; @@ -104,7 +106,8 @@ int AppTask::Init() int AppTask::StartApp() { - int ret = Init(); + int ret = Init(); + uint64_t mLastPublishServiceTimeUS = 0; if (ret) { @@ -179,6 +182,15 @@ int AppTask::StartApp() sStatusLED.Animate(); sUnusedLED.Animate(); sUnusedLED_1.Animate(); + + uint64_t nowUS = chip::System::Platform::Layer::GetClock_Monotonic(); + uint64_t nextChangeTimeUS = mLastPublishServiceTimeUS + kPublishServicePeriodUs; + + if (nowUS > nextChangeTimeUS) + { + PublishService(); + mLastPublishServiceTimeUS = nowUS; + } } } diff --git a/examples/lock-app/nrfconnect/CMakeLists.txt b/examples/lock-app/nrfconnect/CMakeLists.txt index b3d462673728b9..2c5198b9ad03c5 100644 --- a/examples/lock-app/nrfconnect/CMakeLists.txt +++ b/examples/lock-app/nrfconnect/CMakeLists.txt @@ -26,7 +26,7 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CHIP_ROOT}/config/nrfconnect/) include(nrfconnect-app) project(chip-nrf52840-lock-example) -target_include_directories(app PRIVATE main/include ${LOCK_COMMON} ${NRFCONNECT_COMMON}/util/include ${CHIP_APP_SERVER}/include) +target_include_directories(app PRIVATE main/include ${LOCK_COMMON} ${NRFCONNECT_COMMON}/util/include ${NRFCONNECT_COMMON}/app/include ${CHIP_APP_SERVER}/include) target_sources(app PRIVATE main/AppTask.cpp main/BoltLockManager.cpp @@ -37,6 +37,7 @@ target_sources(app PRIVATE ${LOCK_COMMON}/gen/znet-bookkeeping.c ${NRFCONNECT_COMMON}/util/LEDWidget.cpp ${NRFCONNECT_COMMON}/util/ThreadUtil.cpp + ${NRFCONNECT_COMMON}/app/Service.cpp ${CHIP_APP_SERVER}/DataModelHandler.cpp ${CHIP_APP_SERVER}/Server.cpp ${CHIP_APP_SERVER}/QRCodeUtil.cpp diff --git a/examples/lock-app/nrfconnect/main/AppTask.cpp b/examples/lock-app/nrfconnect/main/AppTask.cpp index 7bd951e403c6f8..4f69b78908268a 100644 --- a/examples/lock-app/nrfconnect/main/AppTask.cpp +++ b/examples/lock-app/nrfconnect/main/AppTask.cpp @@ -22,6 +22,7 @@ #include "LEDWidget.h" #include "QRCodeUtil.h" #include "Server.h" +#include "Service.h" #include "ThreadUtil.h" #include @@ -41,6 +42,8 @@ LOG_MODULE_DECLARE(app); K_MSGQ_DEFINE(sAppEventQueue, sizeof(AppEvent), APP_EVENT_QUEUE_SIZE, alignof(AppEvent)); +constexpr uint32_t kPublishServicePeriodUs = 5000000; + static LEDWidget sStatusLED; static LEDWidget sLockLED; static LEDWidget sUnusedLED; @@ -95,7 +98,8 @@ int AppTask::Init() int AppTask::StartApp() { - int ret = Init(); + int ret = Init(); + uint64_t mLastPublishServiceTimeUS = 0; if (ret) { @@ -171,6 +175,15 @@ int AppTask::StartApp() sLockLED.Animate(); sUnusedLED.Animate(); sUnusedLED_1.Animate(); + + uint64_t nowUS = chip::System::Platform::Layer::GetClock_Monotonic(); + uint64_t nextChangeTimeUS = mLastPublishServiceTimeUS + kPublishServicePeriodUs; + + if (nowUS > nextChangeTimeUS) + { + PublishService(); + mLastPublishServiceTimeUS = nowUS; + } } } diff --git a/examples/platform/nrfconnect/app/Service.cpp b/examples/platform/nrfconnect/app/Service.cpp new file mode 100644 index 00000000000000..c548f94da5f62f --- /dev/null +++ b/examples/platform/nrfconnect/app/Service.cpp @@ -0,0 +1,94 @@ +/* + * + * 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 implements the service publishing code for example usage. + */ + +#include "Service.h" + +#include + +#include +#include +#include + +#if CHIP_ENABLE_OPENTHREAD +#include +#include +#include +#include +#include +#endif + +LOG_MODULE_DECLARE(serv); + +// Transport Callbacks +namespace { + +char deviceName[CONFIG_BT_DEVICE_NAME_MAX]; +constexpr uint16_t kUDPBroadcastPort = 23367; + +} // namespace + +void PublishService() +{ + chip::Inet::IPAddress addr; + if (!chip::DeviceLayer::ConnectivityMgrImpl().IsThreadAttached()) + { + return; + } + chip::DeviceLayer::ThreadStackMgrImpl().LockThreadStack(); + otError error = OT_ERROR_NONE; + otMessageInfo messageInfo; + otUdpSocket mSocket; + otMessage * message = nullptr; + + memset(&mSocket, 0, sizeof(mSocket)); + memset(&messageInfo, 0, sizeof(messageInfo)); + + // Use mesh local EID by default, if we have GUA, use that IP address. + memcpy(&messageInfo.mSockAddr, otThreadGetMeshLocalEid(chip::DeviceLayer::ThreadStackMgrImpl().OTInstance()), + sizeof(messageInfo.mSockAddr)); + + // Select a address to send + const otNetifAddress * otAddrs = otIp6GetUnicastAddresses(chip::DeviceLayer::ThreadStackMgrImpl().OTInstance()); + for (const otNetifAddress * otAddr = otAddrs; otAddr != NULL; otAddr = otAddr->mNext) + { + addr = chip::DeviceLayer::Internal::ToIPAddress(otAddr->mAddress); + if (otAddr->mValid && addr.IsIPv6GlobalUnicast()) + { + memcpy(&messageInfo.mSockAddr, &(otAddr->mAddress), sizeof(otAddr->mAddress)); + break; + } + } + + message = otUdpNewMessage(chip::DeviceLayer::ThreadStackMgrImpl().OTInstance(), nullptr); + otIp6AddressFromString("ff03::1", &messageInfo.mPeerAddr); + messageInfo.mPeerPort = kUDPBroadcastPort; + otMessageAppend(message, deviceName, static_cast(strlen(deviceName))); + + error = otUdpSend(chip::DeviceLayer::ThreadStackMgrImpl().OTInstance(), &mSocket, message, &messageInfo); + + if (error != OT_ERROR_NONE && message != nullptr) + { + otMessageFree(message); + LOG_INF("Failed to otUdpSend: %d", error); + } + chip::DeviceLayer::ThreadStackMgrImpl().UnlockThreadStack(); +} diff --git a/examples/platform/nrfconnect/app/include/Service.h b/examples/platform/nrfconnect/app/include/Service.h new file mode 100644 index 00000000000000..19fcdb8fb29c48 --- /dev/null +++ b/examples/platform/nrfconnect/app/include/Service.h @@ -0,0 +1,23 @@ +/* + * + * 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 NRFCONNECT_COMMON_SERVICE_H +#define NRFCONNECT_COMMON_SERVICE_H + +void PublishService(); + +#endif // NRFCONNECT_COMMON_SERVICE_H