From c83abe93a3e332db1f8bfc059098fc6ec50ad972 Mon Sep 17 00:00:00 2001 From: Junior Martinez <67972863+jmartinez-silabs@users.noreply.github.com> Date: Wed, 9 Oct 2024 17:06:33 -0400 Subject: [PATCH] Add a GenericPlatformManager implementation based on CMSISOS V2 API (#35924) * Add a GenericPlatformManager implementation based on CMSISOS V2 API * Restyled by gn * Fix efr32 test_driver build by including the needed headers as they were previously available through the freertos genericPlatformImplementation * Address comments --------- Co-authored-by: Restyled.io --- src/include/platform/ConnectivityManager.h | 4 + src/include/platform/PlatformManager.h | 4 + src/include/platform/ThreadStackManager.h | 4 + .../GenericPlatformManagerImpl_CMSISOS.h | 182 +++++++++ .../GenericPlatformManagerImpl_CMSISOS.ipp | 375 ++++++++++++++++++ src/platform/BUILD.gn | 2 + src/platform/FreeRTOS/SystemTimeSupport.cpp | 1 + .../silabs/CHIPDevicePlatformConfig.h | 6 + src/platform/silabs/CHIPPlatformConfig.h | 10 +- .../silabs/ConfigurationManagerImpl.cpp | 3 +- src/platform/silabs/Logging.cpp | 13 - src/platform/silabs/PlatformManagerImpl.cpp | 7 +- src/platform/silabs/PlatformManagerImpl.h | 8 +- 13 files changed, 592 insertions(+), 27 deletions(-) create mode 100644 src/include/platform/internal/GenericPlatformManagerImpl_CMSISOS.h create mode 100644 src/include/platform/internal/GenericPlatformManagerImpl_CMSISOS.ipp diff --git a/src/include/platform/ConnectivityManager.h b/src/include/platform/ConnectivityManager.h index 209d7484b92bda..cac22ed0da68a9 100644 --- a/src/include/platform/ConnectivityManager.h +++ b/src/include/platform/ConnectivityManager.h @@ -52,6 +52,8 @@ namespace Internal { template class GenericPlatformManagerImpl; template +class GenericPlatformManagerImpl_CMSISOS; +template class GenericPlatformManagerImpl_FreeRTOS; template class GenericPlatformManagerImpl_POSIX; @@ -249,6 +251,8 @@ class ConnectivityManager template friend class Internal::GenericPlatformManagerImpl; template + friend class Internal::GenericPlatformManagerImpl_CMSISOS; + template friend class Internal::GenericPlatformManagerImpl_FreeRTOS; template friend class Internal::GenericPlatformManagerImpl_POSIX; diff --git a/src/include/platform/PlatformManager.h b/src/include/platform/PlatformManager.h index 4ce673ec4129c4..c5fc1f1c081aca 100644 --- a/src/include/platform/PlatformManager.h +++ b/src/include/platform/PlatformManager.h @@ -53,6 +53,8 @@ class GenericConfigurationManagerImpl; template class GenericPlatformManagerImpl; template +class GenericPlatformManagerImpl_CMSISOS; +template class GenericPlatformManagerImpl_FreeRTOS; template class GenericPlatformManagerImpl_POSIX; @@ -261,6 +263,8 @@ class PlatformManager template friend class Internal::GenericPlatformManagerImpl; template + friend class Internal::GenericPlatformManagerImpl_CMSISOS; + template friend class Internal::GenericPlatformManagerImpl_FreeRTOS; template friend class Internal::GenericPlatformManagerImpl_POSIX; diff --git a/src/include/platform/ThreadStackManager.h b/src/include/platform/ThreadStackManager.h index f9f7aed04e4253..9498ad894cc8e8 100644 --- a/src/include/platform/ThreadStackManager.h +++ b/src/include/platform/ThreadStackManager.h @@ -55,6 +55,8 @@ class GenericPlatformManagerImpl; template class GenericConfigurationManagerImpl; template +class GenericPlatformManagerImpl_CMSISOS; +template class GenericPlatformManagerImpl_FreeRTOS; template class GenericConnectivityManagerImpl_Thread; @@ -168,6 +170,8 @@ class ThreadStackManager template friend class Internal::GenericConfigurationManagerImpl; template + friend class Internal::GenericPlatformManagerImpl_CMSISOS; + template friend class Internal::GenericPlatformManagerImpl_FreeRTOS; template friend class Internal::GenericConnectivityManagerImpl_Thread; diff --git a/src/include/platform/internal/GenericPlatformManagerImpl_CMSISOS.h b/src/include/platform/internal/GenericPlatformManagerImpl_CMSISOS.h new file mode 100644 index 00000000000000..e40281527abbb5 --- /dev/null +++ b/src/include/platform/internal/GenericPlatformManagerImpl_CMSISOS.h @@ -0,0 +1,182 @@ +/* + * + * Copyright (c) 2021-2024 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. + */ + +/** + * @file + * Provides an generic implementation of PlatformManager features + * for platform using CMSISOS 2 OS Abstraction APIs. + */ + +#pragma once + +#include +#include + +#include +#include + +namespace chip { +namespace DeviceLayer { +namespace Internal { + +/** + * Provides a generic implementation of PlatformManager features for platforms using CMSISOS 2 OS Abstraction APIs + * + * This template contains implementations of select features from the PlatformManager abstract + * interface that are suitable for use on CMSISOS-based platforms. It is intended to be inherited + * (directly or indirectly) by the PlatformManagerImpl class, which also appears as the template's + * ImplClass parameter. + */ +template +class GenericPlatformManagerImpl_CMSISOS : public GenericPlatformManagerImpl +{ + +protected: + osMutexId_t mChipStackLock = nullptr; + osMessageQueueId_t mChipEventQueue = nullptr; + osThreadId_t mEventLoopTask = nullptr; + bool mChipTimerActive; + +#if defined(CHIP_DEVICE_CONFIG_ENABLE_BG_EVENT_PROCESSING) && CHIP_DEVICE_CONFIG_ENABLE_BG_EVENT_PROCESSING + osMessageQueueId_t mBackgroundEventQueue = nullptr; + osThreadId_t mBackgroundEventLoopTask = nullptr; +#endif + + // ===== Methods that implement the PlatformManager abstract interface. + + CHIP_ERROR _InitChipStack(); + + void _LockChipStack(void); + bool _TryLockChipStack(void); + void _UnlockChipStack(void); + + CHIP_ERROR _PostEvent(const ChipDeviceEvent * event); + void _RunEventLoop(void); + CHIP_ERROR _StartEventLoopTask(void); + CHIP_ERROR _StopEventLoopTask(); + CHIP_ERROR _StartChipTimer(System::Clock::Timeout duration); + void _Shutdown(void); + +#if CHIP_STACK_LOCK_TRACKING_ENABLED + bool _IsChipStackLockedByCurrentThread() const; +#endif + + CHIP_ERROR _PostBackgroundEvent(const ChipDeviceEvent * event); + void _RunBackgroundEventLoop(void); + CHIP_ERROR _StartBackgroundEventLoopTask(void); + CHIP_ERROR _StopBackgroundEventLoopTask(); + + // ===== Methods available to the implementation subclass. + +private: + // ===== Private members for use by this class only. + + inline ImplClass * Impl() { return static_cast(this); } + + static void EventLoopTaskMain(void * pvParameter); + uint32_t SyncNextChipTimerHandling(); + uint32_t mNextTimerBaseTime = 0; + uint32_t mNextTimerDurationTicks = 0; + std::atomic mShouldRunEventLoop; + +#if defined(CHIP_CONFIG_CMSISOS_USE_STATIC_QUEUE) && CHIP_CONFIG_CMSISOS_USE_STATIC_QUEUE + uint8_t mEventQueueBuffer[CHIP_DEVICE_CONFIG_MAX_EVENT_QUEUE_SIZE * sizeof(ChipDeviceEvent)]; + osMessageQueue_t mEventQueueStruct; + const osMessageQueueAttr_t mEventQueueAttr = { .cb_mem = &mEventQueueStruct, + .cb_size = osMessageQueueCbSize, + .mq_mem = mEventQueueBuffer, + .mq_size = sizeof(mEventQueueBuffer) }; + + const osMessageQueueAttr_t * mEventQueueAttrPtr = &mEventQueueAttr; +#else + // Nothing to configure for queues, Just use this to avoid #ifdef in the class implementation + const osMessageQueueAttr_t * mEventQueueAttrPtr = nullptr; +#endif // CHIP_CONFIG_CMSISOS_USE_STATIC_QUEUE + +#if defined(CHIP_CONFIG_CMSISOS_USE_STATIC_TASK) && CHIP_CONFIG_CMSISOS_USE_STATIC_TASK + uint8_t mEventLoopStack[CHIP_DEVICE_CONFIG_CHIP_TASK_STACK_SIZE]; + osThread_t mEventLoopTaskControlBlock; +#endif // CHIP_CONFIG_CMSISOS_USE_STATIC_TASK + + const osThreadAttr_t mEventLoopTaskAttr = { + .name = CHIP_DEVICE_CONFIG_CHIP_TASK_NAME, + .attr_bits = osThreadDetached, +#if defined(CHIP_CONFIG_CMSISOS_USE_STATIC_TASK) && CHIP_CONFIG_CMSISOS_USE_STATIC_TASK + .cb_mem = &mEventLoopTaskControlBlock, + .cb_size = osThreadCbSize, + .stack_mem = mEventLoopStack, +#endif // CHIP_CONFIG_CMSISOS_USE_STATIC_TASK + .stack_size = CHIP_DEVICE_CONFIG_CHIP_TASK_STACK_SIZE, + .priority = CHIP_DEVICE_CONFIG_CHIP_TASK_PRIORITY + }; + +#if defined(CHIP_CONFIG_CMSISOS_USE_STATIC_MUTEX) && CHIP_CONFIG_CMSISOS_USE_STATIC_MUTEX + osMutexCbSize uint8_t mMutexControlBlock[osMutexCbSize]; +#endif // CHIP_CONFIG_CMSISOS_USE_STATIC_MUTEX + const osMutexAttr_t mChipStackMutexAttr = { + .name = "", +#if defined(CHIP_CONFIG_CMSISOS_USE_STATIC_MUTEX) && CHIP_CONFIG_CMSISOS_USE_STATIC_MUTEX + .cb_mem = &mMutexControlBlock, + .cb_size = osMutexCbSize, +#endif // CHIP_CONFIG_CMSISOS_USE_STATIC_MUTEX + .attr_bits = osMutexRecursive | osMutexPrioInherit, + }; + +#if defined(CHIP_DEVICE_CONFIG_ENABLE_BG_EVENT_PROCESSING) && CHIP_DEVICE_CONFIG_ENABLE_BG_EVENT_PROCESSING + static void BackgroundEventLoopTaskMain(void * pvParameter); + std::atomic mShouldRunBackgroundEventLoop; + +#if defined(CHIP_CONFIG_CMSISOS_USE_STATIC_QUEUE) && CHIP_CONFIG_CMSISOS_USE_STATIC_QUEUE + uint8_t mBackgroundQueueBuffer[CHIP_DEVICE_CONFIG_BG_MAX_EVENT_QUEUE_SIZE * sizeof(ChipDeviceEvent)]; + osMessageQueue_t mBackgroundQueueStruct; + const osMessageQueueAttr_t mBgQueueAttr = { .cb_mem = &mBackgroundQueueStruct, + .cb_size = osMessageQueueCbSize, + .mq_mem = mBackgroundQueueBuffer, + .mq_size = sizeof(mBackgroundQueueBuffer) }; + + const osMessageQueueAttr_t * mBgQueueAttrPtr = &mBgQueueAttr; +#else + // Nothing to configure for queues, Just use this to avoid #ifdef in the class implementation + const osMessageQueueAttr_t * mBgQueueAttrPtr = nullptr; +#endif // CHIP_CONFIG_CMSISOS_USE_STATIC_QUEUE + +#if defined(CHIP_CONFIG_CMSISOS_USE_STATIC_TASK) && CHIP_CONFIG_CMSISOS_USE_STATIC_TASK + uint8_t mBackgroundEventLoopStack[CHIP_DEVICE_CONFIG_BG_TASK_STACK_SIZE]; + osThread_t mBackgroundEventLoopTaskControlBlock; +#endif // CHIP_CONFIG_CMSISOS_USE_STATIC_TASK + + const osThreadAttr_t mBgEventLoopTaskAttr = { + .name = CHIP_DEVICE_CONFIG_BG_TASK_NAME, + .attr_bits = osThreadDetached, +#if defined(CHIP_CONFIG_CMSISOS_USE_STATIC_TASK) && CHIP_CONFIG_CMSISOS_USE_STATIC_TASK + .cb_mem = &mBackgroundEventLoopTaskControlBlock, + .cb_size = osThreadCbSize, + .stack_mem = mBackgroundEventLoopStack, +#endif // CHIP_CONFIG_CMSISOS_USE_STATIC_TASK + .stack_size = CHIP_DEVICE_CONFIG_BG_TASK_STACK_SIZE, + .priority = CHIP_DEVICE_CONFIG_BG_TASK_PRIORITY + }; +#endif // CHIP_DEVICE_CONFIG_ENABLE_BG_EVENT_PROCESSING +}; + +// Instruct the compiler to instantiate the template only when explicitly told to do so. +extern template class GenericPlatformManagerImpl_CMSISOS; + +} // namespace Internal +} // namespace DeviceLayer +} // namespace chip diff --git a/src/include/platform/internal/GenericPlatformManagerImpl_CMSISOS.ipp b/src/include/platform/internal/GenericPlatformManagerImpl_CMSISOS.ipp new file mode 100644 index 00000000000000..b75fcbe0c24a6f --- /dev/null +++ b/src/include/platform/internal/GenericPlatformManagerImpl_CMSISOS.ipp @@ -0,0 +1,375 @@ +/* + * + * Copyright (c) 2021-2024 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. + */ + +/** + * @file + * Contains non-inline method definitions for the + * GenericPlatformManagerImpl_CMSISOS<> template. + */ + +#ifndef GENERIC_PLATFORM_MANAGER_IMPL_CMSISOS_CPP +#define GENERIC_PLATFORM_MANAGER_IMPL_CMSISOS_CPP + +#include +#include +#include + +#include + +// Include the non-inline definitions for the GenericPlatformManagerImpl<> template, +// from which the GenericPlatformManagerImpl_CMSISOS<> template inherits. +#include + +namespace chip { +namespace DeviceLayer { +namespace Internal { + +template +CHIP_ERROR GenericPlatformManagerImpl_CMSISOS::_InitChipStack(void) +{ + mNextTimerBaseTime = osKernelGetTickCount(); + mNextTimerDurationTicks = 0; + mChipTimerActive = false; + + // We support calling Shutdown followed by InitChipStack, because some tests + // do that. To keep things simple for existing consumers, we do not + // destroy our lock and queue at shutdown, but rather check whether they + // already exist here before trying to create them. + if (mChipStackLock == nullptr) + { + mChipStackLock = osMutexNew(&mChipStackMutexAttr); + VerifyOrReturnError(mChipStackLock != nullptr, CHIP_ERROR_NO_MEMORY, + ChipLogError(DeviceLayer, "Failed to create CHIP stack lock")); + } + + if (mChipEventQueue == nullptr) + { + mChipEventQueue = osMessageQueueNew(CHIP_DEVICE_CONFIG_MAX_EVENT_QUEUE_SIZE, sizeof(ChipDeviceEvent), mEventQueueAttrPtr); + VerifyOrReturnError(mChipEventQueue != nullptr, CHIP_ERROR_NO_MEMORY, + ChipLogError(DeviceLayer, "Failed to allocate CHIP main event queue")); + } + else + { + // Clear out any events that might be stuck in the queue, so we start + // with a clean slate, as if we had just re-created the queue. + osMessageQueueReset(mChipEventQueue); + } + + mShouldRunEventLoop.store(false); + +#if defined(CHIP_DEVICE_CONFIG_ENABLE_BG_EVENT_PROCESSING) && CHIP_DEVICE_CONFIG_ENABLE_BG_EVENT_PROCESSING + if (mBackgroundEventQueue == nullptr) + { + mBackgroundEventQueue = + osMessageQueueNew(CHIP_DEVICE_CONFIG_BG_MAX_EVENT_QUEUE_SIZE, sizeof(ChipDeviceEvent), mBgQueueAttrPtr); + VerifyOrReturnError(mBackgroundEventQueue != nullptr, CHIP_ERROR_NO_MEMORY, + ChipLogError(DeviceLayer, "Failed to allocate CHIP background event queue")); + } + else + { + osMessageQueueReset(mBackgroundEventQueue); + } + + mShouldRunBackgroundEventLoop.store(false); +#endif + + // Call up to the base class _InitChipStack() to perform the bulk of the initialization. + return GenericPlatformManagerImpl::_InitChipStack(); +} + +template +void GenericPlatformManagerImpl_CMSISOS::_LockChipStack(void) +{ + osMutexAcquire(mChipStackLock, osWaitForever); +} + +template +bool GenericPlatformManagerImpl_CMSISOS::_TryLockChipStack(void) +{ + return osMutexAcquire(mChipStackLock, 0) == osOK; +} + +template +void GenericPlatformManagerImpl_CMSISOS::_UnlockChipStack(void) +{ + osMutexRelease(mChipStackLock); +} + +#if CHIP_STACK_LOCK_TRACKING_ENABLED +template +bool GenericPlatformManagerImpl_CMSISOS::_IsChipStackLockedByCurrentThread() const +{ + // If we have not started our event loop yet, return true because in that + // case we can't be racing against the (not yet started) event loop. + // + // Similarly, if mChipStackLock has not been created yet, might as well + // return true. + return (mEventLoopTask == nullptr) || (mChipStackLock == nullptr) || (osMutexGetOwner(mChipStackLock) == osThreadGetId()); +} +#endif // CHIP_STACK_LOCK_TRACKING_ENABLED + +template +CHIP_ERROR GenericPlatformManagerImpl_CMSISOS::_PostEvent(const ChipDeviceEvent * event) +{ + VerifyOrReturnError(mChipEventQueue != nullptr, CHIP_ERROR_UNINITIALIZED); + + osStatus_t status = osMessageQueuePut(mChipEventQueue, event, osPriorityNormal, 1); + if (status != osOK) + { + ChipLogError(DeviceLayer, "Failed to post event to CHIP Platform event queue"); + return CHIP_ERROR(chip::ChipError::Range::kOS, status); + } + return CHIP_NO_ERROR; +} + +template +void GenericPlatformManagerImpl_CMSISOS::_RunEventLoop(void) +{ + // Lock the CHIP stack. + StackLock lock; + + bool oldShouldRunEventLoop = false; + if (!mShouldRunEventLoop.compare_exchange_strong(oldShouldRunEventLoop /* expected */, true /* desired */)) + { + ChipLogError(DeviceLayer, "Error trying to run the event loop while it is already running"); + return; + } + + while (mShouldRunEventLoop.load()) + { + uint32_t waitTimeInTicks; + + // If one or more CHIP timers are active... + if (mChipTimerActive) + { + // Adjust the base time and remaining duration for the next scheduled timer based on the + // amount of time that has elapsed since it was started. + // When the timer's expiration time elapses, Handle the platform Timer + // else wait for a queue event for timer remaining time. + waitTimeInTicks = SyncNextChipTimerHandling(); + if (waitTimeInTicks == 0) + { + // Reset the 'timer active' flag. This will be set to true again by _StartChipTimer() + // if there are further timers beyond the expired one that are still active. + mChipTimerActive = false; + + // Call into the system layer to dispatch the callback functions for all timers + // that have expired. + // TODO We use the same SystemLayer implementation as FreeRTOS, Nothing in it is freeRTOS specific. We should + // it. + CHIP_ERROR err = static_cast(DeviceLayer::SystemLayer()).HandlePlatformTimer(); + if (err != CHIP_NO_ERROR) + { + ChipLogError(DeviceLayer, "Error handling CHIP timers: %" CHIP_ERROR_FORMAT, err.Format()); + } + } + } + else + { + // No CHIP timers are active, so we wait indefinitely for an event to arrive on the event + // queue. + waitTimeInTicks = osWaitForever; + } + + // Unlock the CHIP stack, allowing other threads to enter CHIP while + // the event loop thread is sleeping. + StackUnlock unlock; + ChipDeviceEvent event; + osStatus_t eventReceived = osMessageQueueGet(mChipEventQueue, &event, nullptr, waitTimeInTicks); + + // If an event was received, dispatch it and continue until the queue is empty. + while (eventReceived == osOK) + { + StackLock lock; + Impl()->DispatchEvent(&event); + StackUnlock unlock; + eventReceived = osMessageQueueGet(mChipEventQueue, &event, nullptr, 0); + } + } +} + +template +CHIP_ERROR GenericPlatformManagerImpl_CMSISOS::_StartEventLoopTask(void) +{ + mEventLoopTask = osThreadNew(EventLoopTaskMain, this, &mEventLoopTaskAttr); + return (mEventLoopTask != nullptr) ? CHIP_NO_ERROR : CHIP_ERROR_NO_MEMORY; +} + +template +void GenericPlatformManagerImpl_CMSISOS::EventLoopTaskMain(void * pvParameter) +{ + ChipLogDetail(DeviceLayer, "CHIP event task running"); + static_cast *>(pvParameter)->Impl()->RunEventLoop(); +} + +/** + * @brief Calculate the elapsed time of the active chip platform timer since it has been started, + * as set in mNextTimerBaseTime, and adjust its remaining time with the mNextTimerDurationTicks member + * + * @return The next Timer remaining time in ticks + */ +template +uint32_t GenericPlatformManagerImpl_CMSISOS::SyncNextChipTimerHandling() +{ + uint32_t elapsedTime = 0; + uint32_t timerBaseTime = mNextTimerBaseTime; + uint32_t currentTime = osKernelGetTickCount(); + if (currentTime < timerBaseTime) + { + // TickCount has wrapped around + elapsedTime = (UINT32_MAX - timerBaseTime) + currentTime; + } + else + { + elapsedTime = currentTime - timerBaseTime; + } + + if (elapsedTime < mNextTimerDurationTicks) + { + // We didn't timeout yet, adjust the remaining time + mNextTimerDurationTicks -= elapsedTime; + mNextTimerBaseTime = osKernelGetTickCount(); + } + else + { + mNextTimerDurationTicks = 0; + } + return mNextTimerDurationTicks; +} + +template +CHIP_ERROR GenericPlatformManagerImpl_CMSISOS::_PostBackgroundEvent(const ChipDeviceEvent * event) +{ +#if defined(CHIP_DEVICE_CONFIG_ENABLE_BG_EVENT_PROCESSING) && CHIP_DEVICE_CONFIG_ENABLE_BG_EVENT_PROCESSING + VerifyOrReturnError(mBackgroundEventQueue != nullptr, CHIP_ERROR_UNINITIALIZED); + if (!(event->Type == DeviceEventType::kCallWorkFunct || event->Type == DeviceEventType::kNoOp)) + { + return CHIP_ERROR_INVALID_ARGUMENT; + } + + osStatus_t status = osMessageQueuePut(mBackgroundEventQueue, event, osPriorityNormal, 1); + VerifyOrReturnError(status == osOk, CHIP_ERROR_NO_MEMORY, + ChipLogError(DeviceLayer, "Failed to post event to CHIP background event queue")); + return CHIP_NO_ERROR; +#else + // Use foreground event loop for background events + return _PostEvent(event); +#endif +} + +template +void GenericPlatformManagerImpl_CMSISOS::_RunBackgroundEventLoop(void) +{ +#if defined(CHIP_DEVICE_CONFIG_ENABLE_BG_EVENT_PROCESSING) && CHIP_DEVICE_CONFIG_ENABLE_BG_EVENT_PROCESSING + bool oldShouldRunBackgroundEventLoop = false; + VerifyOrReturn( + mShouldRunBackgroundEventLoop.compare_exchange_strong(oldShouldRunBackgroundEventLoop /* expected */, true /* desired */), + ChipLogError(DeviceLayer, "Error trying to run the background event loop while it is already running")); + + while (mShouldRunBackgroundEventLoop.load()) + { + ChipDeviceEvent event; + osStatus_t eventReceived = osMessageQueueGet(mBackgroundEventQueue, &event, NULL, osWaitForever); + while (eventReceived == osOK) + { + Impl()->DispatchEvent(&event); + eventReceived = osMessageQueueGet(mBackgroundEventQueue, &event, portMAX_DELAY); + } + } +#endif +} + +template +CHIP_ERROR GenericPlatformManagerImpl_CMSISOS::_StartBackgroundEventLoopTask(void) +{ +#if defined(CHIP_DEVICE_CONFIG_ENABLE_BG_EVENT_PROCESSING) && CHIP_DEVICE_CONFIG_ENABLE_BG_EVENT_PROCESSING + mBackgroundEventLoopTask = osThreadNew(BackgroundEventLoopTaskMain, this, &mBgEventLoopTaskAttr); + return (mBackgroundEventLoopTask != NULL) ? CHIP_NO_ERROR : CHIP_ERROR_NO_MEMORY; +#else + // Use foreground event loop for background events + return CHIP_NO_ERROR; +#endif +} + +template +CHIP_ERROR GenericPlatformManagerImpl_CMSISOS::_StopBackgroundEventLoopTask(void) +{ +#if defined(CHIP_DEVICE_CONFIG_ENABLE_BG_EVENT_PROCESSING) && CHIP_DEVICE_CONFIG_ENABLE_BG_EVENT_PROCESSING + bool oldShouldRunBackgroundEventLoop = true; + if (mShouldRunBackgroundEventLoop.compare_exchange_strong(oldShouldRunBackgroundEventLoop /* expected */, false /* desired */)) + { + ChipDeviceEvent noop{ .Type = DeviceEventType::kNoOp }; + osMessageQueuePut(mBackgroundEventQueue, &noop, osPriorityNormal, 0); + } + return CHIP_NO_ERROR; +#else + // Use foreground event loop for background events + return CHIP_NO_ERROR; +#endif +} + +#if defined(CHIP_DEVICE_CONFIG_ENABLE_BG_EVENT_PROCESSING) && CHIP_DEVICE_CONFIG_ENABLE_BG_EVENT_PROCESSING +template +void GenericPlatformManagerImpl_CMSISOS::BackgroundEventLoopTaskMain(void * pvParameter) +{ + ChipLogDetail(DeviceLayer, "CHIP background task running"); + static_cast *>(pvParameter)->Impl()->RunBackgroundEventLoop(); +} +#endif + +template +CHIP_ERROR GenericPlatformManagerImpl_CMSISOS::_StartChipTimer(System::Clock::Timeout delay) +{ + mChipTimerActive = true; + mNextTimerBaseTime = osKernelGetTickCount(); + mNextTimerDurationTicks = (System::Clock::Milliseconds64(delay).count() * osKernelGetTickFreq()) / 1000; + + // If the platform timer is being updated by a thread other than the event loop thread, + // trigger the event loop thread to recalculate its wait time by posting a no-op event + // to the event queue. + if (osThreadGetId() != mEventLoopTask) + { + ChipDeviceEvent noop{ .Type = DeviceEventType::kNoOp }; + ReturnErrorOnFailure(Impl()->PostEvent(&noop)); + } + + return CHIP_NO_ERROR; +} + +template +void GenericPlatformManagerImpl_CMSISOS::_Shutdown(void) +{ + GenericPlatformManagerImpl::_Shutdown(); +} + +template +CHIP_ERROR GenericPlatformManagerImpl_CMSISOS::_StopEventLoopTask(void) +{ + mShouldRunEventLoop.store(false); + return CHIP_NO_ERROR; +} + +// Fully instantiate the generic implementation class in whatever compilation unit includes this file. +// NB: This must come after all templated class members are defined. +template class GenericPlatformManagerImpl_CMSISOS; + +} // namespace Internal +} // namespace DeviceLayer +} // namespace chip + +#endif // GENERIC_PLATFORM_MANAGER_IMPL_CMSISOS_CPP diff --git a/src/platform/BUILD.gn b/src/platform/BUILD.gn index d379bd0e1f4e0d..7f0b7ff87a1b16 100644 --- a/src/platform/BUILD.gn +++ b/src/platform/BUILD.gn @@ -496,6 +496,8 @@ if (chip_device_platform != "none") { "../include/platform/internal/GenericDeviceInstanceInfoProvider.ipp", "../include/platform/internal/GenericPlatformManagerImpl.h", "../include/platform/internal/GenericPlatformManagerImpl.ipp", + "../include/platform/internal/GenericPlatformManagerImpl_CMSISOS.h", + "../include/platform/internal/GenericPlatformManagerImpl_CMSISOS.ipp", "../include/platform/internal/GenericPlatformManagerImpl_FreeRTOS.h", "../include/platform/internal/GenericPlatformManagerImpl_FreeRTOS.ipp", "../include/platform/internal/GenericPlatformManagerImpl_POSIX.h", diff --git a/src/platform/FreeRTOS/SystemTimeSupport.cpp b/src/platform/FreeRTOS/SystemTimeSupport.cpp index a14c0527b44240..12fa8e636da64f 100644 --- a/src/platform/FreeRTOS/SystemTimeSupport.cpp +++ b/src/platform/FreeRTOS/SystemTimeSupport.cpp @@ -28,6 +28,7 @@ #include #include "FreeRTOS.h" +#include "task.h" namespace chip { namespace System { diff --git a/src/platform/silabs/CHIPDevicePlatformConfig.h b/src/platform/silabs/CHIPDevicePlatformConfig.h index d8c58a93685c21..7e86c64694de5b 100644 --- a/src/platform/silabs/CHIPDevicePlatformConfig.h +++ b/src/platform/silabs/CHIPDevicePlatformConfig.h @@ -23,6 +23,8 @@ */ #pragma once +#include +#include // ==================== Platform Adaptations ==================== @@ -129,6 +131,10 @@ // ========== Platform-specific Configuration Overrides ========= +#ifndef CHIP_DEVICE_CONFIG_CHIP_TASK_PRIORITY +#define CHIP_DEVICE_CONFIG_CHIP_TASK_PRIORITY osPriorityHigh +#endif + #ifndef CHIP_DEVICE_CONFIG_CHIP_TASK_STACK_SIZE #if SLI_SI91X_MCU_INTERFACE #define CHIP_DEVICE_CONFIG_CHIP_TASK_STACK_SIZE (7 * 1024) diff --git a/src/platform/silabs/CHIPPlatformConfig.h b/src/platform/silabs/CHIPPlatformConfig.h index c6c855ee9c7533..c72c7fa20c6972 100644 --- a/src/platform/silabs/CHIPPlatformConfig.h +++ b/src/platform/silabs/CHIPPlatformConfig.h @@ -129,13 +129,13 @@ #define CHIP_SHELL_MAX_LINE_SIZE 256 #endif // CHIP_SHELL_MAX_LINE_SIZE -// ==================== FreeRTOS Configuration Overrides ==================== -#ifndef CHIP_CONFIG_FREERTOS_USE_STATIC_TASK -#define CHIP_CONFIG_FREERTOS_USE_STATIC_TASK 1 +// ==================== CMSISOS Configuration Overrides ==================== +#ifndef CHIP_CONFIG_CMSISOS_USE_STATIC_TASK +#define CHIP_CONFIG_CMSISOS_USE_STATIC_TASK 1 #endif -#ifndef CHIP_CONFIG_FREERTOS_USE_STATIC_QUEUE -#define CHIP_CONFIG_FREERTOS_USE_STATIC_QUEUE 1 +#ifndef CHIP_CONFIG_CMSISOS_USE_STATIC_QUEUE +#define CHIP_CONFIG_CMSISOS_USE_STATIC_QUEUE 1 #endif #ifndef CHIP_SHELL_MAX_TOKENS diff --git a/src/platform/silabs/ConfigurationManagerImpl.cpp b/src/platform/silabs/ConfigurationManagerImpl.cpp index 122799952acab5..b4dd5c9c524f72 100644 --- a/src/platform/silabs/ConfigurationManagerImpl.cpp +++ b/src/platform/silabs/ConfigurationManagerImpl.cpp @@ -22,6 +22,7 @@ * for Silabs platforms using the Silicon Labs SDK. */ /* this file behaves like a config.h, comes first */ +#include #include #include #include @@ -304,7 +305,7 @@ void ConfigurationManagerImpl::DoFactoryReset(intptr_t arg) // When called from an RPC, the following reset occurs before the RPC can respond, // which breaks tests (because it looks like the RPC hasn't successfully completed). // Block the task for 500 ms before the reset occurs to allow RPC response to be sent - vTaskDelay(pdMS_TO_TICKS(500)); + osDelay(pdMS_TO_TICKS(500)); NVIC_SystemReset(); } diff --git a/src/platform/silabs/Logging.cpp b/src/platform/silabs/Logging.cpp index 339bc8ae078cd6..dea891379140fa 100644 --- a/src/platform/silabs/Logging.cpp +++ b/src/platform/silabs/Logging.cpp @@ -293,13 +293,6 @@ extern "C" void LwIPLog(const char * aFormat, ...) } PrintLog(formattedMsg); - -#if configCHECK_FOR_STACK_OVERFLOW - // Force a stack overflow check. - if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) - taskYIELD(); -#endif - // Let the application know that a log message has been emitted. chip::DeviceLayer::OnLogOutput(); #endif // SILABS_LOG_ENABLED @@ -348,12 +341,6 @@ extern "C" void otPlatLog(otLogLevel aLogLevel, otLogRegion aLogRegion, const ch } PrintLog(formattedMsg); - -#if configCHECK_FOR_STACK_OVERFLOW - // Force a stack overflow check. - if (xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED) - taskYIELD(); -#endif } // Let the application know that a log message has been emitted. diff --git a/src/platform/silabs/PlatformManagerImpl.cpp b/src/platform/silabs/PlatformManagerImpl.cpp index 14dd4f78f2487e..dccb5db7657251 100644 --- a/src/platform/silabs/PlatformManagerImpl.cpp +++ b/src/platform/silabs/PlatformManagerImpl.cpp @@ -28,7 +28,7 @@ #include #include #include -#include +#include #include #if defined(SL_MBEDTLS_USE_TINYCRYPT) @@ -104,7 +104,7 @@ CHIP_ERROR PlatformManagerImpl::_InitChipStack(void) // Call _InitChipStack() on the generic implementation base class // to finish the initialization process. - err = Internal::GenericPlatformManagerImpl_FreeRTOS::_InitChipStack(); + err = Internal::GenericPlatformManagerImpl_CMSISOS::_InitChipStack(); SuccessOrExit(err); // Start timer to increment TotalOperationalHours every hour @@ -129,9 +129,10 @@ void PlatformManagerImpl::UpdateOperationalHours(System::Layer * systemLayer, vo SystemLayer().StartTimer(System::Clock::Seconds32(kSecondsPerHour), UpdateOperationalHours, NULL); } + void PlatformManagerImpl::_Shutdown() { - Internal::GenericPlatformManagerImpl_FreeRTOS::_Shutdown(); + Internal::GenericPlatformManagerImpl_CMSISOS::_Shutdown(); } #if CHIP_DEVICE_CONFIG_ENABLE_WIFI_STATION diff --git a/src/platform/silabs/PlatformManagerImpl.h b/src/platform/silabs/PlatformManagerImpl.h index 25813afb4839f9..1abbb9f07f5e7b 100644 --- a/src/platform/silabs/PlatformManagerImpl.h +++ b/src/platform/silabs/PlatformManagerImpl.h @@ -24,7 +24,7 @@ #pragma once -#include +#include #if CHIP_DEVICE_CONFIG_ENABLE_WIFI_STATION #include "wfx_host_events.h" #endif @@ -36,7 +36,7 @@ namespace DeviceLayer { /** * Concrete implementation of the PlatformManager singleton object for the SILABS platform. */ -class PlatformManagerImpl final : public PlatformManager, public Internal::GenericPlatformManagerImpl_FreeRTOS +class PlatformManagerImpl final : public PlatformManager, public Internal::GenericPlatformManagerImpl_CMSISOS { // Allow the PlatformManager interface class to delegate method calls to // the implementation methods provided by this class. @@ -57,7 +57,7 @@ class PlatformManagerImpl final : public PlatformManager, public Internal::Gener // Allow the generic implementation base class to call helper methods on // this class. #ifndef DOXYGEN_SHOULD_SKIP_THIS - friend Internal::GenericPlatformManagerImpl_FreeRTOS; + friend Internal::GenericPlatformManagerImpl_CMSISOS; #endif public: @@ -87,8 +87,6 @@ class PlatformManagerImpl final : public PlatformManager, public Internal::Gener System::Clock::Timestamp mStartTime = System::Clock::kZero; static PlatformManagerImpl sInstance; - - using Internal::GenericPlatformManagerImpl_FreeRTOS::PostEventFromISR; }; /**