/*************************************************************************************************/
|
/*!
|
* \file wsf_os.c
|
*
|
* \brief Software foundation OS main module.
|
*
|
* Copyright (c) 2009-2019 Arm Ltd. All Rights Reserved.
|
*
|
* Copyright (c) 2019-2020 Packetcraft, Inc.
|
*
|
* 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.
|
*/
|
/*************************************************************************************************/
|
|
#ifdef __IAR_SYSTEMS_ICC__
|
#include <intrinsics.h>
|
#endif
|
#include "wsf_types.h"
|
#include "wsf_os.h"
|
#include "wsf_assert.h"
|
#include "wsf_trace.h"
|
#include "wsf_timer.h"
|
#include "wsf_queue.h"
|
#include "wsf_buf.h"
|
#include "wsf_msg.h"
|
#include "wsf_cs.h"
|
|
#if defined(RTOS_CMSIS_RTX) && (RTOS_CMSIS_RTX == 1)
|
#include "cmsis_os2.h"
|
#endif
|
|
/**************************************************************************************************
|
Compile time assert checks
|
**************************************************************************************************/
|
|
WSF_CT_ASSERT(sizeof(uint8_t) == 1);
|
WSF_CT_ASSERT(sizeof(uint16_t) == 2);
|
WSF_CT_ASSERT(sizeof(uint32_t) == 4);
|
|
/**************************************************************************************************
|
Macros
|
**************************************************************************************************/
|
|
/* maximum number of event handlers per task */
|
#ifndef WSF_MAX_HANDLERS
|
#define WSF_MAX_HANDLERS 16
|
#endif
|
|
#if WSF_OS_DIAG == TRUE
|
#define WSF_OS_SET_ACTIVE_HANDLER_ID(id) (WsfActiveHandler = id);
|
#else
|
#define WSF_OS_SET_ACTIVE_HANDLER_ID(id)
|
#endif /* WSF_OS_DIAG */
|
|
#if defined(RTOS_CMSIS_RTX) && (RTOS_CMSIS_RTX == 1)
|
/*! \brief Thread sleep flag */
|
#define WSF_OS_THREAD_SLEEP_WAKEUP_FLAG 0x0001
|
#endif
|
|
/*! \brief OS serivice function number */
|
#define WSF_OS_MAX_SERVICE_FUNCTIONS 3
|
|
/**************************************************************************************************
|
Data Types
|
**************************************************************************************************/
|
|
/*! \brief Task structure */
|
typedef struct
|
{
|
wsfEventHandler_t handler[WSF_MAX_HANDLERS];
|
wsfEventMask_t handlerEventMask[WSF_MAX_HANDLERS];
|
wsfQueue_t msgQueue;
|
volatile wsfTaskEvent_t taskEventMask;
|
uint8_t numHandler;
|
} wsfOsTask_t;
|
|
/*! \brief OS structure */
|
typedef struct
|
{
|
wsfOsTask_t task;
|
WsfOsIdleCheckFunc_t sleepCheckFuncs[WSF_OS_MAX_SERVICE_FUNCTIONS];
|
uint8_t numFunc;
|
} wsfOs_t;
|
|
/**************************************************************************************************
|
Local Variables
|
**************************************************************************************************/
|
|
/*! \brief OS context. */
|
static wsfOs_t wsfOs;
|
|
#if WSF_OS_DIAG == TRUE
|
/*! Active task handler ID. */
|
wsfHandlerId_t WsfActiveHandler;
|
#endif /* WSF_OS_DIAG */
|
|
#if defined(RTOS_CMSIS_RTX) && (RTOS_CMSIS_RTX == 1)
|
static osThreadId_t wsfOsThreadId;
|
#endif
|
|
/*************************************************************************************************/
|
/*!
|
* \brief Lock task scheduling.
|
*/
|
/*************************************************************************************************/
|
uint32_t WsfTaskLock(void)
|
{
|
return PalEnterCs();
|
}
|
|
/*************************************************************************************************/
|
/*!
|
* \brief Unock task scheduling.
|
*/
|
/*************************************************************************************************/
|
void WsfTaskUnlock(uint32_t lock)
|
{
|
PalExitCs(lock);
|
}
|
|
/*************************************************************************************************/
|
/*!
|
* \brief Set an event for an event handler.
|
*
|
* \param handlerId Handler ID.
|
* \param event Event or events to set.
|
*/
|
/*************************************************************************************************/
|
void WsfSetEvent(wsfHandlerId_t handlerId, wsfEventMask_t event)
|
{
|
WSF_CS_INIT(cs);
|
|
WSF_ASSERT(WSF_HANDLER_FROM_ID(handlerId) < WSF_MAX_HANDLERS);
|
|
WSF_TRACE_INFO2("WsfSetEvent handlerId:%u event:%u", handlerId, event);
|
|
uint32_t lock = WSF_CS_ENTER();
|
wsfOs.task.handlerEventMask[WSF_HANDLER_FROM_ID(handlerId)] |= event;
|
wsfOs.task.taskEventMask |= WSF_HANDLER_EVENT;
|
WSF_CS_EXIT(lock);
|
|
/* set event in OS */
|
}
|
|
/*************************************************************************************************/
|
/*!
|
* \brief Set the task used by the given handler as ready to run.
|
*
|
* \param handlerId Event handler ID.
|
* \param event Task event mask.
|
*/
|
/*************************************************************************************************/
|
void WsfTaskSetReady(wsfHandlerId_t handlerId, wsfTaskEvent_t event)
|
{
|
/* Unused parameter */
|
(void)handlerId;
|
|
WSF_CS_INIT(cs);
|
|
uint32_t lock = WSF_CS_ENTER();
|
wsfOs.task.taskEventMask |= event;
|
WSF_CS_EXIT(lock);
|
|
/* set event in OS */
|
}
|
|
/*************************************************************************************************/
|
/*!
|
* \brief Return the message queue used by the given handler.
|
*
|
* \param handlerId Event handler ID.
|
*
|
* \return Task message queue.
|
*/
|
/*************************************************************************************************/
|
wsfQueue_t *WsfTaskMsgQueue(wsfHandlerId_t handlerId)
|
{
|
/* Unused parameter */
|
(void)handlerId;
|
|
return &(wsfOs.task.msgQueue);
|
}
|
|
/*************************************************************************************************/
|
/*!
|
* \brief Set the next WSF handler function in the WSF OS handler array. This function
|
* should only be called as part of the stack initialization procedure.
|
*
|
* \param handler WSF handler function.
|
*
|
* \return WSF handler ID for this handler.
|
*/
|
/*************************************************************************************************/
|
wsfHandlerId_t WsfOsSetNextHandler(wsfEventHandler_t handler)
|
{
|
wsfHandlerId_t handlerId = wsfOs.task.numHandler++;
|
|
WSF_ASSERT(handlerId < WSF_MAX_HANDLERS);
|
|
wsfOs.task.handler[handlerId] = handler;
|
|
return handlerId;
|
}
|
|
/*************************************************************************************************/
|
/*!
|
* \brief Check if WSF is ready to sleep. This function should be called when interrupts
|
* are disabled.
|
*
|
* \return Return TRUE if there are no pending WSF task events set, FALSE otherwise.
|
*/
|
/*************************************************************************************************/
|
bool_t wsfOsReadyToSleep(void)
|
{
|
return (wsfOs.task.taskEventMask == 0);
|
}
|
|
/*************************************************************************************************/
|
/*!
|
* \brief Initialize OS control structure.
|
*
|
* \return None.
|
*/
|
/*************************************************************************************************/
|
void WsfOsInit(void)
|
{
|
memset(&wsfOs, 0, sizeof(wsfOs));
|
|
#if defined(RTOS_CMSIS_RTX) && (RTOS_CMSIS_RTX == 1)
|
osKernelInitialize(); /* Initialize CMSIS-RTOS. */
|
#endif
|
}
|
|
/*************************************************************************************************/
|
/*!
|
* \brief Event dispatched. Designed to be called repeatedly from infinite loop.
|
*/
|
/*************************************************************************************************/
|
void wsfOsDispatcher(void)
|
{
|
wsfOsTask_t *pTask;
|
void *pMsg;
|
wsfTimer_t *pTimer;
|
wsfEventMask_t eventMask;
|
wsfTaskEvent_t taskEventMask;
|
wsfHandlerId_t handlerId;
|
uint8_t i;
|
|
WSF_CS_INIT(cs);
|
|
pTask = &wsfOs.task;
|
|
/* get and then clear task event mask */
|
uint32_t lock = WSF_CS_ENTER();
|
taskEventMask = pTask->taskEventMask;
|
pTask->taskEventMask = 0;
|
WSF_CS_EXIT(lock);
|
|
if (taskEventMask & WSF_MSG_QUEUE_EVENT)
|
{
|
/* handle msg queue */
|
while ((pMsg = WsfMsgDeq(&pTask->msgQueue, &handlerId)) != NULL)
|
{
|
WSF_ASSERT(handlerId < WSF_MAX_HANDLERS);
|
WSF_OS_SET_ACTIVE_HANDLER_ID(handlerId);
|
(*pTask->handler[handlerId])(0, pMsg);
|
WsfMsgFree(pMsg);
|
}
|
}
|
|
if (taskEventMask & WSF_TIMER_EVENT)
|
{
|
/* service timers */
|
while ((pTimer = WsfTimerServiceExpired(0)) != NULL)
|
{
|
WSF_ASSERT(pTimer->handlerId < WSF_MAX_HANDLERS);
|
WSF_OS_SET_ACTIVE_HANDLER_ID(pTimer->handlerId);
|
(*pTask->handler[pTimer->handlerId])(0, &pTimer->msg);
|
}
|
}
|
|
if (taskEventMask & WSF_HANDLER_EVENT)
|
{
|
/* service handlers */
|
for (i = 0; i < WSF_MAX_HANDLERS; i++)
|
{
|
if ((pTask->handlerEventMask[i] != 0) && (pTask->handler[i] != NULL))
|
{
|
lock = WSF_CS_ENTER();
|
eventMask = pTask->handlerEventMask[i];
|
pTask->handlerEventMask[i] = 0;
|
WSF_OS_SET_ACTIVE_HANDLER_ID(i);
|
WSF_CS_EXIT(lock);
|
|
(*pTask->handler[i])(eventMask, NULL);
|
}
|
}
|
}
|
}
|
|
#if defined(RTOS_CMSIS_RTX) && (RTOS_CMSIS_RTX == 1)
|
/*************************************************************************************************/
|
/*!
|
* \brief Idle thread.
|
*
|
* \param pArg Pointer to argument.
|
*/
|
/*************************************************************************************************/
|
void osRtxIdleThread(void *pArg)
|
{
|
bool_t activeFlag = FALSE;
|
|
(void)pArg;
|
|
while (TRUE)
|
{
|
activeFlag = FALSE;
|
|
for (unsigned int i = 0; i < wsfOs.numFunc; i++)
|
{
|
if (wsfOs.sleepCheckFuncs[i])
|
{
|
activeFlag |= wsfOs.sleepCheckFuncs[i]();
|
}
|
}
|
|
if (!activeFlag)
|
{
|
WsfTimerSleep();
|
}
|
osThreadFlagsSet(wsfOsThreadId, WSF_OS_THREAD_SLEEP_WAKEUP_FLAG);
|
}
|
}
|
|
/*************************************************************************************************/
|
/*!
|
* \brief Main thread.
|
*
|
* \param pArg Pointer to argument.
|
*/
|
/*************************************************************************************************/
|
void wsfThread(void *pArg)
|
{
|
(void)pArg;
|
|
while (TRUE)
|
{
|
WsfTimerSleepUpdate();
|
wsfOsDispatcher();
|
osThreadFlagsWait(WSF_OS_THREAD_SLEEP_WAKEUP_FLAG, osFlagsWaitAny, osWaitForever);
|
}
|
}
|
#endif
|
|
/*************************************************************************************************/
|
/*!
|
* \brief Register service check functions.
|
*
|
* \param func Service function.
|
*/
|
/*************************************************************************************************/
|
void WsfOsRegisterSleepCheckFunc(WsfOsIdleCheckFunc_t func)
|
{
|
wsfOs.sleepCheckFuncs[wsfOs.numFunc++] = func;
|
}
|