Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / src / include / platform / internal / GenericPlatformManagerImpl_FreeRTOS.cpp
1 /*
2  *
3  *    Copyright (c) 2020 Project CHIP Authors
4  *    Copyright (c) 2018 Nest Labs, Inc.
5  *
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
9  *
10  *        http://www.apache.org/licenses/LICENSE-2.0
11  *
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.
17  */
18
19 /**
20  *    @file
21  *          Contains non-inline method definitions for the
22  *          GenericPlatformManagerImpl_FreeRTOS<> template.
23  */
24
25 #ifndef GENERIC_PLATFORM_MANAGER_IMPL_FREERTOS_CPP
26 #define GENERIC_PLATFORM_MANAGER_IMPL_FREERTOS_CPP
27
28 #include <platform/PlatformManager.h>
29 #include <platform/internal/CHIPDeviceLayerInternal.h>
30 #include <platform/internal/GenericPlatformManagerImpl_FreeRTOS.h>
31
32 #include <lib/support/CodeUtils.h>
33
34 // Include the non-inline definitions for the GenericPlatformManagerImpl<> template,
35 // from which the GenericPlatformManagerImpl_FreeRTOS<> template inherits.
36 #include <platform/internal/GenericPlatformManagerImpl.cpp>
37
38 namespace chip {
39 namespace DeviceLayer {
40 namespace Internal {
41
42 // Fully instantiate the generic implementation class in whatever compilation unit includes this file.
43 template class GenericPlatformManagerImpl_FreeRTOS<PlatformManagerImpl>;
44
45 template <class ImplClass>
46 CHIP_ERROR GenericPlatformManagerImpl_FreeRTOS<ImplClass>::_InitChipStack(void)
47 {
48     CHIP_ERROR err = CHIP_NO_ERROR;
49
50     vTaskSetTimeOutState(&mNextTimerBaseTime);
51     mNextTimerDurationTicks = 0;
52     mEventLoopTask          = NULL;
53     mChipTimerActive        = false;
54
55     mChipStackLock = xSemaphoreCreateMutex();
56     if (mChipStackLock == NULL)
57     {
58         ChipLogError(DeviceLayer, "Failed to create CHIP stack lock");
59         ExitNow(err = CHIP_ERROR_NO_MEMORY);
60     }
61
62 #if defined(CHIP_CONFIG_FREERTOS_USE_STATIC_QUEUE) && CHIP_CONFIG_FREERTOS_USE_STATIC_QUEUE
63     mChipEventQueue =
64         xQueueCreateStatic(CHIP_DEVICE_CONFIG_MAX_EVENT_QUEUE_SIZE, sizeof(ChipDeviceEvent), mEventQueueBuffer, &mEventQueueStruct);
65 #else
66     mChipEventQueue = xQueueCreate(CHIP_DEVICE_CONFIG_MAX_EVENT_QUEUE_SIZE, sizeof(ChipDeviceEvent));
67 #endif
68     if (mChipEventQueue == NULL)
69     {
70         ChipLogError(DeviceLayer, "Failed to allocate CHIP event queue");
71         ExitNow(err = CHIP_ERROR_NO_MEMORY);
72     }
73
74     // Call up to the base class _InitChipStack() to perform the bulk of the initialization.
75     err = GenericPlatformManagerImpl<ImplClass>::_InitChipStack();
76     SuccessOrExit(err);
77
78 exit:
79     return err;
80 }
81
82 template <class ImplClass>
83 void GenericPlatformManagerImpl_FreeRTOS<ImplClass>::_LockChipStack(void)
84 {
85     xSemaphoreTake(mChipStackLock, portMAX_DELAY);
86 }
87
88 template <class ImplClass>
89 bool GenericPlatformManagerImpl_FreeRTOS<ImplClass>::_TryLockChipStack(void)
90 {
91     return xSemaphoreTake(mChipStackLock, 0) == pdTRUE;
92 }
93
94 template <class ImplClass>
95 void GenericPlatformManagerImpl_FreeRTOS<ImplClass>::_UnlockChipStack(void)
96 {
97     xSemaphoreGive(mChipStackLock);
98 }
99
100 template <class ImplClass>
101 void GenericPlatformManagerImpl_FreeRTOS<ImplClass>::_PostEvent(const ChipDeviceEvent * event)
102 {
103     if (mChipEventQueue != NULL)
104     {
105         if (!xQueueSend(mChipEventQueue, event, 1))
106         {
107             ChipLogError(DeviceLayer, "Failed to post event to CHIP Platform event queue");
108         }
109     }
110 }
111
112 template <class ImplClass>
113 void GenericPlatformManagerImpl_FreeRTOS<ImplClass>::_RunEventLoop(void)
114 {
115     CHIP_ERROR err;
116     ChipDeviceEvent event;
117
118     VerifyOrDie(mEventLoopTask != NULL);
119
120     // Lock the CHIP stack.
121     Impl()->LockChipStack();
122
123     while (true)
124     {
125         TickType_t waitTime;
126
127         // If one or more CHIP timers are active...
128         if (mChipTimerActive)
129         {
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)
134             {
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;
138
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)
143                 {
144                     ChipLogError(DeviceLayer, "Error handling CHIP timers: %s", ErrorStr(err));
145                 }
146
147                 // When processing the event queue below, do not wait if the queue is empty.  Instead
148                 // immediately loop around and process timers again
149                 waitTime = 0;
150             }
151
152             // If there is still time before the next timer expires, arrange to wait on the event queue
153             // until that timer expires.
154             else
155             {
156                 waitTime = mNextTimerDurationTicks;
157             }
158         }
159
160         // Otherwise no CHIP timers are active, so wait indefinitely for an event to arrive on the event
161         // queue.
162         else
163         {
164             waitTime = portMAX_DELAY;
165         }
166
167         // Unlock the CHIP stack, allowing other threads to enter CHIP while the event loop thread is sleeping.
168         Impl()->UnlockChipStack();
169
170         BaseType_t eventReceived = xQueueReceive(mChipEventQueue, &event, waitTime);
171
172         // Lock the CHIP stack.
173         Impl()->LockChipStack();
174
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)
178         {
179             Impl()->DispatchEvent(&event);
180
181             eventReceived = xQueueReceive(mChipEventQueue, &event, 0);
182         }
183     }
184 }
185
186 template <class ImplClass>
187 CHIP_ERROR GenericPlatformManagerImpl_FreeRTOS<ImplClass>::_StartEventLoopTask(void)
188 {
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);
192 #else
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);
195 #endif
196
197     return (mEventLoopTask != NULL) ? CHIP_NO_ERROR : CHIP_ERROR_NO_MEMORY;
198 }
199
200 template <class ImplClass>
201 void GenericPlatformManagerImpl_FreeRTOS<ImplClass>::EventLoopTaskMain(void * arg)
202 {
203     ChipLogDetail(DeviceLayer, "CHIP task running");
204     static_cast<GenericPlatformManagerImpl_FreeRTOS<ImplClass> *>(arg)->Impl()->RunEventLoop();
205 }
206
207 template <class ImplClass>
208 CHIP_ERROR GenericPlatformManagerImpl_FreeRTOS<ImplClass>::_StartChipTimer(uint32_t aMilliseconds)
209 {
210     mChipTimerActive = true;
211     vTaskSetTimeOutState(&mNextTimerBaseTime);
212     mNextTimerDurationTicks = pdMS_TO_TICKS(aMilliseconds);
213
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)
218     {
219         ChipDeviceEvent event;
220         event.Type = DeviceEventType::kNoOp;
221         Impl()->PostEvent(&event);
222     }
223
224     return CHIP_NO_ERROR;
225 }
226
227 template <class ImplClass>
228 void GenericPlatformManagerImpl_FreeRTOS<ImplClass>::PostEventFromISR(const ChipDeviceEvent * event, BaseType_t & yieldRequired)
229 {
230     yieldRequired = pdFALSE;
231
232     if (mChipEventQueue != NULL)
233     {
234         if (!xQueueSendFromISR(mChipEventQueue, event, &yieldRequired))
235         {
236             ChipLogError(DeviceLayer, "Failed to post event to CHIP Platform event queue");
237         }
238     }
239 }
240
241 template <class ImplClass>
242 CHIP_ERROR GenericPlatformManagerImpl_FreeRTOS<ImplClass>::_Shutdown(void)
243 {
244     return CHIP_ERROR_NOT_IMPLEMENTED;
245 }
246
247 } // namespace Internal
248 } // namespace DeviceLayer
249 } // namespace chip
250
251 #endif // GENERIC_PLATFORM_MANAGER_IMPL_FREERTOS_CPP