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 <commits@restyled.io>
diff --git a/src/include/platform/ConnectivityManager.h b/src/include/platform/ConnectivityManager.h
index 209d748..cac22ed 100644
--- a/src/include/platform/ConnectivityManager.h
+++ b/src/include/platform/ConnectivityManager.h
@@ -52,6 +52,8 @@
template <class>
class GenericPlatformManagerImpl;
template <class>
+class GenericPlatformManagerImpl_CMSISOS;
+template <class>
class GenericPlatformManagerImpl_FreeRTOS;
template <class>
class GenericPlatformManagerImpl_POSIX;
@@ -249,6 +251,8 @@
template <class>
friend class Internal::GenericPlatformManagerImpl;
template <class>
+ friend class Internal::GenericPlatformManagerImpl_CMSISOS;
+ template <class>
friend class Internal::GenericPlatformManagerImpl_FreeRTOS;
template <class>
friend class Internal::GenericPlatformManagerImpl_POSIX;
diff --git a/src/include/platform/PlatformManager.h b/src/include/platform/PlatformManager.h
index 4ce673e..c5fc1f1 100644
--- a/src/include/platform/PlatformManager.h
+++ b/src/include/platform/PlatformManager.h
@@ -53,6 +53,8 @@
template <class>
class GenericPlatformManagerImpl;
template <class>
+class GenericPlatformManagerImpl_CMSISOS;
+template <class>
class GenericPlatformManagerImpl_FreeRTOS;
template <class>
class GenericPlatformManagerImpl_POSIX;
@@ -261,6 +263,8 @@
template <class>
friend class Internal::GenericPlatformManagerImpl;
template <class>
+ friend class Internal::GenericPlatformManagerImpl_CMSISOS;
+ template <class>
friend class Internal::GenericPlatformManagerImpl_FreeRTOS;
template <class>
friend class Internal::GenericPlatformManagerImpl_POSIX;
diff --git a/src/include/platform/ThreadStackManager.h b/src/include/platform/ThreadStackManager.h
index f9f7aed..9498ad8 100644
--- a/src/include/platform/ThreadStackManager.h
+++ b/src/include/platform/ThreadStackManager.h
@@ -55,6 +55,8 @@
template <class>
class GenericConfigurationManagerImpl;
template <class>
+class GenericPlatformManagerImpl_CMSISOS;
+template <class>
class GenericPlatformManagerImpl_FreeRTOS;
template <class>
class GenericConnectivityManagerImpl_Thread;
@@ -168,6 +170,8 @@
template <class>
friend class Internal::GenericConfigurationManagerImpl;
template <class>
+ friend class Internal::GenericPlatformManagerImpl_CMSISOS;
+ template <class>
friend class Internal::GenericPlatformManagerImpl_FreeRTOS;
template <class>
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 0000000..e402815
--- /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 <platform/CHIPDeviceConfig.h>
+#include <platform/internal/GenericPlatformManagerImpl.h>
+
+#include <atomic>
+#include <cmsis_os2.h>
+
+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 ImplClass>
+class GenericPlatformManagerImpl_CMSISOS : public GenericPlatformManagerImpl<ImplClass>
+{
+
+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<ImplClass *>(this); }
+
+ static void EventLoopTaskMain(void * pvParameter);
+ uint32_t SyncNextChipTimerHandling();
+ uint32_t mNextTimerBaseTime = 0;
+ uint32_t mNextTimerDurationTicks = 0;
+ std::atomic<bool> 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<bool> 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<PlatformManagerImpl>;
+
+} // 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 0000000..b75fcbe
--- /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 <platform/PlatformManager.h>
+#include <platform/internal/CHIPDeviceLayerInternal.h>
+#include <platform/internal/GenericPlatformManagerImpl_CMSISOS.h>
+
+#include <lib/support/CodeUtils.h>
+
+// Include the non-inline definitions for the GenericPlatformManagerImpl<> template,
+// from which the GenericPlatformManagerImpl_CMSISOS<> template inherits.
+#include <platform/internal/GenericPlatformManagerImpl.ipp>
+
+namespace chip {
+namespace DeviceLayer {
+namespace Internal {
+
+template <class ImplClass>
+CHIP_ERROR GenericPlatformManagerImpl_CMSISOS<ImplClass>::_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<ImplClass>::_InitChipStack();
+}
+
+template <class ImplClass>
+void GenericPlatformManagerImpl_CMSISOS<ImplClass>::_LockChipStack(void)
+{
+ osMutexAcquire(mChipStackLock, osWaitForever);
+}
+
+template <class ImplClass>
+bool GenericPlatformManagerImpl_CMSISOS<ImplClass>::_TryLockChipStack(void)
+{
+ return osMutexAcquire(mChipStackLock, 0) == osOK;
+}
+
+template <class ImplClass>
+void GenericPlatformManagerImpl_CMSISOS<ImplClass>::_UnlockChipStack(void)
+{
+ osMutexRelease(mChipStackLock);
+}
+
+#if CHIP_STACK_LOCK_TRACKING_ENABLED
+template <class ImplClass>
+bool GenericPlatformManagerImpl_CMSISOS<ImplClass>::_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 <class ImplClass>
+CHIP_ERROR GenericPlatformManagerImpl_CMSISOS<ImplClass>::_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 <class ImplClass>
+void GenericPlatformManagerImpl_CMSISOS<ImplClass>::_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<System::LayerImplFreeRTOS &>(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 <class ImplClass>
+CHIP_ERROR GenericPlatformManagerImpl_CMSISOS<ImplClass>::_StartEventLoopTask(void)
+{
+ mEventLoopTask = osThreadNew(EventLoopTaskMain, this, &mEventLoopTaskAttr);
+ return (mEventLoopTask != nullptr) ? CHIP_NO_ERROR : CHIP_ERROR_NO_MEMORY;
+}
+
+template <class ImplClass>
+void GenericPlatformManagerImpl_CMSISOS<ImplClass>::EventLoopTaskMain(void * pvParameter)
+{
+ ChipLogDetail(DeviceLayer, "CHIP event task running");
+ static_cast<GenericPlatformManagerImpl_CMSISOS<ImplClass> *>(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 <class ImplClass>
+uint32_t GenericPlatformManagerImpl_CMSISOS<ImplClass>::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 <class ImplClass>
+CHIP_ERROR GenericPlatformManagerImpl_CMSISOS<ImplClass>::_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 <class ImplClass>
+void GenericPlatformManagerImpl_CMSISOS<ImplClass>::_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 <class ImplClass>
+CHIP_ERROR GenericPlatformManagerImpl_CMSISOS<ImplClass>::_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 <class ImplClass>
+CHIP_ERROR GenericPlatformManagerImpl_CMSISOS<ImplClass>::_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 <class ImplClass>
+void GenericPlatformManagerImpl_CMSISOS<ImplClass>::BackgroundEventLoopTaskMain(void * pvParameter)
+{
+ ChipLogDetail(DeviceLayer, "CHIP background task running");
+ static_cast<GenericPlatformManagerImpl_CMSISOS<ImplClass> *>(pvParameter)->Impl()->RunBackgroundEventLoop();
+}
+#endif
+
+template <class ImplClass>
+CHIP_ERROR GenericPlatformManagerImpl_CMSISOS<ImplClass>::_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 <class ImplClass>
+void GenericPlatformManagerImpl_CMSISOS<ImplClass>::_Shutdown(void)
+{
+ GenericPlatformManagerImpl<ImplClass>::_Shutdown();
+}
+
+template <class ImplClass>
+CHIP_ERROR GenericPlatformManagerImpl_CMSISOS<ImplClass>::_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<PlatformManagerImpl>;
+
+} // 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 d379bd0..7f0b7ff 100644
--- a/src/platform/BUILD.gn
+++ b/src/platform/BUILD.gn
@@ -496,6 +496,8 @@
"../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 a14c052..12fa8e6 100644
--- a/src/platform/FreeRTOS/SystemTimeSupport.cpp
+++ b/src/platform/FreeRTOS/SystemTimeSupport.cpp
@@ -28,6 +28,7 @@
#include <lib/support/TimeUtils.h>
#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 d8c58a9..7e86c64 100644
--- a/src/platform/silabs/CHIPDevicePlatformConfig.h
+++ b/src/platform/silabs/CHIPDevicePlatformConfig.h
@@ -23,6 +23,8 @@
*/
#pragma once
+#include <cmsis_os2.h>
+#include <sl_cmsis_os2_common.h>
// ==================== 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 c6c855e..c72c7fa 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 1227999..b4dd5c9 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 <cmsis_os2.h>
#include <platform/ConfigurationManager.h>
#include <platform/DiagnosticDataProvider.h>
#include <platform/internal/CHIPDeviceLayerInternal.h>
@@ -304,7 +305,7 @@
// 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 339bc8a..dea8913 100644
--- a/src/platform/silabs/Logging.cpp
+++ b/src/platform/silabs/Logging.cpp
@@ -293,13 +293,6 @@
}
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 @@
}
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 14dd4f7..dccb5db 100644
--- a/src/platform/silabs/PlatformManagerImpl.cpp
+++ b/src/platform/silabs/PlatformManagerImpl.cpp
@@ -28,7 +28,7 @@
#include <platform/FreeRTOS/SystemTimeSupport.h>
#include <platform/KeyValueStoreManager.h>
#include <platform/PlatformManager.h>
-#include <platform/internal/GenericPlatformManagerImpl_FreeRTOS.ipp>
+#include <platform/internal/GenericPlatformManagerImpl_CMSISOS.ipp>
#include <platform/silabs/DiagnosticDataProviderImpl.h>
#if defined(SL_MBEDTLS_USE_TINYCRYPT)
@@ -104,7 +104,7 @@
// Call _InitChipStack() on the generic implementation base class
// to finish the initialization process.
- err = Internal::GenericPlatformManagerImpl_FreeRTOS<PlatformManagerImpl>::_InitChipStack();
+ err = Internal::GenericPlatformManagerImpl_CMSISOS<PlatformManagerImpl>::_InitChipStack();
SuccessOrExit(err);
// Start timer to increment TotalOperationalHours every hour
@@ -129,9 +129,10 @@
SystemLayer().StartTimer(System::Clock::Seconds32(kSecondsPerHour), UpdateOperationalHours, NULL);
}
+
void PlatformManagerImpl::_Shutdown()
{
- Internal::GenericPlatformManagerImpl_FreeRTOS<PlatformManagerImpl>::_Shutdown();
+ Internal::GenericPlatformManagerImpl_CMSISOS<PlatformManagerImpl>::_Shutdown();
}
#if CHIP_DEVICE_CONFIG_ENABLE_WIFI_STATION
diff --git a/src/platform/silabs/PlatformManagerImpl.h b/src/platform/silabs/PlatformManagerImpl.h
index 25813af..1abbb9f 100644
--- a/src/platform/silabs/PlatformManagerImpl.h
+++ b/src/platform/silabs/PlatformManagerImpl.h
@@ -24,7 +24,7 @@
#pragma once
-#include <platform/internal/GenericPlatformManagerImpl_FreeRTOS.h>
+#include <platform/internal/GenericPlatformManagerImpl_CMSISOS.h>
#if CHIP_DEVICE_CONFIG_ENABLE_WIFI_STATION
#include "wfx_host_events.h"
#endif
@@ -36,7 +36,7 @@
/**
* Concrete implementation of the PlatformManager singleton object for the SILABS platform.
*/
-class PlatformManagerImpl final : public PlatformManager, public Internal::GenericPlatformManagerImpl_FreeRTOS<PlatformManagerImpl>
+class PlatformManagerImpl final : public PlatformManager, public Internal::GenericPlatformManagerImpl_CMSISOS<PlatformManagerImpl>
{
// Allow the PlatformManager interface class to delegate method calls to
// the implementation methods provided by this class.
@@ -57,7 +57,7 @@
// Allow the generic implementation base class to call helper methods on
// this class.
#ifndef DOXYGEN_SHOULD_SKIP_THIS
- friend Internal::GenericPlatformManagerImpl_FreeRTOS<PlatformManagerImpl>;
+ friend Internal::GenericPlatformManagerImpl_CMSISOS<PlatformManagerImpl>;
#endif
public:
@@ -87,8 +87,6 @@
System::Clock::Timestamp mStartTime = System::Clock::kZero;
static PlatformManagerImpl sInstance;
-
- using Internal::GenericPlatformManagerImpl_FreeRTOS<PlatformManagerImpl>::PostEventFromISR;
};
/**