3 * Copyright (c) 2020 Project CHIP Authors
4 * Copyright (c) 2018 Nest Labs, Inc.
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
21 * Contains non-inline method definitions for the
22 * GenericPlatformManagerImpl_FreeRTOS<> template.
25 #ifndef GENERIC_PLATFORM_MANAGER_IMPL_FREERTOS_CPP
26 #define GENERIC_PLATFORM_MANAGER_IMPL_FREERTOS_CPP
28 #include <platform/PlatformManager.h>
29 #include <platform/internal/CHIPDeviceLayerInternal.h>
30 #include <platform/internal/GenericPlatformManagerImpl_FreeRTOS.h>
32 #include <lib/support/CodeUtils.h>
34 // Include the non-inline definitions for the GenericPlatformManagerImpl<> template,
35 // from which the GenericPlatformManagerImpl_FreeRTOS<> template inherits.
36 #include <platform/internal/GenericPlatformManagerImpl.cpp>
39 namespace DeviceLayer {
42 // Fully instantiate the generic implementation class in whatever compilation unit includes this file.
43 template class GenericPlatformManagerImpl_FreeRTOS<PlatformManagerImpl>;
45 template <class ImplClass>
46 CHIP_ERROR GenericPlatformManagerImpl_FreeRTOS<ImplClass>::_InitChipStack(void)
48 CHIP_ERROR err = CHIP_NO_ERROR;
50 vTaskSetTimeOutState(&mNextTimerBaseTime);
51 mNextTimerDurationTicks = 0;
52 mEventLoopTask = NULL;
53 mChipTimerActive = false;
55 mChipStackLock = xSemaphoreCreateMutex();
56 if (mChipStackLock == NULL)
58 ChipLogError(DeviceLayer, "Failed to create CHIP stack lock");
59 ExitNow(err = CHIP_ERROR_NO_MEMORY);
62 #if defined(CHIP_CONFIG_FREERTOS_USE_STATIC_QUEUE) && CHIP_CONFIG_FREERTOS_USE_STATIC_QUEUE
64 xQueueCreateStatic(CHIP_DEVICE_CONFIG_MAX_EVENT_QUEUE_SIZE, sizeof(ChipDeviceEvent), mEventQueueBuffer, &mEventQueueStruct);
66 mChipEventQueue = xQueueCreate(CHIP_DEVICE_CONFIG_MAX_EVENT_QUEUE_SIZE, sizeof(ChipDeviceEvent));
68 if (mChipEventQueue == NULL)
70 ChipLogError(DeviceLayer, "Failed to allocate CHIP event queue");
71 ExitNow(err = CHIP_ERROR_NO_MEMORY);
74 // Call up to the base class _InitChipStack() to perform the bulk of the initialization.
75 err = GenericPlatformManagerImpl<ImplClass>::_InitChipStack();
82 template <class ImplClass>
83 void GenericPlatformManagerImpl_FreeRTOS<ImplClass>::_LockChipStack(void)
85 xSemaphoreTake(mChipStackLock, portMAX_DELAY);
88 template <class ImplClass>
89 bool GenericPlatformManagerImpl_FreeRTOS<ImplClass>::_TryLockChipStack(void)
91 return xSemaphoreTake(mChipStackLock, 0) == pdTRUE;
94 template <class ImplClass>
95 void GenericPlatformManagerImpl_FreeRTOS<ImplClass>::_UnlockChipStack(void)
97 xSemaphoreGive(mChipStackLock);
100 template <class ImplClass>
101 void GenericPlatformManagerImpl_FreeRTOS<ImplClass>::_PostEvent(const ChipDeviceEvent * event)
103 if (mChipEventQueue != NULL)
105 if (!xQueueSend(mChipEventQueue, event, 1))
107 ChipLogError(DeviceLayer, "Failed to post event to CHIP Platform event queue");
112 template <class ImplClass>
113 void GenericPlatformManagerImpl_FreeRTOS<ImplClass>::_RunEventLoop(void)
116 ChipDeviceEvent event;
118 VerifyOrDie(mEventLoopTask != NULL);
120 // Lock the CHIP stack.
121 Impl()->LockChipStack();
127 // If one or more CHIP timers are active...
128 if (mChipTimerActive)
130 // Adjust the base time and remaining duration for the next scheduled timer based on the
131 // amount of time that has elapsed since it was started.
132 // IF the timer's expiration time has already arrived...
133 if (xTaskCheckForTimeOut(&mNextTimerBaseTime, &mNextTimerDurationTicks) == pdTRUE)
135 // Reset the 'timer active' flag. This will be set to true again by _StartChipTimer()
136 // if there are further timers beyond the expired one that are still active.
137 mChipTimerActive = false;
139 // Call into the system layer to dispatch the callback functions for all timers
140 // that have expired.
141 err = SystemLayer.HandlePlatformTimer();
142 if (err != CHIP_SYSTEM_NO_ERROR)
144 ChipLogError(DeviceLayer, "Error handling CHIP timers: %s", ErrorStr(err));
147 // When processing the event queue below, do not wait if the queue is empty. Instead
148 // immediately loop around and process timers again
152 // If there is still time before the next timer expires, arrange to wait on the event queue
153 // until that timer expires.
156 waitTime = mNextTimerDurationTicks;
160 // Otherwise no CHIP timers are active, so wait indefinitely for an event to arrive on the event
164 waitTime = portMAX_DELAY;
167 // Unlock the CHIP stack, allowing other threads to enter CHIP while the event loop thread is sleeping.
168 Impl()->UnlockChipStack();
170 BaseType_t eventReceived = xQueueReceive(mChipEventQueue, &event, waitTime);
172 // Lock the CHIP stack.
173 Impl()->LockChipStack();
175 // If an event was received, dispatch it. Continue receiving events from the queue and
176 // dispatching them until the queue is empty.
177 while (eventReceived == pdTRUE)
179 Impl()->DispatchEvent(&event);
181 eventReceived = xQueueReceive(mChipEventQueue, &event, 0);
186 template <class ImplClass>
187 CHIP_ERROR GenericPlatformManagerImpl_FreeRTOS<ImplClass>::_StartEventLoopTask(void)
189 #if defined(CHIP_CONFIG_FREERTOS_USE_STATIC_TASK) && CHIP_CONFIG_FREERTOS_USE_STATIC_TASK
190 mEventLoopTask = xTaskCreateStatic(EventLoopTaskMain, CHIP_DEVICE_CONFIG_CHIP_TASK_NAME, ArraySize(mEventLoopStack), this,
191 CHIP_DEVICE_CONFIG_CHIP_TASK_PRIORITY, mEventLoopStack, &mventLoopTaskStruct);
193 xTaskCreate(EventLoopTaskMain, CHIP_DEVICE_CONFIG_CHIP_TASK_NAME, CHIP_DEVICE_CONFIG_CHIP_TASK_STACK_SIZE / sizeof(StackType_t),
194 this, CHIP_DEVICE_CONFIG_CHIP_TASK_PRIORITY, &mEventLoopTask);
197 return (mEventLoopTask != NULL) ? CHIP_NO_ERROR : CHIP_ERROR_NO_MEMORY;
200 template <class ImplClass>
201 void GenericPlatformManagerImpl_FreeRTOS<ImplClass>::EventLoopTaskMain(void * arg)
203 ChipLogDetail(DeviceLayer, "CHIP task running");
204 static_cast<GenericPlatformManagerImpl_FreeRTOS<ImplClass> *>(arg)->Impl()->RunEventLoop();
207 template <class ImplClass>
208 CHIP_ERROR GenericPlatformManagerImpl_FreeRTOS<ImplClass>::_StartChipTimer(uint32_t aMilliseconds)
210 mChipTimerActive = true;
211 vTaskSetTimeOutState(&mNextTimerBaseTime);
212 mNextTimerDurationTicks = pdMS_TO_TICKS(aMilliseconds);
214 // If the platform timer is being updated by a thread other than the event loop thread,
215 // trigger the event loop thread to recalculate its wait time by posting a no-op event
216 // to the event queue.
217 if (xTaskGetCurrentTaskHandle() != mEventLoopTask)
219 ChipDeviceEvent event;
220 event.Type = DeviceEventType::kNoOp;
221 Impl()->PostEvent(&event);
224 return CHIP_NO_ERROR;
227 template <class ImplClass>
228 void GenericPlatformManagerImpl_FreeRTOS<ImplClass>::PostEventFromISR(const ChipDeviceEvent * event, BaseType_t & yieldRequired)
230 yieldRequired = pdFALSE;
232 if (mChipEventQueue != NULL)
234 if (!xQueueSendFromISR(mChipEventQueue, event, &yieldRequired))
236 ChipLogError(DeviceLayer, "Failed to post event to CHIP Platform event queue");
241 template <class ImplClass>
242 CHIP_ERROR GenericPlatformManagerImpl_FreeRTOS<ImplClass>::_Shutdown(void)
244 return CHIP_ERROR_NOT_IMPLEMENTED;
247 } // namespace Internal
248 } // namespace DeviceLayer
251 #endif // GENERIC_PLATFORM_MANAGER_IMPL_FREERTOS_CPP