blob: 5ee09578fd24753f24bc5340ed1bb497b08e6c42 [file] [log] [blame]
/*
*
* Copyright (c) 2018 Nest Labs, Inc.
* 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_FreeRTOS<> template.
*/
#ifndef GENERIC_PLATFORM_MANAGER_IMPL_FREERTOS_IPP
#define GENERIC_PLATFORM_MANAGER_IMPL_FREERTOS_IPP
#include <Weave/DeviceLayer/internal/WeaveDeviceLayerInternal.h>
#include <Weave/DeviceLayer/PlatformManager.h>
#include <Weave/DeviceLayer/FreeRTOS/GenericPlatformManagerImpl_FreeRTOS.h>
// Include the non-inline definitions for the GenericPlatformManagerImpl<> template,
// from which the GenericPlatformManagerImpl_FreeRTOS<> template inherits.
#include <Weave/DeviceLayer/internal/GenericPlatformManagerImpl.ipp>
namespace nl {
namespace Weave {
namespace DeviceLayer {
namespace Internal {
// Fully instantiate the generic implementation class in whatever compilation unit includes this file.
template class GenericPlatformManagerImpl_FreeRTOS<PlatformManagerImpl>;
template<class ImplClass>
WEAVE_ERROR GenericPlatformManagerImpl_FreeRTOS<ImplClass>::_InitWeaveStack(void)
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
vTaskSetTimeOutState(&mNextTimerBaseTime);
mNextTimerDurationTicks = 0;
mEventLoopTask = NULL;
mWeaveTimerActive = false;
mWeaveStackLock = xSemaphoreCreateMutex();
if (mWeaveStackLock == NULL)
{
WeaveLogError(DeviceLayer, "Failed to create Weave stack lock");
ExitNow(err = WEAVE_ERROR_NO_MEMORY);
}
mWeaveEventQueue = xQueueCreate(WEAVE_DEVICE_CONFIG_MAX_EVENT_QUEUE_SIZE, sizeof(WeaveDeviceEvent));
if (mWeaveEventQueue == NULL)
{
WeaveLogError(DeviceLayer, "Failed to allocate Weave event queue");
ExitNow(err = WEAVE_ERROR_NO_MEMORY);
}
// Call up to the base class _InitWeaveStack() to perform the bulk of the initialization.
err = GenericPlatformManagerImpl<ImplClass>::_InitWeaveStack();
SuccessOrExit(err);
exit:
return err;
}
template<class ImplClass>
void GenericPlatformManagerImpl_FreeRTOS<ImplClass>::_LockWeaveStack(void)
{
xSemaphoreTake(mWeaveStackLock, portMAX_DELAY);
}
template<class ImplClass>
bool GenericPlatformManagerImpl_FreeRTOS<ImplClass>::_TryLockWeaveStack(void)
{
return xSemaphoreTake(mWeaveStackLock, 0) == pdTRUE;
}
template<class ImplClass>
void GenericPlatformManagerImpl_FreeRTOS<ImplClass>::_UnlockWeaveStack(void)
{
xSemaphoreGive(mWeaveStackLock);
}
template<class ImplClass>
void GenericPlatformManagerImpl_FreeRTOS<ImplClass>::_PostEvent(const WeaveDeviceEvent * event)
{
if (mWeaveEventQueue != NULL)
{
if (!xQueueSend(mWeaveEventQueue, event, 1))
{
WeaveLogError(DeviceLayer, "Failed to post event to Weave Platform event queue");
}
}
}
template<class ImplClass>
void GenericPlatformManagerImpl_FreeRTOS<ImplClass>::_RunEventLoop(void)
{
WEAVE_ERROR err;
WeaveDeviceEvent event;
VerifyOrDie(mEventLoopTask == NULL);
// Capture the task handle.
mEventLoopTask = xTaskGetCurrentTaskHandle();
// Lock the Weave stack.
Impl()->LockWeaveStack();
while (true)
{
TickType_t waitTime;
// If one or more Weave timers are active...
if (mWeaveTimerActive)
{
// 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.
// IF the timer's expiration time has already arrived...
if (xTaskCheckForTimeOut(&mNextTimerBaseTime, &mNextTimerDurationTicks) == pdTRUE)
{
// Reset the 'timer active' flag. This will be set to true again by _StartWeaveTimer()
// if there are further timers beyond the expired one that are still active.
mWeaveTimerActive = false;
// Call into the system layer to dispatch the callback functions for all timers
// that have expired.
err = SystemLayer.HandlePlatformTimer();
if (err != WEAVE_SYSTEM_NO_ERROR)
{
WeaveLogError(DeviceLayer, "Error handling Weave timers: %s", ErrorStr(err));
}
// When processing the event queue below, do not wait if the queue is empty. Instead
// immediately loop around and process timers again
waitTime = 0;
}
// If there is still time before the next timer expires, arrange to wait on the event queue
// until that timer expires.
else
{
waitTime = mNextTimerDurationTicks;
}
}
// Otherwise no Weave timers are active, so wait indefinitely for an event to arrive on the event
// queue.
else
{
waitTime = portMAX_DELAY;
}
// Unlock the Weave stack, allowing other threads to enter Weave while the event loop thread is sleeping.
Impl()->UnlockWeaveStack();
BaseType_t eventReceived = xQueueReceive(mWeaveEventQueue, &event, waitTime);
// Lock the Weave stack.
Impl()->LockWeaveStack();
// If an event was received, dispatch it. Continue receiving events from the queue and
// dispatching them until the queue is empty.
while (eventReceived == pdTRUE)
{
Impl()->DispatchEvent(&event);
eventReceived = xQueueReceive(mWeaveEventQueue, &event, 0);
}
}
}
template<class ImplClass>
WEAVE_ERROR GenericPlatformManagerImpl_FreeRTOS<ImplClass>::_StartEventLoopTask(void)
{
BaseType_t res;
res = xTaskCreate(EventLoopTaskMain,
WEAVE_DEVICE_CONFIG_WEAVE_TASK_NAME,
WEAVE_DEVICE_CONFIG_WEAVE_TASK_STACK_SIZE / sizeof(StackType_t),
this,
WEAVE_DEVICE_CONFIG_WEAVE_TASK_PRIORITY,
NULL);
return (res == pdPASS) ? WEAVE_NO_ERROR : WEAVE_ERROR_NO_MEMORY;
}
template<class ImplClass>
void GenericPlatformManagerImpl_FreeRTOS<ImplClass>::EventLoopTaskMain(void * arg)
{
WeaveLogDetail(DeviceLayer, "Weave task running");
static_cast<GenericPlatformManagerImpl_FreeRTOS<ImplClass>*>(arg)->Impl()->RunEventLoop();
}
template<class ImplClass>
WEAVE_ERROR GenericPlatformManagerImpl_FreeRTOS<ImplClass>::_StartWeaveTimer(uint32_t aMilliseconds)
{
mWeaveTimerActive = true;
vTaskSetTimeOutState(&mNextTimerBaseTime);
mNextTimerDurationTicks = pdMS_TO_TICKS(aMilliseconds);
// 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 (xTaskGetCurrentTaskHandle() != mEventLoopTask)
{
WeaveDeviceEvent event;
event.Type = DeviceEventType::kNoOp;
Impl()->PostEvent(&event);
}
return WEAVE_NO_ERROR;
}
template<class ImplClass>
void GenericPlatformManagerImpl_FreeRTOS<ImplClass>::PostEventFromISR(const WeaveDeviceEvent * event, BaseType_t & yieldRequired)
{
yieldRequired = pdFALSE;
if (mWeaveEventQueue != NULL)
{
if (!xQueueSendFromISR(mWeaveEventQueue, event, &yieldRequired))
{
WeaveLogError(DeviceLayer, "Failed to post event to Weave Platform event queue");
}
}
}
} // namespace Internal
} // namespace DeviceLayer
} // namespace Weave
} // namespace nl
#endif // GENERIC_PLATFORM_MANAGER_IMPL_FREERTOS_IPP