diff --git a/.github/workflows/examples-telink.yaml b/.github/workflows/examples-telink.yaml index 1377b4c0ebfee4..547e6bf7bd8ad0 100644 --- a/.github/workflows/examples-telink.yaml +++ b/.github/workflows/examples-telink.yaml @@ -36,7 +36,7 @@ jobs: if: github.actor != 'restyled-io[bot]' container: - image: connectedhomeip/chip-build-telink:0.6.47 + image: connectedhomeip/chip-build-telink:0.6.53 volumes: - "/tmp/bloat_reports:/tmp/bloat_reports" diff --git a/config/telink/app/zephyr.conf b/config/telink/app/zephyr.conf index ddef211ffa0c86..ebf6c3abe5edfc 100644 --- a/config/telink/app/zephyr.conf +++ b/config/telink/app/zephyr.conf @@ -129,3 +129,6 @@ CONFIG_SHELL_BACKEND_SERIAL_RX_RING_BUFFER_SIZE=255 # Legacy CONFIG_LEGACY_INCLUDE_PATH=y + +# BLE MAC address +CONFIG_B91_BLE_CTRL_MAC_FLASH_ADDR=0x1FE000 diff --git a/config/telink/chip-module/Kconfig b/config/telink/chip-module/Kconfig index f047a9cace7526..7760b734632648 100644 --- a/config/telink/chip-module/Kconfig +++ b/config/telink/chip-module/Kconfig @@ -168,3 +168,10 @@ config CHIP_ENABLE_PM_DURING_BLE default y help Enable PM during BLE operation. + +config CHIP_OPENTHREAD_TX_POWER + int "OpenThread Transmission power" + range -30 9 + default 0 + help + OpenThread Transmission power in dBm. diff --git a/examples/lighting-app/telink/prj.conf b/examples/lighting-app/telink/prj.conf index 28f890f98bd9eb..8cf739a92b55ef 100644 --- a/examples/lighting-app/telink/prj.conf +++ b/examples/lighting-app/telink/prj.conf @@ -77,4 +77,4 @@ CONFIG_CHIP_ENABLE_PM_DURING_BLE=n # Custom RF power values CONFIG_B91_BLE_CTRL_RF_POWER_P9P11DBM=y -CONFIG_IEEE802154_B91_CUSTOM_RF_POWER=9 +CONFIG_CHIP_OPENTHREAD_TX_POWER=9 diff --git a/examples/temperature-measurement-app/telink/prj.conf b/examples/temperature-measurement-app/telink/prj.conf index 581d7714188ff6..3c35726ec586cf 100644 --- a/examples/temperature-measurement-app/telink/prj.conf +++ b/examples/temperature-measurement-app/telink/prj.conf @@ -77,4 +77,4 @@ CONFIG_CHIP_ENABLE_PM_DURING_BLE=n # Custom RF power values CONFIG_B91_BLE_CTRL_RF_POWER_P9P11DBM=y -CONFIG_IEEE802154_B91_CUSTOM_RF_POWER=9 +CONFIG_CHIP_OPENTHREAD_TX_POWER=9 diff --git a/examples/window-app/telink/prj.conf b/examples/window-app/telink/prj.conf index 0abc1f68818e50..634afcecb31112 100644 --- a/examples/window-app/telink/prj.conf +++ b/examples/window-app/telink/prj.conf @@ -76,4 +76,4 @@ CONFIG_CHIP_ENABLE_PM_DURING_BLE=n # Custom RF power values CONFIG_B91_BLE_CTRL_RF_POWER_P9P11DBM=y -CONFIG_IEEE802154_B91_CUSTOM_RF_POWER=9 +CONFIG_CHIP_OPENTHREAD_TX_POWER=9 diff --git a/src/platform/telink/BLEManagerImpl.cpp b/src/platform/telink/BLEManagerImpl.cpp index 4f09f525bced75..d072b38b1a063b 100644 --- a/src/platform/telink/BLEManagerImpl.cpp +++ b/src/platform/telink/BLEManagerImpl.cpp @@ -49,9 +49,6 @@ #include -// Includes for ieee802154 switchings -#include - using namespace ::chip; using namespace ::chip::Ble; using namespace ::chip::System; @@ -148,14 +145,10 @@ CHIP_ERROR InitRandomStaticAddress() BLEManagerImpl BLEManagerImpl::sInstance; -bool ThreadConnectivityReady; -bool BLERadioInitialized; - CHIP_ERROR BLEManagerImpl::_Init(void) { - ThreadConnectivityReady = false; - BLERadioInitialized = false; - mconId = NULL; + mBLERadioInitialized = false; + mconId = NULL; mServiceMode = ConnectivityManager::kCHIPoBLEServiceMode_Enabled; mFlags.ClearAll().Set(Flags::kAdvertisingEnabled, CHIP_DEVICE_CONFIG_CHIPOBLE_ENABLE_ADVERTISING_AUTOSTART); @@ -305,21 +298,20 @@ CHIP_ERROR BLEManagerImpl::StartAdvertising(void) return CHIP_ERROR_INCORRECT_STATE; } - if (!BLERadioInitialized) + if (!mBLERadioInitialized) { char bt_dev_name[CONFIG_BT_DEVICE_NAME_MAX]; strncpy(bt_dev_name, bt_get_name(), sizeof(bt_dev_name)); - /* Block IEEE802154 */ - /* @todo: move to RadioSwitch module*/ - const struct device * radio_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_ieee802154)); - __ASSERT(radio_dev != NULL, "Get radio_dev fail"); - b91_deinit(radio_dev); + + /* Switch off Thread */ + ThreadStackMgrImpl().SetThreadEnabled(false); + ThreadStackMgrImpl().SetRadioBlocked(true); /* Init BLE stack */ err = bt_enable(NULL); VerifyOrReturnError(err == 0, MapErrorZephyr(err)); (void) bt_set_name(bt_dev_name); - BLERadioInitialized = true; + mBLERadioInitialized = true; #if defined(CONFIG_PM) && !defined(CONFIG_CHIP_ENABLE_PM_DURING_BLE) pm_policy_state_lock_get(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); #endif @@ -931,9 +923,6 @@ CHIP_ERROR BLEManagerImpl::HandleThreadStateChange(const ChipDeviceEvent * event error = PlatformMgr().PostEvent(&attachEvent); VerifyOrExit(error == CHIP_NO_ERROR, ChipLogError(DeviceLayer, "PostEvent err: %" CHIP_ERROR_FORMAT, error.Format())); - - ChipLogDetail(DeviceLayer, "Thread Connectivity Ready"); - ThreadConnectivityReady = true; } exit: @@ -942,8 +931,7 @@ CHIP_ERROR BLEManagerImpl::HandleThreadStateChange(const ChipDeviceEvent * event CHIP_ERROR BLEManagerImpl::HandleBleConnectionClosed(const ChipDeviceEvent * event) { - /* It is time to swich to IEEE802154 radio if it is provisioned */ - if (ThreadConnectivityReady) + if (ThreadStackMgrImpl().IsReadyToAttach()) { SwitchToIeee802154(); } @@ -954,28 +942,19 @@ CHIP_ERROR BLEManagerImpl::HandleBleConnectionClosed(const ChipDeviceEvent * eve /* @todo: move to RadioSwitch module */ void BLEManagerImpl::SwitchToIeee802154(void) { - int result = 0; - ChipLogProgress(DeviceLayer, "SwitchToIeee802154"); - /* Stop BLE */ - StopAdvertising(); - /* Deinit BLE stack */ bt_disable(); - // irq_disable(IRQ1_SYSTIMER); - BLERadioInitialized = false; + mBLERadioInitialized = false; #if defined(CONFIG_PM) && !defined(CONFIG_CHIP_ENABLE_PM_DURING_BLE) pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); #endif - const struct device * radio_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_ieee802154)); - __ASSERT(radio_dev != NULL, "Get radio_dev fail"); - /* Init IEEE802154 */ - result = b91_init(radio_dev); - __ASSERT(result == 0, "Init IEEE802154 err: %d", result); + ThreadStackMgrImpl().SetRadioBlocked(false); + ThreadStackMgrImpl().SetThreadEnabled(true); } } // namespace Internal diff --git a/src/platform/telink/BLEManagerImpl.h b/src/platform/telink/BLEManagerImpl.h index 2ec09aeea04dce..731acae13aa40d 100644 --- a/src/platform/telink/BLEManagerImpl.h +++ b/src/platform/telink/BLEManagerImpl.h @@ -107,6 +107,7 @@ class BLEManagerImpl final : public BLEManager, private BleLayer, private BlePla #if CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING PacketBufferHandle c3CharDataBufferHandle; #endif + bool mBLERadioInitialized; void DriveBLEState(void); CHIP_ERROR PrepareAdvertisingRequest(void); diff --git a/src/platform/telink/BUILD.gn b/src/platform/telink/BUILD.gn index 5c54ccba3e3bb8..4a4cbb9bd66338 100644 --- a/src/platform/telink/BUILD.gn +++ b/src/platform/telink/BUILD.gn @@ -69,7 +69,7 @@ static_library("telink") { if (chip_enable_openthread) { sources += [ "../OpenThread/OpenThreadUtils.cpp", - "../Zephyr/ThreadStackManagerImpl.cpp", + "ThreadStackManagerImpl.cpp", "ThreadStackManagerImpl.h", ] diff --git a/src/platform/telink/ThreadStackManagerImpl.cpp b/src/platform/telink/ThreadStackManagerImpl.cpp new file mode 100644 index 00000000000000..f4bc4fea5bdfa2 --- /dev/null +++ b/src/platform/telink/ThreadStackManagerImpl.cpp @@ -0,0 +1,123 @@ +/* + * + * Copyright (c) 2023 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 + * Provides an implementation of the ThreadStackManager object + * for Telink platform. + * + */ +/* this file behaves like a config.h, comes first */ +#include + +#include +#include + +#include +#include +#include +#include + +namespace chip { +namespace DeviceLayer { + +using namespace ::chip::DeviceLayer::Internal; +using namespace ::chip::Inet; + +ThreadStackManagerImpl ThreadStackManagerImpl::sInstance; + +CHIP_ERROR ThreadStackManagerImpl::_InitThreadStack() +{ + mRadioBlocked = false; + mReadyToAttach = false; + otInstance * const instance = openthread_get_default_instance(); + + ReturnErrorOnFailure(GenericThreadStackManagerImpl_OpenThread::DoInit(instance)); +#ifdef CONFIG_CHIP_OPENTHREAD_TX_POWER + /* On Zephyr platform otPlatRadioSetTransmitPower does not touch radio HW */ + if (otPlatRadioSetTransmitPower(OTInstance(), CONFIG_CHIP_OPENTHREAD_TX_POWER) != OT_ERROR_NONE) + { + ChipLogError(DeviceLayer, "Can't set OpenThread TX power"); + } +#endif /* CONFIG_CHIP_OPENTHREAD_TX_POWER */ + + UDPEndPointImplSockets::SetJoinMulticastGroupHandler([](InterfaceId, const IPAddress & address) { + const otIp6Address otAddress = ToOpenThreadIP6Address(address); + + ThreadStackMgr().LockThreadStack(); + const auto otError = otIp6SubscribeMulticastAddress(openthread_get_default_instance(), &otAddress); + ThreadStackMgr().UnlockThreadStack(); + + return MapOpenThreadError(otError); + }); + + UDPEndPointImplSockets::SetLeaveMulticastGroupHandler([](InterfaceId, const IPAddress & address) { + const otIp6Address otAddress = ToOpenThreadIP6Address(address); + + ThreadStackMgr().LockThreadStack(); + const auto otError = otIp6UnsubscribeMulticastAddress(openthread_get_default_instance(), &otAddress); + ThreadStackMgr().UnlockThreadStack(); + + return MapOpenThreadError(otError); + }); + + return CHIP_NO_ERROR; +} + +void ThreadStackManagerImpl::_LockThreadStack() +{ + openthread_api_mutex_lock(openthread_get_default_context()); +} + +bool ThreadStackManagerImpl::_TryLockThreadStack() +{ + // There's no openthread_api_mutex_try_lock() in Zephyr, so until it's contributed we must use the low-level API + return k_mutex_lock(&openthread_get_default_context()->api_lock, K_NO_WAIT) == 0; +} + +void ThreadStackManagerImpl::_UnlockThreadStack() +{ + openthread_api_mutex_unlock(openthread_get_default_context()); +} + +CHIP_ERROR +ThreadStackManagerImpl::_AttachToThreadNetwork(const Thread::OperationalDataset & dataset, + NetworkCommissioning::Internal::WirelessDriver::ConnectCallback * callback) +{ + CHIP_ERROR result = CHIP_NO_ERROR; + + if (mRadioBlocked) + { + /* On Telink platform it's not possible to rise Thread network when its used by BLE, + so just mark that it's provisioned and rise Thread after BLE disconnect */ + result = SetThreadProvision(dataset.AsByteSpan()); + if (result == CHIP_NO_ERROR) + { + mReadyToAttach = true; + callback->OnResult(NetworkCommissioning::Status::kSuccess, CharSpan(), 0); + } + } + else + { + result = + Internal::GenericThreadStackManagerImpl_OpenThread::_AttachToThreadNetwork(dataset, callback); + } + return result; +} + +} // namespace DeviceLayer +} // namespace chip diff --git a/src/platform/telink/ThreadStackManagerImpl.h b/src/platform/telink/ThreadStackManagerImpl.h index 95560af0836033..c598af1e7501a0 100644 --- a/src/platform/telink/ThreadStackManagerImpl.h +++ b/src/platform/telink/ThreadStackManagerImpl.h @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2021 Project CHIP Authors + * Copyright (c) 2023 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. @@ -18,10 +18,103 @@ /** * @file * Provides an implementation of the ThreadStackManager object - * for Telink platform, by including Zephyr platform - * implementation. + * for Telink platform. */ #pragma once -#include +#include + +#include +#include + +#include +#if !CONFIG_SOC_SERIES_RISCV_TELINK_B91 +#include +#endif // !CONFIG_SOC_SERIES_RISCV_TELINK_B91 + +#include + +namespace chip { +namespace DeviceLayer { + +class ThreadStackManager; +class ThreadStackManagerImpl; + +/** + * Concrete implementation of the ThreadStackManager singleton object for nRF Connect platforms. + */ +class ThreadStackManagerImpl final : public ThreadStackManager, + public Internal::GenericThreadStackManagerImpl_OpenThread +{ + // Allow the ThreadStackManager interface class to delegate method calls to + // the implementation methods provided by this class. + friend class ThreadStackManager; + + // namespace Internal { + + // Allow the generic implementation base classes to call helper methods on + // this class. +#ifndef DOXYGEN_SHOULD_SKIP_THIS + friend Internal::GenericThreadStackManagerImpl_OpenThread; +#endif + +public: + // ===== Methods that implement the ThreadStackManager abstract interface. + CHIP_ERROR _InitThreadStack(); + void SetRadioBlocked(bool state) { mRadioBlocked = state; } + bool IsReadyToAttach(void) const { return mReadyToAttach; } + +protected: + // ===== Methods that implement the ThreadStackManager abstract interface. + + CHIP_ERROR _StartThreadTask() { return CHIP_NO_ERROR; } + void _LockThreadStack(); + bool _TryLockThreadStack(); + void _UnlockThreadStack(); + + // ===== Methods that override the GenericThreadStackManagerImpl_OpenThread abstract interface. + + void _ProcessThreadActivity() {} + CHIP_ERROR _AttachToThreadNetwork(const Thread::OperationalDataset & dataset, + NetworkCommissioning::Internal::WirelessDriver::ConnectCallback * callback); + + //} // namespace Internal + +private: + // ===== Members for internal use by the following friends. + + friend ThreadStackManager & ::chip::DeviceLayer::ThreadStackMgr(void); + friend ThreadStackManagerImpl & ::chip::DeviceLayer::ThreadStackMgrImpl(void); + + static ThreadStackManagerImpl sInstance; + + // ===== Private members for use by this class only. + bool mRadioBlocked; + bool mReadyToAttach; +}; + +/** + * Returns the public interface of the ThreadStackManager singleton object. + * + * chip applications should use this to access features of the ThreadStackManager object + * that are common to all platforms. + */ +inline ThreadStackManager & ThreadStackMgr(void) +{ + return ThreadStackManagerImpl::sInstance; +} + +/** + * Returns the platform-specific implementation of the ThreadStackManager singleton object. + * + * chip applications can use this to gain access to features of the ThreadStackManager + * that are specific to nRF Connect platforms. + */ +inline ThreadStackManagerImpl & ThreadStackMgrImpl(void) +{ + return ThreadStackManagerImpl::sInstance; +} + +} // namespace DeviceLayer +} // namespace chip