diff --git a/src/platform/cc13xx_26xx/icall_FreeRTOS.c b/src/platform/cc13xx_26xx/icall_FreeRTOS.c deleted file mode 100644 index 1711f2882986ce..00000000000000 --- a/src/platform/cc13xx_26xx/icall_FreeRTOS.c +++ /dev/null @@ -1,4124 +0,0 @@ -/****************************************************************************** - @file icall_FreeRTOS.c - - @brief Indirect function Call dispatcher implementation on top of OS. - - This implementation uses heapmgr.h to implement a simple heap with low - memory overhead but large processing overhead.
- The size of the heap is determined with HEAPMGR_SIZE macro, which can - be overridden with a compile option. - Note: The ICall layer (e.g. this file) is using TI internal implementation of POSIX. - For now, the ICall layer is not supports using outer POSIX on the application layer. - - Group: WCS, LPC, BTS - Target Device: cc13xx_cc26xx - - ****************************************************************************** - - Copyright (c) 2013-2024, Texas Instruments Incorporated - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - * Neither the name of Texas Instruments Incorporated nor the names of - its contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, - EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - ****************************************************************************** - - - *****************************************************************************/ - -#ifdef FREERTOS -#include -#include -#include "bget.h" -#endif - - -#ifdef FREERTOS -#include -#include -#include -#endif - - -#include -#include -#define Hwi_disable HwiP_disable -#define Hwi_restore HwiP_restore -#define Hwi_disableinterrupt HwiP_disableInterrupt -#define Hwi_enableinterrupt HwiP_enableInterrupt -#define Swi_restore SwiP_restore -#define Swi_disable SwiP_disable -#define BIOS_WAIT_FOREVER (~(0U)) -#define BIOS_NO_WAIT (0U) - -#include "osal.h" -#include "icall.h" -#include "icall_platform.h" -#include -#include - - - -#ifndef ICALL_FEATURE_SEPARATE_IMGINFO -#include -#endif /* ICALL_FEATURE_SEPARATE_IMGINFO */ - - -//typedef uint32_t * Task_Handle; - - -#ifndef Task_self -#define Task_self ICall_taskSelf -#endif - - -#ifndef ICALL_MAX_NUM_ENTITIES -/** - * Maximum number of entities that use ICall, including service entities - * and application entities. - * The value may be overridden by a compile option. - * Note that there are at least, - * Primitive service, Stack services along with potentially generic - * framework service for the stack thread. - */ -#define ICALL_MAX_NUM_ENTITIES 6 -#endif - -#ifndef ICALL_MAX_NUM_TASKS -/** - * Maximum number of threads which include entities. - * The value may be overridden by a compile option. - */ -#define ICALL_MAX_NUM_TASKS 2 -#endif - -/** - * @internal - * Service class value used to indicate an invalid (unused) entry - */ -#define ICALL_SERVICE_CLASS_INVALID_ENTRY 0x0000 - -/** - * @internal - * Service class value used to indicate an entry for an application entity - */ -#define ICALL_SERVICE_CLASS_APPLICATION ICALL_SERVICE_CLASS_MASK - -/** - * @internal - * Primitive service entity ID - */ -#define ICALL_PRIMITIVE_ENTITY_ID 0 - -/** - * @internal - * Accessor macro to get a header field (next) from a message pointer - */ -#define ICALL_MSG_NEXT(_p) (((ICall_MsgHdr *)(_p) - 1)->next) - -/** - * @internal - * Accessor macro to get a header field (dest_id) from a message pointer - */ -#define ICALL_MSG_DEST_ID(_p) (((ICall_MsgHdr *)(_p) - 1)->dest_id) - - -#ifndef ICALL_TIMER_TASK_STACK_SIZE -/** - * @internal - * Timer thread stack size - */ -#define ICALL_TIMER_TASK_STACK_SIZE (512) -#endif //ICALL_TIMER_TASK_STACK_SIZE - -/** - * @internal - * Creation of the synchronous object between application and service - */ - -#ifdef ICALL_EVENTS -#define ICALL_SYNC_HANDLE_CREATE() (Event_create(NULL, NULL)) -#else /* ICALL_EVENTS */ -#define ICALL_SYNC_HANDLE_CREATE() (Semaphore_create(0, NULL, NULL)) -#endif /* ICALL_EVENTS */ - - -/** - * @internal - * post the synchronous object between application and service - */ -#ifdef ICALL_EVENTS -#define ICALL_SYNC_HANDLE_POST(x) (Event_post(x, ICALL_MSG_EVENT_ID)) -#define ICALL_SYNC_HANDLE_POST_WM(x) (Event_post(x, ICALL_WAITMATCH_EVENT_ID)) -#else /* ICALL_EVENTS */ -#define ICALL_SYNC_HANDLE_POST(x) (Semaphore_post(x)) -#define ICALL_SYNC_HANDLE_POST_WM(x) (Semaphore_post(x)) /* Semaphore does not have event ID */ -#endif /* ICALL_EVENTS */ - - -/** - * @internal - * pend for the synchronous object between application and service - */ -#ifdef ICALL_EVENTS -#define ICALL_SYNC_HANDLE_PEND(x, t) (Event_pend(x, 0, ICALL_MSG_EVENT_ID ,t)) -#define ICALL_SYNC_HANDLE_PEND_WM(x, t) (Event_pend(x, 0, ICALL_WAITMATCH_EVENT_ID, t)) -#else /* ICALL_EVENTS */ -#define ICALL_SYNC_HANDLE_PEND(x, t) (Semaphore_pend(x, t)) -#define ICALL_SYNC_HANDLE_PEND_WM(x, t) (Semaphore_pend(x, t)) /* Semaphore does not have event ID */ -#endif /* ICALL_EVENTS */ - -/** - * @internal - * ticks - */ -#define CLOCK_TICKS_PERIOD (10) - - -/** - * @internal - * Data structure used to access critical section - * state variable. - * Without this data structure, C code will violate - * C89 or C99 strict aliasing rule. - */ -typedef union _icall_cs_state_union_t -{ - /** critical section variable as declared in the interface */ - ICall_CSState state; - /** @internal field used to access internal data */ - struct _icall_cs_state_aggr_t - { - /** field to store Swi_disable() return value */ - uint_least16_t swikey; - /** field to store Hwi_disable() return value */ - uint_least16_t hwikey; - } each; -} ICall_CSStateUnion; - -/** - * @internal Primitive service handler function type - */ -typedef ICall_Errno (*ICall_PrimSvcFunc)(ICall_FuncArgsHdr *); - -#ifdef ICALL_FEATURE_SEPARATE_IMGINFO -/* Image information shall be in separate module */ - -/** - * Array of entry function addresses of external images. - * - * Note that function address must be odd number for Thumb mode functions. - */ -extern const ICall_RemoteTaskEntry ICall_imgEntries[]; -/** - * Array of task priorities of external images. - * One task is created per image to start off the image entry function. - * Each element of this array correspond to the task priority of - * each entry function defined in @ref ICall_imgEntries. - */ -extern const int ICall_imgTaskPriorities[]; - -/** - * Array of task stack sizes of external images. - * One task is created per image to start off the image entry function. - * Each element of this array correspond to the task stack size of - * each entry function defined in @ref ICall_imgEntries. - */ -extern const size_t ICall_imgTaskStackSizes[]; - -/** - * Array of custom initialization parameters (pointers). - * Each initialization parameter (pointer) is passed to each corresponding - * image entry function defined in @ref ICall_imgEntries; - */ -extern const void *ICall_imgInitParams[]; - -/** - * Number of external images. - */ -extern const uint_least8_t ICall_numImages; - -#define icall_threadEntries ICall_imgEntries -#define ICall_threadPriorities ICall_imgTaskPriorities -#define ICall_threadStackSizes ICall_imgTaskStackSizes -#define ICall_getInitParams(_i) (ICall_imgInitParams[i]) -#define ICALL_REMOTE_THREAD_COUNT ICall_numImages -#else /* ICALL_FEATURE_SEPARATE_IMGINFO */ -/** - * @internal - * Array of entry function of external images. - */ -static const ICall_RemoteTaskEntry icall_threadEntries[] = ICALL_ADDR_MAPS; - -/** @internal external image count */ -#define ICALL_REMOTE_THREAD_COUNT \ - (sizeof(icall_threadEntries)/sizeof(icall_threadEntries[0])) - -/** @internal thread priorities to be assigned to each remote thread */ -#ifndef BLE_STACK_TASK_PRIORITY -static const int ICall_threadPriorities[] = {ICALL_TASK_PRIORITIES}; -#else -static const int ICall_threadPriorities[] = {BLE_STACK_TASK_PRIORITY}; -#endif - -/** @internal thread stack max depth for each remote thread */ -static const size_t ICall_threadStackSizes[] = ICALL_TASK_STACK_SIZES; - -/** @internal initialization parameter (pointer) for each remote thread */ -#ifdef ICALL_CUSTOM_INIT_PARAMS -static const void *ICall_initParams[] = ICALL_CUSTOM_INIT_PARAMS; -#define ICall_getInitParams(_i) (ICall_initParams[i]) -#else /* ICALL_CUSTOM_INIT_PARAMS */ -#define ICall_getInitParams(_i) NULL -#endif /* ICALL_CUSTOM_INIT_PARAMS */ - -#endif /* ICALL_FEATURE_SEPARATE_IMGINFO */ - -/** @internal message queue */ -typedef void *ICall_MsgQueue; - -/** @internal data structure about a task using ICall module */ -typedef struct _icall_task_entry_t -{ - TaskHandle_t task; - ICall_SyncHandle syncHandle; - ICall_MsgQueue queue; -} ICall_TaskEntry; - -/** @internal data structure about an entity using ICall module */ -typedef struct _icall_entity_entry_t -{ - ICall_ServiceEnum service; - ICall_TaskEntry *task; - ICall_ServiceFunc fn; -} ICall_entityEntry; - -/** @internal storage to track all tasks using ICall module */ -static ICall_TaskEntry ICall_tasks[ICALL_MAX_NUM_TASKS]; - -/** @internal storage to track all entities using ICall module */ -static ICall_entityEntry ICall_entities[ICALL_MAX_NUM_ENTITIES]; - -#ifndef FREERTOS -extern mqd_t g_EventsQueueID; -#endif -/** - * @internal - * Wakeup schedule data structure definition - */ - -#ifdef FREERTOS -void ICALL_Task_restore(UBaseType_t *OriginalParam); -void ICALL_Task_disable(UBaseType_t *OriginalParam); -#else - -void ICALL_Task_restore(struct sched_param *OriginalParam); -void ICALL_Task_disable(struct sched_param *OriginalParam); -#endif -typedef struct _icall_schedule_t -{ - ClockP_Handle clockP; - ICall_TimerCback cback; - void *arg; -} ICall_ScheduleEntry; - - -/* For now critical sections completely disable hardware interrupts - * because they are used from ISRs in MAC layer implementation. - * If MAC layer implementation changes, critical section - * implementation may change to reduce overall interrupt latency. - */ -/* Enter critical section implementation. See header file for comment. */ -ICall_CSState ICall_enterCSImpl(void) -{ - - ICall_CSStateUnion cu; - cu.each.swikey = (uint_least16_t) Swi_disable(); - cu.each.hwikey = (uint_least16_t) Hwi_disable(); - return cu.state; -} -#ifdef FREERTOS -TaskHandle_t ICall_taskSelf(void) -#else -Task_Handle ICall_taskSelf(void) -#endif -{ - - TaskHandle_t task = NULL; -#ifdef FREERTOS - task = (TaskHandle_t) xTaskGetCurrentTaskHandle(); -#else - task = ; -#endif // FREERTOS - return (task); -} - -/* See header file for comment */ -ICall_EnterCS ICall_enterCriticalSection = ICall_enterCSImpl; - -/* leave critical section implementation. See header file for comment */ -void ICall_leaveCSImpl(ICall_CSState key) -{ - ICall_CSStateUnion *cu = (ICall_CSStateUnion *) &key; - Hwi_restore((uint32_t) cu->each.hwikey); - Swi_restore((uint32_t) cu->each.swikey); -} - -/* See header file for comment */ -ICall_LeaveCS ICall_leaveCriticalSection = ICall_leaveCSImpl; - -/* Implementing a simple heap using heapmgr.h template. - * This simple heap depends on critical section implementation - * and hence the template is used after critical section definition. */ -void *ICall_heapMalloc(uint32_t size); -void *ICall_heapRealloc(void *blk, uint32_t size); -void ICall_heapFree(void *blk); - -#define HEAPMGR_INIT ICall_heapInit -#define HEAPMGR_MALLOC ICall_heapMalloc -#define HEAPMGR_FREE ICall_heapFree -#define HEAPMGR_REALLOC ICall_heapRealloc -#define HEAPMGR_GETSTATS ICall_heapGetStats -#define HEAPMGR_MALLOC_LIMITED ICall_heapMallocLimited - -void ICall_heapMgrGetMetrics(uint32_t *pBlkMax, - uint32_t *pBlkCnt, - uint32_t *pBlkFree, - uint32_t *pMemAlo, - uint32_t *pMemMax, - uint32_t *pMemUB); -#ifdef HEAPMGR_METRICS -#define HEAPMGR_GETMETRICS ICall_heapMgrGetMetrics -#endif - -#define HEAPMGR_LOCK() \ - do { ICall_heapCSState = ICall_enterCSImpl(); } while (0) -#define HEAPMGR_UNLOCK() \ - do { ICall_leaveCSImpl(ICall_heapCSState); } while (0) -#define HEAPMGR_IMPL_INIT() -/* Note that a static variable can be used to contain critical section - * state since heapmgr.h template ensures that there is no nested - * lock call. */ - -#if defined(HEAPMGR_CONFIG) && ((HEAPMGR_CONFIG == 0) || (HEAPMGR_CONFIG == 0x80)) -#include -#elif defined(HEAPMGR_CONFIG) && ( (HEAPMGR_CONFIG == 1) || (HEAPMGR_CONFIG == 0x81)) -#include -#elif defined(HEAPMGR_CONFIG) && ( (HEAPMGR_CONFIG == 2) || (HEAPMGR_CONFIG == 0x82)) -#include -#elif defined(FREERTOS) -#include "TI_heap_wrapper.h" -#else -static ICall_CSState ICall_heapCSState; -#include -#endif - -/** - * @internal Searches for a task entry within @ref ICall_tasks. - * @param taskhandle OS task handle - * @return Pointer to task entry when found, or NULL. - */ -static ICall_TaskEntry *ICall_searchTask(TaskHandle_t taskhandle) -{ - size_t i; - ICall_CSState key; - - key = ICall_enterCSImpl(); - for (i = 0; i < ICALL_MAX_NUM_TASKS; i++) - { - if (!ICall_tasks[i].task) - { - /* Empty slot */ - break; - } - if ((TaskHandle_t)taskhandle == (TaskHandle_t)ICall_tasks[i].task) - { - ICall_leaveCSImpl(key); - return &ICall_tasks[i]; - } - } - ICall_leaveCSImpl(key); - return NULL; -} - -/** - * @internal Searches for a task entry within @ref ICall_tasks or - * build an entry if the entry table is empty. - * @param taskhandle OS task handle - * @return Pointer to task entry when found, or NULL. - */ - -static ICall_TaskEntry *ICall_newTask(TaskHandle_t taskhandle) -{ - size_t i; - ICall_CSState key; - - - key = ICall_enterCSImpl(); - for (i = 0; i < ICALL_MAX_NUM_TASKS; i++) - { - if (!ICall_tasks[i].task) - { - /* Empty slot */ - ICall_TaskEntry *taskentry = &ICall_tasks[i]; - taskentry->task = taskhandle; - taskentry->queue = NULL; - -#ifdef FREERTOS - taskentry->syncHandle = xQueueCreate(20, sizeof(uint32_t)); -#endif - - if (taskentry->syncHandle == 0) - { - /* abort */ - ICALL_HOOK_ABORT_FUNC(); - } - - ICall_leaveCSImpl(key); - return taskentry; - } - if (taskhandle == (TaskHandle_t)ICall_tasks[i].task) - { - ICall_leaveCSImpl(key); - return &ICall_tasks[i]; - } - } - ICall_leaveCSImpl(key); - return NULL; -} - -/* See header file for comments. */ -ICall_EntityID ICall_searchServiceEntity(ICall_ServiceEnum service) -{ - size_t i; - ICall_CSState key; - - key = ICall_enterCSImpl(); - for (i = 0; i < ICALL_MAX_NUM_ENTITIES; i++) - { - if (ICall_entities[i].service == ICALL_SERVICE_CLASS_INVALID_ENTRY) - { - /* Empty slot */ - break; - } - if (service == ICall_entities[i].service) - { - ICall_leaveCSImpl(key); - return (ICall_EntityID) i; - } - } - ICall_leaveCSImpl(key); - return ICALL_INVALID_ENTITY_ID; -} - -/** - * @internal Searches for a service entity entry. - * @param service service id - * @return Pointer to entity entry of the service or - * NULL when none found. - */ -static ICall_entityEntry * -ICall_searchService(ICall_ServiceEnum service) -{ - ICall_EntityID entity = ICall_searchServiceEntity(service); - if (entity == ICALL_INVALID_ENTITY_ID) - { - return NULL; - } - return &ICall_entities[entity]; -} - -/* Dispatcher implementation. See ICall_dispatcher declaration - * for comment. */ -static ICall_Errno ICall_dispatch(ICall_FuncArgsHdr *args) -{ - ICall_entityEntry *entity; - - entity = ICall_searchService(args->service); - if (!entity) - { - return ICALL_ERRNO_INVALID_SERVICE; - } - if (!entity->fn) - { - return ICALL_ERRNO_INVALID_FUNCTION; - } - - return entity->fn(args); -} - -/* See header file for comments */ -ICall_Dispatcher ICall_dispatcher = ICall_dispatch; - -/* Static instance of ICall_RemoteTaskArg to pass to - * remote task entry function. - * See header file for comments */ -static const ICall_RemoteTaskArg ICall_taskEntryFuncs = -{ - ICall_dispatch, - ICall_enterCSImpl, - ICall_leaveCSImpl -}; - -/** - * @internal Thread entry function wrapper that complies with - * OS. - * @param arg0 actual entry function - * @param arg1 ignored - */ -TaskHandle_t RemoteTask = NULL; - -//pthread_t RemoteTask; - -struct argsForPosixTaskStart -{ - void *arg0; - void *arg1; -}; -struct argsForPosixTaskStart POSIX_args; - -typedef void (*TaskFunction_t)( void * ); - -static void ICall_taskEntry(void *arg) - -{ - void * arg0 = ((struct argsForPosixTaskStart *)(arg))->arg0; - void * arg1 = ((struct argsForPosixTaskStart *)(arg))->arg1; - - ICall_CSState key; - key = ICall_enterCSImpl(); - if (ICall_newTask(ICall_taskSelf()) == NULL) - { - /* abort */ - ICALL_HOOK_ABORT_FUNC(); - } - ICall_leaveCSImpl(key); - - /* Attempt to yield prior to running task */ - taskYIELD(); - - ICall_RemoteTaskEntry entryfn = (ICall_RemoteTaskEntry) arg0; - - entryfn(&ICall_taskEntryFuncs, (void *) arg1); - - //return NULL; -} - -#ifndef ICALL_JT -/* forward reference */ -static void ICall_initPrim(void); -#endif /* ICALL_JT */ - -/* See header file for comments. */ -void ICall_init(void) -{ - size_t i; - - for (i = 0; i < ICALL_MAX_NUM_TASKS; i++) - { - ICall_tasks[i].task = NULL; - ICall_tasks[i].queue = NULL; - } - for (i = 0; i < ICALL_MAX_NUM_ENTITIES; i++) - { - ICall_entities[i].service = ICALL_SERVICE_CLASS_INVALID_ENTRY; - } - -#ifndef ICALL_JT - /* Initialize primitive service */ - ICall_initPrim(); -#else - /* Initialize heap */ -#ifndef FREERTOS - ICall_heapInit(); -#endif //FREERTOS -#endif -} - - -/* See header file for comments */ -void ICall_createRemoteTasksAtRuntime(ICall_RemoteTask_t *remoteTaskTable, uint8_t nbElems) -{ - size_t i; - /* ICALL_Task_disable is a cheap locking mechanism to lock tasks - * which may attempt to access the service call dispatcher - * till all services are registered. - */ - UBaseType_t OriginalParam; - ICALL_Task_disable(&OriginalParam); - for (i = 0; i < nbElems; i++) - { -#ifdef FREERTOS - BaseType_t xReturned; - - /* Pass the args via external sturct (POSIX use only single arg) */ - POSIX_args.arg0 = (void*)remoteTaskTable[i].startupEntry; - POSIX_args.arg1 = (void*)remoteTaskTable[i].ICall_imgInitParam; - - xReturned = xTaskCreate( - ICall_taskEntry, /* Function that implements the task. */ - "x", /* Text name for the task. */ - remoteTaskTable[i].imgTaskStackSize / sizeof(uint32_t), /* Stack size in words, not bytes. */ - ( void * ) &POSIX_args, /* Parameter passed into the task. */ - remoteTaskTable[i].imgTaskPriority, /* Priority at which the task is created. */ - &RemoteTask ); /* Used to pass out the created task's handle. */ - - if(xReturned == errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY) - { - /* Creation of FreeRTOS task failed */ - while(1); - } - } - ICALL_Task_restore(&OriginalParam); -#endif -} - -/* See header file for comments */ -void ICall_createRemoteTasks(void) -{ - size_t i; - ICall_RemoteTask_t remoteTaskTable[ICALL_REMOTE_THREAD_COUNT]; - - for (i = 0; i < ICALL_REMOTE_THREAD_COUNT; i++) - { - remoteTaskTable[i].imgTaskPriority = ICall_threadPriorities[i]; - remoteTaskTable[i].imgTaskStackSize = ICall_threadStackSizes[i]; - remoteTaskTable[i].startupEntry = icall_threadEntries[i]; - remoteTaskTable[i].ICall_imgInitParam = (void *) ICall_getInitParams(i); - } - ICall_createRemoteTasksAtRuntime(remoteTaskTable, ICALL_REMOTE_THREAD_COUNT); -} - - - -#ifdef FREERTOS -void ICALL_Task_disable(UBaseType_t *OriginalParam) - -#else -void ICALL_Task_disable(struct sched_param *OriginalParam) -#endif -{ - -#ifdef FREERTOS - TaskStatus_t pxTaskStatus; - vTaskGetInfo(ICall_taskSelf(), &pxTaskStatus, pdFALSE, eInvalid); - *OriginalParam = pxTaskStatus.uxCurrentPriority; - - vTaskPrioritySet(ICall_taskSelf(), configMAX_PRIORITIES - 1); -#endif - - -} -#ifdef FREERTOS -void ICALL_Task_restore(UBaseType_t *OriginalParam) -#else -void ICALL_Task_restore(struct sched_param *OriginalParam) -#endif -{ - -#ifdef FREERTOS - vTaskPrioritySet(ICall_taskSelf(), *OriginalParam); - -#else - pthread_t pthreadID = pthread_self(); - pthread_setschedparam(pthreadID, 0, OriginalParam); -#endif -} - - -/* See header file for comments */ -ICall_TaskHandle ICall_getRemoteTaskHandle(uint8 index) -{ - TaskHandle_t *task = NULL; - - - UBaseType_t OriginalParam; - ICALL_Task_disable(&OriginalParam); - - if (index < ICALL_MAX_NUM_TASKS) - { - task = &ICall_tasks[index].task; - } - - ICALL_Task_restore(&OriginalParam); - - return((ICall_TaskHandle)task); -} - -/* Primitive service implementation follows */ - -#ifndef ICALL_JT -/** - * @internal Enrolls a service - * @param args arguments - * @return @ref ICALL_ERRNO_SUCCESS when successful.
- * @ref ICALL_ERRNO_INVALID_PARAMETER when service id is already - * registered by another entity.
- * @ref ICALL_ERRNO_NO_RESOURCE when maximum number of services - * are already registered. - */ -static ICall_Errno ICall_primEnroll(ICall_EnrollServiceArgs *args) -{ - size_t i; - ICall_TaskEntry *taskentry = ICall_newTask(Task_self()); - ICall_CSState key; - - /* Note that certain service does not handle a message - * and hence, taskentry might be NULL. - */ - if (taskentry == NULL) - { - return ICALL_ERRNO_INVALID_PARAMETER; - } - - key = ICall_enterCSImpl(); - for (i = 0; i < ICALL_MAX_NUM_ENTITIES; i++) - { - if (ICall_entities[i].service == ICALL_SERVICE_CLASS_INVALID_ENTRY) - { - /* Use this entry */ - ICall_entities[i].service = args->service; - ICall_entities[i].task = taskentry; - ICall_entities[i].fn = args->fn; - args->entity = (ICall_EntityID) i; - args->msgSyncHdl = taskentry->syncHandle; - ICall_leaveCSImpl(key); - return ICALL_ERRNO_SUCCESS; - } - else if (args->service == ICall_entities[i].service) - { - /* Duplicate service enrollment */ - ICall_leaveCSImpl(key); - return ICALL_ERRNO_INVALID_PARAMETER; - } - } - /* abort */ - ICALL_HOOK_ABORT_FUNC(); - ICall_leaveCSImpl(key); - return ICALL_ERRNO_NO_RESOURCE; - -} - -/** - * @internal Registers an application - * @param args arguments - * @return @ref ICALL_ERRNO_SUCCESS when successful.
- * @ref ICALL_ERRNO_NO_RESOURCE when ran out of resource. - */ -static ICall_Errno ICall_primRegisterApp(ICall_RegisterAppArgs *args) -{ - size_t i; - ICall_TaskEntry *taskentry = ICall_newTask(Task_self()); - ICall_CSState key; - - if (!taskentry) - { - /* abort */ - ICALL_HOOK_ABORT_FUNC(); - return ICALL_ERRNO_NO_RESOURCE; - } - - key = ICall_enterCSImpl(); - for (i = 0; i < ICALL_MAX_NUM_ENTITIES; i++) - { - if (ICall_entities[i].service == ICALL_SERVICE_CLASS_INVALID_ENTRY) - { - /* Use this entry */ - ICall_entities[i].service = ICALL_SERVICE_CLASS_APPLICATION; - ICall_entities[i].task = taskentry; - ICall_entities[i].fn = NULL; - args->entity = (ICall_EntityID) i; - args->msgSyncHdl = taskentry->syncHandle; - ICall_leaveCSImpl(key); - return ICALL_ERRNO_SUCCESS; - } - } - /* abort */ - ICALL_HOOK_ABORT_FUNC(); - ICall_leaveCSImpl(key); - return ICALL_ERRNO_NO_RESOURCE; -} - -/** - * @internal Allocates memory block for a message. - * @param args arguments - */ -static ICall_Errno ICall_primAllocMsg(ICall_AllocArgs *args) -{ - ICall_MsgHdr *hdr = - (ICall_MsgHdr *) ICall_heapMalloc(sizeof(ICall_MsgHdr) + args->size); - - if (!hdr) - { - return ICALL_ERRNO_NO_RESOURCE; - } - hdr->len = args->size; - hdr->next = NULL; - hdr->dest_id = ICALL_UNDEF_DEST_ID; - args->ptr = (void *) (hdr + 1); - return ICALL_ERRNO_SUCCESS; -} - -/** - * @internal Frees the memory block allocated for a message. - * @param args arguments - * @return @ref ICALL_ERRNO_SUCCESS - */ -static ICall_Errno ICall_primFreeMsg(ICall_FreeArgs *args) -{ - ICall_MsgHdr *hdr = (ICall_MsgHdr *) args->ptr - 1; - ICall_heapFree(hdr); - return ICALL_ERRNO_SUCCESS; -} - -/** - * Allocates a memory block. - * Note that this function is for use by ICall implementation. - * - * @param size size in bytes - * @return pointer to the allocated memory block or NULL - */ -void *ICall_mallocImpl(uint_fast16_t size) -{ - return ICall_heapMalloc(size); -} - -/** - * Frees a memory block. - * Note that this function is for use by ICall implementation. - * - * @param ptr pointer to the memory block - */ -void ICall_freeImpl(void *ptr) -{ - ICall_heapFree(ptr); -} - -/** - * @internal Allocates a memory block - * @param args arguments - * @return @ref ICALL_ERRNO_SUCCESS when successful.
- * @ref ICALL_ERRNO_NO_RESOURCE when memory block cannot - * be allocated. - */ -static ICall_Errno ICall_primMalloc(ICall_AllocArgs *args) -{ - args->ptr = ICall_heapMalloc(args->size); - if (args->ptr == NULL) - { - return ICALL_ERRNO_NO_RESOURCE; - } - return ICALL_ERRNO_SUCCESS; -} - -/** - * @internal Frees a memory block - * @param args arguments - * @return @ref ICALL_ERRNO_SUCCESS - */ -static ICall_Errno ICall_primFree(ICall_FreeArgs *args) -{ - ICall_heapFree(args->ptr); - return ICALL_ERRNO_SUCCESS; -} -#endif /* ICALL_JT */ - -/** - * @internal Queues a message to a message queue. - * @param q_ptr message queue - * @param msg_ptr message pointer - */ -static void ICall_msgEnqueue( ICall_MsgQueue *q_ptr, void *msg_ptr ) -{ - void *list; - ICall_CSState key; - - // Hold off interrupts - key = ICall_enterCSImpl(); - - ICALL_MSG_NEXT( msg_ptr ) = NULL; - // If first message in queue - if ( *q_ptr == NULL ) - { - *q_ptr = msg_ptr; - } - else - { - // Find end of queue - for ( list = *q_ptr; ICALL_MSG_NEXT( list ) != NULL; - list = ICALL_MSG_NEXT( list ) ); - - // Add message to end of queue - ICALL_MSG_NEXT( list ) = msg_ptr; - } - - // Re-enable interrupts - ICall_leaveCSImpl(key); -} - -/** - * @internal Dequeues a message from a message queue - * @param q_ptr message queue pointer - * @return Dequeued message pointer or NULL if none. - */ -static void *ICall_msgDequeue( ICall_MsgQueue *q_ptr ) -{ - void *msg_ptr = NULL; - ICall_CSState key; - - // Hold off interrupts - key = ICall_enterCSImpl(); - - if ( *q_ptr != NULL ) - { - // Dequeue message - msg_ptr = *q_ptr; - *q_ptr = ICALL_MSG_NEXT( msg_ptr ); - ICALL_MSG_NEXT( msg_ptr ) = NULL; - ICALL_MSG_DEST_ID( msg_ptr ) = ICALL_UNDEF_DEST_ID; - } - - // Re-enable interrupts - ICall_leaveCSImpl(key); - - return msg_ptr; -} - -/** - * @internal Prepends a list of messages to a message queue - * @param q_ptr message queue pointer - * @param head message list to prepend - */ -static void ICall_msgPrepend( ICall_MsgQueue *q_ptr, ICall_MsgQueue head ) -{ - void *msg_ptr = NULL; - ICall_CSState key; - - // Hold off interrupts - key = ICall_enterCSImpl(); - - if ( head != NULL ) - { - /* Find the end of the queue */ - msg_ptr = head; - while (ICALL_MSG_NEXT( msg_ptr ) != NULL) - { - msg_ptr = ICALL_MSG_NEXT( msg_ptr ); - } - ICALL_MSG_NEXT(msg_ptr) = *q_ptr; - *q_ptr = head; - } - - // Re-enable interrupts - ICall_leaveCSImpl(key); -} - -#ifndef ICALL_JT -/** - * @internal Sends a message to an entity. - * @param args arguments - * @return @ref ICALL_ERRNO_SUCCESS when successful.
- * @ref ICALL_ERRNO_INVALID_PARAMETER when either src - * or dest is not a valid entity id or when - * dest is an entity id of an entity that does - * not receive a message - * (e.g., ICall primitive service entity). - */ -static ICall_Errno ICall_primSend(ICall_SendArgs *args) -{ - ICall_CSState key; - ICall_MsgHdr *hdr = (ICall_MsgHdr *) args->msg - 1; - - if (args->dest.entityId >= ICALL_MAX_NUM_ENTITIES || - args->src >= ICALL_MAX_NUM_ENTITIES) - { - return ICALL_ERRNO_INVALID_PARAMETER; - } - key = ICall_enterCSImpl(); - if (!ICall_entities[args->dest.entityId].task) - { - ICall_leaveCSImpl(key); - return ICALL_ERRNO_INVALID_PARAMETER; - } - - ICall_leaveCSImpl(key); - /* Note that once the entry is valid, - * the value does not change and hence it is OK - * to leave the critical section. - */ - - hdr->srcentity = args->src; - hdr->dstentity = args->dest.entityId; - hdr->format = args->format; - ICall_msgEnqueue(&ICall_entities[args->dest.entityId].task->queue, args->msg); - ICALL_SYNC_HANDLE_POST(ICall_entities[args->dest.entityId].task->syncHandle); - - return ICALL_ERRNO_SUCCESS; -} - -/** - * @internal Retrieves a message, queued to receive queue of the calling thread. - * - * @param args arguments - * @return @ref ICALL_ERRNO_SUCCESS when a message was successfully - * retrieved.
- * @ref ICALL_ERRNO_NOMSG when no message was queued to - * the receive queue at the moment.
- * @ref ICALL_ERRNO_UNKNOWN_THREAD when the calling thread - * does not have a received queue associated with it. - * This happens when neither ICall_enrollService() nor - * ICall_registerApp() was ever called from the calling - * thread. - */ -static ICall_Errno ICall_primFetchMsg(ICall_FetchMsgArgs *args) -{ - Task_Handle taskhandle = Task_self(); - ICall_TaskEntry *taskentry = ICall_searchTask(taskhandle); - ICall_MsgHdr *hdr; - - if (!taskentry) - { - return ICALL_ERRNO_UNKNOWN_THREAD; - } - /* Successful */ - args->msg = ICall_msgDequeue(&taskentry->queue); - - if (args->msg == NULL) - { - return ICALL_ERRNO_NOMSG; - } - hdr = (ICall_MsgHdr *) args->msg - 1; - args->src.entityId = hdr->srcentity; - args->dest = hdr->dstentity; - return ICALL_ERRNO_SUCCESS; -} -#endif /* ICALL_JT */ - - -/** - * @internal - * Transforms and entityId into a serviceId. - * @param entityId entity id - * @param servId pointer to a variable to store - * the resultant service id - * @return @ICALL_ERRNO_SUCCESS if the transformation was successful. - * @ICALL_ERRNO_INVALID_SERVICE if no matching service - * is found for the entity id. - */ -static ICall_Errno ICall_primEntityId2ServiceId(ICall_EntityID entityId, - ICall_ServiceEnum *servId) -{ - if (entityId >= ICALL_MAX_NUM_ENTITIES || - ICall_entities[entityId].service == - ICALL_SERVICE_CLASS_INVALID_ENTRY || - ICall_entities[entityId].service == - ICALL_SERVICE_CLASS_APPLICATION) - { - return ICALL_ERRNO_INVALID_SERVICE; - } - *servId = ICall_entities[entityId].service; - return ICALL_ERRNO_SUCCESS; -} - -#ifndef ICALL_JT -/** - * @internal Transforms and entityId into a serviceId. - * @param args arguments - * @return return values corresponding to those of ICall_entityId2ServiceId() - */ -static ICall_Errno ICall_primE2S(ICall_EntityId2ServiceIdArgs *args) -{ - return ICall_primEntityId2ServiceId(args->entityId, &args->servId); -} - -/** - * @internal Sends a message to a registered server. - * @param args arguments corresponding to those of ICall_sendServiceMsg(). - * @return @ref ICALL_ERRNO_SUCCESS when successful.
- * @ref ICALL_ERRNO_INVALID_SERVICE when the 'dest' - * is unregistered service.
- * @ref ICALL_ERRNO_INVALID_PARAMETER when the 'src' - * is not a valid entity id or when 'dest' is - * is a service that does not receive a message - * (such as ICall primitive service). - */ -static ICall_Errno ICall_primSendServiceMsg(ICall_SendArgs *args) -{ - ICall_EntityID dstentity = ICall_searchServiceEntity(args->dest.servId); - - if (dstentity == ICALL_INVALID_ENTITY_ID) - { - return ICALL_ERRNO_INVALID_SERVICE; - } - args->dest.entityId = dstentity; - return ICall_primSend(args); -} - -/** - * @internal Retrieves a message received at the message queue - * associated with the calling thread. - * - * Note that this function should be used by an application - * which does not expect any message from non-server entity. - * - * @param args arguments corresponding to those of ICall_fetchServiceMsg() - * @return @ref ICALL_ERRNO_SUCCESS when the operation was successful - * and a message was retrieved.
- * @ref ICALL_ERRNO_NOMSG when there is no queued message - * at the moment.
- * @ref ICALL_ERRNO_CORRUPT_MSG when a message queued in - * front of the thread's receive queue was not sent by - * a server. Note that in this case, the message is - * not retrieved but thrown away.
- * @ref ICALL_ERRNO_UNKNOWN_THREAD when this function is - * called from a thread which has not registered - * an entity, either through ICall_enrollService() - * or through ICall_registerApp(). - */ -static ICall_Errno ICall_primFetchServiceMsg(ICall_FetchMsgArgs *args) -{ - ICall_ServiceEnum servId; - ICall_Errno errno = ICall_primFetchMsg(args); - if (errno == ICALL_ERRNO_SUCCESS) - { - if (ICall_primEntityId2ServiceId(args->src.entityId, &servId) != - ICALL_ERRNO_SUCCESS) - { - /* Source entity ID cannot be translated to service id */ - ICall_freeMsg(args->msg); - return ICALL_ERRNO_CORRUPT_MSG; - } - args->src.servId = servId; - -#ifdef ICALL_EVENTS - /* - * Because Events are binary flags, the task's queue must be checked for - * any remaining messages. If there are the ICall event flag must be - * re-posted due to it being cleared on the last pend. - */ - ICall_primRepostSync(); -#endif //ICALL_EVENTS - } - return errno; -} -#endif /* ICALL_JT */ -/** - * @internal - * Converts milliseconds to number of ticks. - * @param msecs milliseconds - * @param ticks pointer to a variable to store the resultant number of ticks - * @return @ref ICALL_ERRNO_SUCCESS when successful
- * @ref ICALL_ERRNO_INVALID_PARAMETER when conversion failed - * as the input goes out of range for the output data type. - */ -static ICall_Errno ICall_msecs2Ticks(uint_fast32_t msecs, uint32_t *ticks) -{ - uint_fast64_t intermediate = msecs; - - /*convert to microSec*/ - intermediate *= 1000; - /*divide with the ticks perios*/ - intermediate /= ICall_getTickPeriod(); - if (intermediate >= ((uint_fast64_t) 1 << (sizeof(uint32_t)*8 - 1))) - { - /* Out of range. - * Note that we use only half of the range so that client can - * determine whether the time has passed or time has yet to come. - */ - return ICALL_ERRNO_INVALID_PARAMETER; - } - *ticks = (uint32_t) intermediate; - return ICALL_ERRNO_SUCCESS; -} - -#ifndef ICALL_JT -/** - * @internal - * Waits for a signal to the synchronization object associated with the calling - * thread. - * - * Note that the synchronization object associated with a thread is signaled - * when a message is queued to the message receive queue of the thread - * or when ICall_signal() function is called onto the synchronization object. - * - * @param args arguments corresponding to those of ICall_wait(). - * @return @ref ICALL_ERRNO_SUCCESS when the synchronization object is - * signaled.
- * @ref ICALL_ERRNO_TIMEOUT when designated timeout period - * has passed since the call of the function without - * the synchronization object being signaled.
- * @ref ICALL_ERRNO_INVALID_PARAMETER when the milliseconds - * is greater than the value of ICall_getMaxMSecs(). - */ -static ICall_Errno ICall_primWait(ICall_WaitArgs *args) -{ - Task_Handle taskhandle = Task_self(); - ICall_TaskEntry *taskentry = ICall_searchTask(taskhandle); - uint32_t timeout; - - { - BIOS_ThreadType threadtype = BIOS_getThreadType(); - - if (threadtype == BIOS_ThreadType_Hwi || - threadtype == BIOS_ThreadType_Swi) - { - /* Blocking call is not allowed from Hwi or Swi. - * Note that though theoretically, Swi or lower priority Hwi may block - * on an event to be generated by a higher priority Hwi, it is not a - * safe practice and hence it is disabled. - */ - return ICALL_ERRNO_UNKNOWN_THREAD; - } - } - - if (!taskentry) - { - return ICALL_ERRNO_UNKNOWN_THREAD; - } - /* Successful */ - if (args->milliseconds == 0) - { - timeout = BIOS_NO_WAIT; - } - else if (args->milliseconds == ICALL_TIMEOUT_FOREVER) - { - timeout = BIOS_WAIT_FOREVER; - } - else - { - /* Convert milliseconds to number of ticks */ - ICall_Errno errno = ICall_msecs2Ticks(args->milliseconds, &timeout); - if (errno != ICALL_ERRNO_SUCCESS) - { - return errno; - } - } - - if (ICALL_SYNC_HANDLE_PEND(taskentry->syncHandle, timeout)) - { - return ICALL_ERRNO_SUCCESS; - } - - return ICALL_ERRNO_TIMEOUT; -} - -/** - * @internal signals a synchronziation object. - * @param args arguments corresponding to those of ICall_signal() - * @return return value corresponding to those of ICall_signal() - */ -static ICall_Errno ICall_primSignal(ICall_SignalArgs *args) -{ - ICALL_SYNC_HANDLE_POST(args->syncHandle); - return ICALL_ERRNO_SUCCESS; -} - -/** - * @internal aborts program - * @param args arguments corresponding to those of ICall_abort() - * @return return value corresponding to those of ICall_abort() - */ -static ICall_Errno ICall_primAbort(ICall_FuncArgsHdr *args) -{ - ICALL_HOOK_ABORT_FUNC(); - return ICALL_ERRNO_SUCCESS; -} - -/** - * @internal Enables an interrupt. - * @param args arguments corresponding to those of ICall_enableint() - * @return return values corresponding to those of ICall_enableint() - */ -static ICall_Errno ICall_primEnableint(ICall_intNumArgs *args) -{ - Hwi_enableinterrupt(args->intnum); - return ICALL_ERRNO_SUCCESS; -} - -/** - * @internal Disables an interrupt. - * @param args arguments corresponding to those of ICall_disableint() - * @return return values corresponding to those of ICall_disableint() - */ -static ICall_Errno ICall_primDisableint(ICall_intNumArgs *args) -{ - Hwi_disableinterrupt(args->intnum); - return ICALL_ERRNO_SUCCESS; -} - -/** - * @internal Enables master interrupt and context switching. - * @param args arguments corresponding to those of ICall_enableMint() - * @return return values corresponding to those of ICall_enableMint() - */ -static ICall_Errno ICall_primEnableMint(ICall_FuncArgsHdr *args) -{ - Hwi_enable(); - Swi_enable(); - return ICALL_ERRNO_SUCCESS; -} - -/** - * @internal Disables master interrupt and context switching. - * @param args arguments corresponding to those of ICall_disableMint() - * @return return values corresponding to those of ICall_disableMint() - */ -static ICall_Errno ICall_primDisableMint(ICall_FuncArgsHdr *args) -{ - Swi_disable(); - Hwi_disable(); - return ICALL_ERRNO_SUCCESS; -} - -/** - * @internal registers an interrupt service routine - * @param args arguments corresponding to those of ICall_registerISR() - * @return return values corresponding to those of ICall_registerISR() - */ -static ICall_Errno ICall_primRegisterISR(ICall_RegisterISRArgs *args) -{ - Hwi_Params hwiParams; - - Hwi_Params_init(&hwiParams); - hwiParams.priority = 0xE0; // default all registered ints to lowest priority - - if (Hwi_create( args->intnum, - (void (*)((void *)))args->isrfunc, - &hwiParams, - NULL) == NULL) - { - ICALL_HOOK_ABORT_FUNC(); - return ICALL_ERRNO_NO_RESOURCE; - } - return ICALL_ERRNO_SUCCESS; -} - -/** - * @internal registers an interrupt service routine - * @param args arguments corresponding to those of ICall_registerISR_Ext() - * @return return values corresponding to those of ICall_registerISR_ext() - */ -static ICall_Errno ICall_primRegisterISR_Ext(ICall_RegisterISRArgs_Ext *args) -{ - Hwi_Params hwiParams; - - Hwi_Params_init(&hwiParams); - hwiParams.priority = args->intPriority; - - if (Hwi_create( args->intnum, - (void (*)((void *)))args->isrfunc, - &hwiParams, - NULL) == NULL) - { - ICALL_HOOK_ABORT_FUNC(); - return ICALL_ERRNO_NO_RESOURCE; - } - return ICALL_ERRNO_SUCCESS; -} - -/** - * @internal Gets tick counter value - * @param args arguments corresponding to those of ICall_getTicks() - * @return return values corresponding to those of ICall_getTicks() - */ -static ICall_Errno ICall_primGetTicks(ICall_Getuint32_tArgs *args) -{ - args->value = Clock_getTicks(); - return ICALL_ERRNO_SUCCESS; -} -#endif /* ICALL_JT */ - -/** - * @internal - * Clock event handler function. - * This function is used to implement the wakeup scheduler. - * - * @param arg an @ref ICall_ScheduleEntry - */ - -static void ICall_clockFunc(uintptr_t arg) -{ - ICall_ScheduleEntry *entry = (ICall_ScheduleEntry *) arg; - - entry->cback(entry->arg); -} - -#ifndef ICALL_JT -/** - * @internal - * Set up or restart a timer. - * - * @param args arguments corresponding to those of ICall_setTimer() - * @return @ref ICALL_ERRNO_SUCCESS when successful;
- * @ref ICALL_ERRNO_INVALID_PARAMETER if timer designated by the - * timer ID value was not set up before. - * @ref ICALL_ERRNO_NO_RESOURCE when ran out of resource. - * Check ICall heap size and OS heap size if this happens. - */ -static ICall_Errno ICall_primSetTimer(ICall_SetTimerArgs *args) -{ - ICall_ScheduleEntry *entry; - - if (args->timerid == ICALL_INVALID_TIMER_ID) - { - Clock_Params params; - - /* Create a new timer */ - entry = ICall_heapMalloc(sizeof(ICall_ScheduleEntry)); - if (entry == NULL) - { - /* allocation failed */ - return ICALL_ERRNO_NO_RESOURCE; - } - Clock_Params_init(¶ms); - params.startFlag = FALSE; - params.period = 0; - params.arg = ((void *)) entry; - entry->clock = Clock_create(ICall_clockFunc, - args->timeout, - ¶ms, NULL); - if (!entry->clock) - { - /* abort */ - ICall_abort(); - ICall_heapFree(entry); - return ICALL_ERRNO_NO_RESOURCE; - } - entry->cback = args->cback; - entry->arg = args->arg; - args->timerid = (ICall_TimerID) entry; - } - else - { - ICall_CSState key; - - entry = (ICall_ScheduleEntry *) args->timerid; - - /* Critical section is entered to disable interrupts that might cause call - * to callback due to race condition */ - key = ICall_enterCriticalSection(); - Clock_stop(entry->clock); - entry->arg = args->arg; - ICall_leaveCriticalSection(key); - } - - Clock_setTimeout(entry->clock, args->timeout); - Clock_start(entry->clock); - - return ICALL_ERRNO_SUCCESS; -} - -/** - * @internal - * Set up or restart a timer. - * - * @param args arguments corresponding to those of ICall_setTimerMSecs() - * @return @ref ICALL_ERRNO_SUCCESS when successful;
- * @ref ICALL_ERRNO_INVALID_PARAMETER when msecs is greater than - * maximum value supported. - * @ref ICALL_ERRNO_NO_RESOURCE when ran out of resource. - * Check ICall heap size and OS heap size if this happens. - */ -static ICall_Errno ICall_primSetTimerMSecs(ICall_SetTimerArgs *args) -{ - uint32_t ticks; - /* Convert to tick time */ - ICall_Errno errno = ICall_msecs2Ticks(args->timeout, &ticks); - - if (errno != ICALL_ERRNO_SUCCESS) - { - return errno; - } - args->timeout = ticks; - return ICall_primSetTimer(args); -} - -/** - * @internal - * Stops a timer. - * - * @param args arguments corresponding to those of ICall_stopTimer() - * - * @return @ref ICALL_ERRNO_SUCCESS when successful;
- * @ref ICALL_ERRNO_INVALID_PARAMETER - * if id is @ref ICALL_INVALID_TIMER_ID. - */ -static ICall_Errno ICall_primStopTimer(ICall_StopTimerArgs *args) -{ - ICall_ScheduleEntry *entry = (ICall_ScheduleEntry *) args->timerid; - - if (args->timerid == ICALL_INVALID_TIMER_ID) - { - return ICALL_ERRNO_INVALID_PARAMETER; - } - - Clock_stop(entry->clock); - return ICALL_ERRNO_SUCCESS; -} - -/** - * @internal Gets tick period - * @param args arguments corresponding to those of ICall_getTickPeriod() - * @return return values corresponding to those of ICall_getTickPeriod() - */ -static ICall_Errno ICall_primGetTickPeriod(ICall_Getuint32_tArgs *args) -{ - args->value = Clock_tickPeriod; - return ICALL_ERRNO_SUCCESS; -} - -/** - * @internal Gets maximum period supported - * @param args arguments corresponding to those of ICall_getMaxMSecs() - * @return return values corresponding to those of ICall_getMaxMSecs() - */ -static ICall_Errno ICall_primGetMaxMSecs(ICall_Getuint32_tArgs *args) -{ - uint_fast64_t tmp = ((uint_fast64_t) 0x7ffffffful) * Clock_tickPeriod; - tmp /= 1000; - if (tmp >= 0x80000000ul) - { - tmp = 0x7ffffffful; - } - args->value = (uint_least32_t) tmp; - return ICALL_ERRNO_SUCCESS; -} - -/** - * @internal - * Waits for a message that matches comparison - * - * @param args arguments corresponding to those of ICall_waitMatch(). - * @return @ref ICALL_ERRNO_SUCCESS when the synchronization object is - * signaled.
- * @ref ICALL_ERRNO_TIMEOUT when designated timeout period - * has passed since the call of the function without - * the semaphore being signaled.
- * @ref ICALL_ERRNO_INVALID_PARAMETER when the milliseconds - * is greater than the value of ICall_getMaxMSecs(). - */ -static ICall_Errno ICall_primWaitMatch(ICall_WaitMatchArgs *args) -{ - Task_Handle taskhandle = Task_self(); - ICall_TaskEntry *taskentry = ICall_searchTask(taskhandle); - ICall_MsgQueue prependQueue = NULL; -#ifndef ICALL_EVENTS - uint_fast16_t consumedCount = 0; -#endif - uint32_t timeout; - uint_fast32_t timeoutStamp; - ICall_Errno errno; - - { - BIOS_ThreadType threadtype = BIOS_getThreadType(); - - if (threadtype == BIOS_ThreadType_Hwi || - threadtype == BIOS_ThreadType_Swi) - { - /* Blocking call is not allowed from Hwi or Swi. - * Note that though theoretically, Swi or lower priority Hwi may block - * on an event to be generated by a higher priority Hwi, it is not a - * safe practice and hence it is disabled. - */ - return ICALL_ERRNO_UNKNOWN_THREAD; - } - } - - if (!taskentry) - { - return ICALL_ERRNO_UNKNOWN_THREAD; - } - /* Successful */ - if (args->milliseconds == 0) - { - timeout = BIOS_NO_WAIT; - } - else if (args->milliseconds == ICALL_TIMEOUT_FOREVER) - { - timeout = BIOS_WAIT_FOREVER; - } - else - { - /* Convert milliseconds to number of ticks */ - errno = ICall_msecs2Ticks(args->milliseconds, &timeout); - if (errno != ICALL_ERRNO_SUCCESS) - { - return errno; - } - } - - errno = ICALL_ERRNO_TIMEOUT; - timeoutStamp = Clock_getTicks() + timeout; - while (ICALL_SYNC_HANDLE_PEND(taskentry->syncHandle, timeout)) - { - ICall_FetchMsgArgs fetchArgs; - ICall_ServiceEnum servId; - errno = ICall_primFetchMsg(&fetchArgs); - if (errno == ICALL_ERRNO_SUCCESS) - { - if (ICall_primEntityId2ServiceId(fetchArgs.src.entityId, &servId) == - ICALL_ERRNO_SUCCESS) - { - if (args->matchFn(servId, fetchArgs.dest, fetchArgs.msg)) - { - /* Matching message found*/ - args->servId = servId; - args->dest = fetchArgs.dest; - args->msg = fetchArgs.msg; - errno = ICALL_ERRNO_SUCCESS; - break; - } - } - /* Message was received but it wasn't expected one. - * Add to the prepend queue */ - ICall_msgEnqueue(&prependQueue, fetchArgs.msg); -#ifdef ICALL_EVENTS - /* Event are binary semaphore, so if several messsages are posted while - * we are processing one, it's possible that some of them are 'missed' and - * not processed. Sending a event to ourself force this loop to run until - * all the messages in the queue are processed. - */ - ICALL_SYNC_HANDLE_POST(taskentry->syncHandle); -#endif - } - - /* Prepare for timeout exit */ - errno = ICALL_ERRNO_TIMEOUT; - -#ifndef ICALL_EVENTS - /* Keep the decremented semaphore count */ - consumedCount++; -#endif /* ICALL_EVENTS */ - if (timeout != BIOS_WAIT_FOREVER && - timeout != BIOS_NO_WAIT) - { - /* Readjust timeout */ - uint32_t newTimeout = timeoutStamp - Clock_getTicks(); - if (newTimeout == 0 || newTimeout > timeout) - { - break; - } - timeout = newTimeout; - } - } - -#ifdef ICALL_EVENTS - /* - * Because Events are binary semaphores, the task's queue must be checked for - * any remaining messages. If there are, the ICall event flag must be - * re-posted due to it being cleared on the last pend. - */ - ICall_primRepostSync(); -#endif //ICALL_EVENTS - - /* Prepend retrieved irrelevant messages */ - ICall_msgPrepend(&taskentry->queue, prependQueue); -#ifndef ICALL_EVENTS - /* Re-increment the consumed semaphores */ - for (; consumedCount > 0; consumedCount--) - { - Semaphore_post(taskentry->syncHandle); - } -#endif /* ICALL_EVENTS */ - return errno; -} - -/** - * @internal - * Retrieves an entity ID of an entity associated with the calling thread. - * - * @param args arguments corresponding to those of ICall_getEntityId(). - * @return @ref ICALL_ERRNO_SUCCESS when successful.
- * @ref ICALL_ERRNO_UNKNOWN_THREAD when no entity was associated - * with the calling thread. - */ -static ICall_Errno ICall_primGetEntityId(ICall_GetEntityIdArgs *args) -{ - Task_Handle taskhandle = Task_self(); - ICall_CSState key; - size_t i; - - { - BIOS_ThreadType threadtype = BIOS_getThreadType(); - - if (threadtype == BIOS_ThreadType_Hwi || - threadtype == BIOS_ThreadType_Swi) - { - return ICALL_ERRNO_UNKNOWN_THREAD; - } - } - - key = ICall_enterCSImpl(); - for (i = 0; i < ICALL_MAX_NUM_ENTITIES; i++) - { - if (ICall_entities[i].service == ICALL_SERVICE_CLASS_INVALID_ENTRY) - { - /* Not found */ - break; - } - if (ICall_entities[i].task->task == taskhandle) - { - /* Found */ - args->entity = i; - ICall_leaveCSImpl(key); - return ICALL_ERRNO_SUCCESS; - } - } - ICall_leaveCSImpl(key); - return ICALL_ERRNO_UNKNOWN_THREAD; -} - -/** - * @internal - * Checks whether the calling thread provides the designated service. - * - * @param args arguments corresponding to those of ICall_threadServes(). - * @return @ref ICALL_ERRNO_SUCCESS when successful.
- * @ref ICALL_ERRNO_UNKNOWN_THREAD when the calling thread is - * unrecognized. - * @ref ICALL_ERRNO_INVALID_SERVICE if the service id is not enrolled - * by any thread. - */ -static ICall_Errno ICall_primThreadServes(ICall_ThreadServesArgs *args) -{ - Task_Handle taskhandle; - ICall_CSState key; - size_t i; - - { - BIOS_ThreadType threadtype = BIOS_getThreadType(); - - if (threadtype == BIOS_ThreadType_Hwi || - threadtype == BIOS_ThreadType_Swi) - { - return ICALL_ERRNO_UNKNOWN_THREAD; - } - } - - taskhandle = Task_self(); - - key = ICall_enterCSImpl(); - for (i = 0; i < ICALL_MAX_NUM_ENTITIES; i++) - { - if (ICall_entities[i].service == ICALL_SERVICE_CLASS_INVALID_ENTRY) - { - /* Not found */ - break; - } - else if (ICall_entities[i].service == args->servId) - { - args->result = (uint_fast8_t) - (ICall_entities[i].task->task == taskhandle); - ICall_leaveCSImpl(key); - return ICALL_ERRNO_SUCCESS; - } - } - ICall_leaveCSImpl(key); - return ICALL_ERRNO_INVALID_SERVICE; -} - -/** - * @internal - * Creates an RTOS task. - * - * @param args arguments corresponding to those of ICall_createTask(). - * @return @ref ICALL_ERRNO_SUCCESS when successful.
- * @ref ICALL_ERRNO_NO_RESOURCE when task creation failed. - */ -static ICall_Errno ICall_primCreateTask(ICall_CreateTaskArgs *args) -{ - /* Task_Params is a huge structure. - * To reduce stack usage, heap is used instead. - * This implies that ICall_createTask() must be called before heap - * space may be exhausted. - */ - Task_Params *params = (Task_Params *) ICall_heapMalloc(sizeof(Task_Params)); - Task_Handle task; - - if (params == NULL) - { - return ICALL_ERRNO_NO_RESOURCE; - } - - Task_Params_init(params); - params->priority = args->priority; - params->stackSize = args->stacksize; - params->arg0 = args->arg; - - task = Task_create((Task_FuncPtr) args->entryfn, params, NULL); - ICall_heapFree(params); - - if (task == NULL) - { - return ICALL_ERRNO_NO_RESOURCE; - } - return ICALL_ERRNO_SUCCESS; -} -#endif /* ICALL_JT */ - -#ifdef ICALL_RTOS_EVENT_API -/** - * @internal - * Creates an event. - * - * @param args arguments corresponding to those of ICall_createEvent(). - * @return @ref ICALL_ERRNO_SUCCESS when successful.
- * @ref ICALL_ERRNO_NO_RESOURCE when task creation failed. - */ -static ICall_Errno ICall_primCreateEvent(ICall_CreateEventArgs *args) -{ - args->event = Event_create(NULL, NULL); - - if (args->event == NULL) - { - return ICALL_ERRNO_NO_RESOURCE; - } - return ICALL_ERRNO_SUCCESS; -} -#endif /* ICALL_RTOS_EVENT_API */ -#ifdef ICALL_RTOS_SEMAPHORE_API -/** - * @internal - * Creates a semaphore. - * - * @param args arguments corresponding to those of ICall_createSemaphore(). - * @return @ref ICALL_ERRNO_SUCCESS when successful.
- * @ref ICALL_ERRNO_NO_RESOURCE when task creation failed. - */ -static ICall_Errno ICall_primCreateSemaphore(ICall_CreateSemaphoreArgs *args) -{ - /* Semaphore_Params is a huge structure. - * To reduce stack usage, heap is used instead. - * This implies that ICall_createSemaphore() must be called before heap - * space may be exhausted. - */ - Semaphore_Params *semParams = - (Semaphore_Params *) ICall_heapMalloc(sizeof(Semaphore_Params)); - - if (semParams == NULL) - { - return ICALL_ERRNO_NO_RESOURCE; - } - - Semaphore_Params_init(semParams); - if (args->mode == ICALL_SEMAPHORE_MODE_BINARY) - { - semParams->mode = Semaphore_Mode_BINARY; - } - - args->sem = Semaphore_create(args->initcount, semParams, NULL); - ICall_heapFree(semParams); - - if (args->sem == NULL) - { - return ICALL_ERRNO_NO_RESOURCE; - } - return ICALL_ERRNO_SUCCESS; -} -#endif /* ICALL_RTOS_SEMAPHORE_API */ -#ifdef ICALL_RTOS_EVENT_API -/** - * @internal - * Waits on a ICALL_MSG_EVENT_ID. - * - * @param args arguments corresponding to those of ICall_waitEvent(). - * @return @ref ICALL_ERRNO_SUCCESS when successful.
- * @ref ICALL_ERRNO_TIMEOUT when timeout occurred. - */ -static ICall_Errno ICall_primWaitEvent(ICall_WaitEventArgs *args) -{ - uint32_t timeout; - - if (args->milliseconds == 0) - { - timeout = BIOS_NO_WAIT; - } - else if (args->milliseconds == ICALL_TIMEOUT_FOREVER) - { - timeout = BIOS_WAIT_FOREVER; - } - else - { - ICall_Errno errno = ICall_msecs2Ticks(args->milliseconds, &timeout); - if (errno != ICALL_ERRNO_SUCCESS) - { - return errno; - } - } - - if (Event_pend(args->event, 0, ICALL_MSG_EVENT_ID, timeout)) - { - return ICALL_ERRNO_SUCCESS; - } - return ICALL_ERRNO_TIMEOUT; -} -#endif /* ICALL_RTOS_EVENT_API */ - -#ifdef ICALL_RTOS_SEMAPHORE_API -/** - * @internal - * Waits on a semaphore. - * - * @param args arguments corresponding to those of ICall_waitSemaphore(). - * @return @ref ICALL_ERRNO_SUCCESS when successful.
- * @ref ICALL_ERRNO_TIMEOUT when timeout occurred. - */ -static ICall_Errno ICall_primWaitSemaphore(ICall_WaitSemaphoreArgs *args) -{ - uint32_t timeout; - - if (args->milliseconds == 0) - { - timeout = BIOS_NO_WAIT; - } - else if (args->milliseconds == ICALL_TIMEOUT_FOREVER) - { - timeout = BIOS_WAIT_FOREVER; - } - else - { - ICall_Errno errno = ICall_msecs2Ticks(args->milliseconds, &timeout); - if (errno != ICALL_ERRNO_SUCCESS) - { - return errno; - } - } - if (Semaphore_pend(args->sem, timeout)) - { - return ICALL_ERRNO_SUCCESS; - } - return ICALL_ERRNO_TIMEOUT; -} -#endif /* ICALL_RTOS_SEMAPHORE_API */ - -#ifdef ICALL_RTOS_SEMAPHORE_API -/** - * @internal signals a semaphore - * @param args arguments corresponding to those of ICall_signal() - * @return return value corresponding to those of ICall_signal() - */ -static ICall_Errno ICall_primPostSemaphore(ICall_SignalArgs *args) -{ - Semaphore_post(args->syncHandle); - return ICALL_ERRNO_SUCCESS; -} -#endif /* ICALL_RTOS_EVENT_API */ -#ifdef ICALL_RTOS_EVENT_API -/** - * @internal signals an event - * @param args arguments corresponding to those of ICall_signal() - * @return return value corresponding to those of ICall_signal() - */ -static ICall_Errno ICall_primPostEvent(ICall_SignalEventsArgs *args) -{ - Event_post(args->syncHandle, args->events); - return ICALL_ERRNO_SUCCESS; -} -#endif /* ICALL_RTOS_EVENT_API */ -/** - * @internal Primitive service function ID to handler function map - */ -#ifndef ICALL_JT -static const struct _icall_primsvcfunc_map_entry_t -{ -#ifdef COVERAGE_TEST - size_t id; -#endif /* COVERAGE_TEST */ - ICall_PrimSvcFunc func; -} ICall_primSvcFuncs[] = -{ - { -#ifdef COVERAGE_TEST - ICALL_PRIMITIVE_FUNC_ENROLL, -#endif /* COVERAGE_TEST */ - (ICall_PrimSvcFunc) ICall_primEnroll - }, - - { -#ifdef COVERAGE_TEST - ICALL_PRIMITIVE_FUNC_REGISTER_APP, -#endif /* COVERAGE_TEST */ - (ICall_PrimSvcFunc) ICall_primRegisterApp - }, - - { -#ifdef COVERAGE_TEST - ICALL_PRIMITIVE_FUNC_MSG_ALLOC, -#endif /* COVERAGE_TEST */ - (ICall_PrimSvcFunc) ICall_primAllocMsg - }, - - { -#ifdef COVERAGE_TEST - ICALL_PRIMITIVE_FUNC_MSG_FREE, -#endif /* COVERAGE_TEST */ - (ICall_PrimSvcFunc) ICall_primFreeMsg - }, - - { -#ifdef COVERAGE_TEST - ICALL_PRIMITIVE_FUNC_MALLOC, -#endif /* COVERAGE_TEST */ - (ICall_PrimSvcFunc) ICall_primMalloc - }, - - { -#ifdef COVERAGE_TEST - ICALL_PRIMITIVE_FUNC_FREE, -#endif /* COVERAGE_TEST */ - (ICall_PrimSvcFunc) ICall_primFree - }, - - { -#ifdef COVERAGE_TEST - ICALL_PRIMITIVE_FUNC_SEND_MSG, -#endif /* COVERAGE_TEST */ - (ICall_PrimSvcFunc) ICall_primSend - }, - - { -#ifdef COVERAGE_TEST - ICALL_PRIMITIVE_FUNC_FETCH_MSG, -#endif /* COVERAGE_TEST */ - (ICall_PrimSvcFunc) ICall_primFetchMsg - }, - - { -#ifdef COVERAGE_TEST - ICALL_PRIMITIVE_FUNC_SEND_SERV_MSG, -#endif /* COVERAGE_TEST */ - (ICall_PrimSvcFunc) ICall_primSendServiceMsg - }, - - { -#ifdef COVERAGE_TEST - ICALL_PRIMITIVE_FUNC_FETCH_SERV_MSG, -#endif /* COVERAGE_TEST */ - (ICall_PrimSvcFunc) ICall_primFetchServiceMsg - }, - - { -#ifdef COVERAGE_TEST - ICALL_PRIMITIVE_FUNC_WAIT, -#endif /* COVERAGE_TEST */ - (ICall_PrimSvcFunc) ICall_primWait - }, - - { -#ifdef COVERAGE_TEST - ICALL_PRIMITIVE_FUNC_SIGNAL, -#endif /* COVERAGE_TEST */ - (ICall_PrimSvcFunc) ICall_primSignal - }, - - { -#ifdef COVERAGE_TEST - ICALL_PRIMITIVE_FUNC_ABORT, -#endif /* COVERAGE_TEST */ - (ICall_PrimSvcFunc) ICall_primAbort - }, - - { -#ifdef COVERAGE_TEST - ICALL_PRIMITIVE_FUNC_ENABLE_int, -#endif /* COVERAGE_TEST */ - (ICall_PrimSvcFunc) ICall_primEnableint - }, - - { -#ifdef COVERAGE_TEST - ICALL_PRIMITIVE_FUNC_DISABLE_int, -#endif /* COVERAGE_TEST */ - (ICall_PrimSvcFunc) ICall_primDisableint - }, - - { -#ifdef COVERAGE_TEST - ICALL_PRIMITIVE_FUNC_ENABLE_Mint, -#endif /* COVERAGE_TEST */ - (ICall_PrimSvcFunc) ICall_primEnableMint - }, - - { -#ifdef COVERAGE_TEST - ICALL_PRIMITIVE_FUNC_DISABLE_Mint, -#endif /* COVERAGE_TEST */ - (ICall_PrimSvcFunc) ICall_primDisableMint - }, - - { -#ifdef COVERAGE_TEST - ICALL_PRIMITIVE_FUNC_REGISTER_ISR, -#endif /* COVERAGE_TEST */ - (ICall_PrimSvcFunc) ICall_primRegisterISR - }, - - { -#ifdef COVERAGE_TEST - ICALL_PRIMITIVE_FUNC_GET_TICKS, -#endif /* COVERAGE_TEST */ - (ICall_PrimSvcFunc) ICall_primGetTicks - }, - - { -#ifdef COVERAGE_TEST - ICALL_PRIMITIVE_FUNC_SET_TIMER_MSECS, -#endif /* COVERAGE_TEST */ - (ICall_PrimSvcFunc) ICall_primSetTimerMSecs - }, - - { -#ifdef COVERAGE_TEST - ICALL_PRIMITIVE_FUNC_GET_TICK_PERIOD, -#endif /* COVERAGE_TEST */ - (ICall_PrimSvcFunc) ICall_primGetTickPeriod - }, - - { -#ifdef COVERAGE_TEST - ICALL_PRIMITIVE_FUNC_GET_MAX_MILLISECONDS, -#endif /* COVERAGE_TEST */ - (ICall_PrimSvcFunc) ICall_primGetMaxMSecs - }, - - { -#ifdef COVERAGE_TEST - ICALL_PRIMITIVE_FUNC_ENTITY2SERVICE, -#endif /* COVERAGE_TEST */ - (ICall_PrimSvcFunc) ICall_primE2S - }, - - { -#ifdef COVERAGE_TEST - ICALL_PRIMITIVE_FUNC_PWR_UPD_ACTIVITY_COUNTER, -#endif /* COVERAGE_TEST */ - (ICall_PrimSvcFunc) ICallPlatform_pwrUpdActivityCounter - }, - - { -#ifdef COVERAGE_TEST - ICALL_PRIMITIVE_FUNC_PWR_REGISTER_NOTIFY, -#endif /* COVERAGE_TEST */ - (ICall_PrimSvcFunc) ICallPlatform_pwrRegisterNotify - }, - - { -#ifdef COVERAGE_TEST - ICALL_PRIMITIVE_FUNC_WAIT_MATCH, -#endif /* COVERAGE_TEST */ - (ICall_PrimSvcFunc) ICall_primWaitMatch - }, - - { -#ifdef COVERAGE_TEST - ICALL_PRIMITIVE_FUNC_GET_ENTITY_ID, -#endif /* COVERAGE_TEST */ - (ICall_PrimSvcFunc) ICall_primGetEntityId - }, - - { -#ifdef COVERAGE_TEST - ICALL_PRIMITIVE_FUNC_SET_TIMER, -#endif /* COVERAGE_TEST */ - (ICall_PrimSvcFunc) ICall_primSetTimer - }, - - { -#ifdef COVERAGE_TEST - ICALL_PRIMITIVE_FUNC_STOP_TIMER, -#endif /* COVERAGE_TEST */ - (ICall_PrimSvcFunc) ICall_primStopTimer - }, - - { -#ifdef COVERAGE_TEST - ICALL_PRIMITIVE_FUNC_PWR_CONFIG_AC_ACTION, -#endif /* COVERAGE_TEST */ - (ICall_PrimSvcFunc) ICallPlatform_pwrConfigACAction - }, - - { -#ifdef COVERAGE_TEST - ICALL_PRIMITIVE_FUNC_PWR_REQUIRE, -#endif /* COVERAGE_TEST */ - (ICall_PrimSvcFunc) ICallPlatform_pwrRequire - }, - - { -#ifdef COVERAGE_TEST - ICALL_PRIMITIVE_FUNC_PWR_DISPENSE, -#endif /* COVERAGE_TEST */ - (ICall_PrimSvcFunc) ICallPlatform_pwrDispense - }, - - { -#ifdef COVERAGE_TEST - ICALL_PRIMITIVE_FUNC_THREAD_SERVES, -#endif /* COVERAGE_TEST */ - (ICall_PrimSvcFunc) ICall_primThreadServes - }, - - { -#ifdef COVERAGE_TEST - ICALL_PRIMITIVE_FUNC_PWR_IS_STABLE_XOSC_HF, -#endif /* COVERAGE_TEST */ - (ICall_PrimSvcFunc) ICallPlatform_pwrIsStableXOSCHF - }, - - { -#ifdef COVERAGE_TEST - ICALL_PRIMITIVE_FUNC_PWR_GET_TRANSITION_STATE, -#endif /* COVERAGE_TEST */ - (ICall_PrimSvcFunc) ICallPlatform_pwrGetTransitionState - }, - - { -#ifdef COVERAGE_TEST - ICALL_PRIMITIVE_FUNC_CREATE_TASK, -#endif /* COVERAGE_TEST */ - (ICall_PrimSvcFunc) ICall_primCreateTask - }, - -#ifdef ICALL_RTOS_SEMAPHORE_API - { -#ifdef COVERAGE_TEST - ICALL_PRIMITIVE_FUNC_CREATE_SEMAPHORE, -#endif /* COVERAGE_TEST */ - (ICall_PrimSvcFunc) ICall_primCreateSemaphore - }, - - { -#ifdef COVERAGE_TEST - ICALL_PRIMITIVE_FUNC_WAIT_SEMAPHORE, -#endif /* COVERAGE_TEST */ - (ICall_PrimSvcFunc) ICall_primWaitSemaphore - }, - -#else /* ICALL_RTOS_SEMAPHORE_API */ - - { -#ifdef COVERAGE_TEST - ICALL_PRIMITIVE_FUNC_WAIT_SEMAPHORE, -#endif /* COVERAGE_TEST */ - NULL - }, - - { -#ifdef COVERAGE_TEST - ICALL_PRIMITIVE_FUNC_WAIT_SEMAPHORE, -#endif /* COVERAGE_TEST */ - NULL - }, -#endif /* ICALL_RTOS_SEMAPHORE_API */ - - { -#ifdef COVERAGE_TEST - ICALL_PRIMITIVE_FUNC_SWITCH_XOSC_HF, -#endif /* COVERAGE_TEST */ - (ICall_PrimSvcFunc) ICallPlatform_pwrSwitchXOSCHF - }, - - { -#ifdef COVERAGE_TEST - ICALL_PRIMITIVE_FUNC_PWR_GET_XOSC_STARTUP_TIME, -#endif /* COVERAGE_TEST */ - (ICall_PrimSvcFunc) ICallPlatform_pwrGetXOSCStartupTime - }, - - { -#ifdef COVERAGE_TEST - ICALL_PRIMITIVE_FUNC_REGISTER_ISR_EXT, -#endif /* COVERAGE_TEST */ - (ICall_PrimSvcFunc) ICall_primRegisterISR_Ext - }, - -#ifdef ICALL_RTOS_SEMAPHORE_API - { -#ifdef COVERAGE_TEST - ICALL_PRIMITIVE_FUNC_POST_SEMAPHORE, -#endif /* COVERAGE_TEST */ - (ICall_PrimSvcFunc) ICall_primPostSemaphore - }, -#else /*ICALL_RTOS_SEMAPHORE_API */ - { -#ifdef COVERAGE_TEST - ICALL_PRIMITIVE_FUNC_POST_SEMAPHORE, -#endif /* COVERAGE_TEST */ - NULL - }, /* ICALL_RTOS_SEMAPHORE_API */ -#endif - -#ifdef ICALL_RTOS_EVENT_API - { -#ifdef COVERAGE_TEST - ICALL_PRIMITIVE_FUNC_CREATE_EVENT, -#endif /* COVERAGE_TEST */ - (ICall_PrimSvcFunc) ICall_primCreateEvent - }, - - { -#ifdef COVERAGE_TEST - ICALL_PRIMITIVE_FUNC_WAIT_EVENT, -#endif /* COVERAGE_TEST */ - (ICall_PrimSvcFunc) ICall_primWaitEvent - }, - - { -#ifdef COVERAGE_TEST - ICALL_PRIMITIVE_FUNC_POST_EVENT, -#endif /* COVERAGE_TEST */ - (ICall_PrimSvcFunc) ICall_primPostEvent - }, -#else /*ICALL_RTOS_EVENT_API */ - { -#ifdef COVERAGE_TEST - ICALL_PRIMITIVE_FUNC_CREATE_EVENT, -#endif /* COVERAGE_TEST */ - NULL - }, - { -#ifdef COVERAGE_TEST - ICALL_PRIMITIVE_FUNC_WAIT_EVENT, -#endif /* COVERAGE_TEST */ - NULL - }, /* ICALL_RTOS_EVENT_API */ - { -#ifdef COVERAGE_TEST - ICALL_PRIMITIVE_FUNC_POST_EVENT, -#endif /* COVERAGE_TEST */ - NULL - }, /* ICALL_RTOS_EVENT_API */ -#endif /* ICALL_RTOS_EVENT_API */ -}; -/** - * @internal - * Primitive service registered handler function - * @param args arguments - * @return error code - */ -static ICall_Errno ICall_primService(ICall_FuncArgsHdr *args) -{ - if (args->func >= sizeof(ICall_primSvcFuncs)/sizeof(ICall_primSvcFuncs[0])) - { - return ICALL_ERRNO_INVALID_FUNCTION; - } - return ICall_primSvcFuncs[args->func].func(args); -} - -/** - * @internal Enrolls primitive service - */ -static void ICall_initPrim(void) -{ - ICall_entities[0].service = ICALL_SERVICE_CLASS_PRIMITIVE; - ICall_entities[0].fn = ICall_primService; - - /* Initialize heap */ - ICall_heapInit(); - - /* TODO: Think about freezing permanently allocated memory blocks - * for optimization. - * Now that multiple stack images may share the same heap. - * kick cannot be triggered by a single stack image. - * Hence, maybe there should be an alternative API to - * permanently allocate memory blocks, such as - * by allocating the blocks at the end of the heap space. */ -} -#endif /* ICALL_JT */ - -#ifdef COVERAGE_TEST -/** - * @internal - * Verification function for ICall implementation - */ -void ICall_verify(void) -{ - size_t i; - for (i = 0; i < sizeof(ICall_primSvcFuncs)/sizeof(ICall_primSvcFuncs[0]); i++) - { - if (i != ICall_primSvcFuncs[i].id) - { - ICall_abort(); - } - } -} -#endif /* COVERAGE_TEST */ - - -#ifdef ICALL_JT -/** - * Registers an application. - * Note that this function must be called from the thread - * from which ICall_wait() function will be called. - * - * @param entity pointer to a variable to store entity id assigned - * to the application. - * @param msgsem pointer to a variable to store the synchronous object handle - * associated with the calling thread. - * @return @ref ICALL_ERRNO_SUCCESS when successful.
- * @ref ICALL_ERRNO_NO_RESOURCE when ran out of resource. - */ -ICall_Errno ICall_registerApp(ICall_EntityID *entity, - ICall_SyncHandle *msgSyncHdl) -{ - - size_t i; - ICall_TaskEntry *taskentry = ICall_newTask(Task_self()); - ICall_CSState key; - - if (!taskentry) - { - /* abort */ - ICALL_HOOK_ABORT_FUNC(); - return ICALL_ERRNO_NO_RESOURCE; - } - - key = ICall_enterCSImpl(); - for (i = 0; i < ICALL_MAX_NUM_ENTITIES; i++) - { - if (ICall_entities[i].service == ICALL_SERVICE_CLASS_INVALID_ENTRY) - { - /* Use this entry */ - ICall_entities[i].service = ICALL_SERVICE_CLASS_APPLICATION; - ICall_entities[i].task = taskentry; - ICall_entities[i].fn = NULL; - *entity = (ICall_EntityID) i; - *msgSyncHdl = taskentry->syncHandle; - ICall_leaveCSImpl(key); - return ICALL_ERRNO_SUCCESS; - } - } - /* abort */ - ICALL_HOOK_ABORT_FUNC(); - ICall_leaveCSImpl(key); - return (ICALL_ERRNO_NO_RESOURCE); -} - -/** - * Allocates memory block for a message. - * @param size size of the message body in bytes. - * @return pointer to the start of the message body of the newly - * allocated memory block, or NULL if the allocation - * failed. - */ -void *ICall_allocMsg(size_t size) -{ - ICall_MsgHdr *hdr = - (ICall_MsgHdr *) ICall_heapMalloc(sizeof(ICall_MsgHdr) + size); - - if (!hdr) - { - return NULL; - } - hdr->len = size; - hdr->next = NULL; - hdr->dest_id = ICALL_UNDEF_DEST_ID; - return ((void *) (hdr + 1)); - -} - -/** - * Frees the memory block allocated for a message. - * @param msg pointer to the start of the message body - * which was returned from ICall_allocMsg(). - */ -void ICall_freeMsg(void *msg) -{ - ICall_MsgHdr *hdr = (ICall_MsgHdr *) msg - 1; - ICall_heapFree(hdr); -} - -/** - * Sends a message to a registered server. - * @param src Entity id of the sender of the message - * @param dest Service id - * @param format Message format: - * @ref ICALL_MSG_FORMAT_KEEP, - * @ref ICALL_MSG_FORMAT_1ST_CHAR_TASK_ID or - * @ref ICALL_MSG_FORMAT_3RD_CHAR_TASK_ID. - * Message format indicates whether and which - * field of the message must be transformed - * into a implementation specific sender - * identity for an external image.
- * When a service message interface is defined, - * it may contain a field that is not understood - * by the client but only understood by - * the system on the server's side. - * The format provides an information to the - * messaging system on such a server - * so that it can generically tag necessary - * information to the message. - * @param msg pointer to the message body to send.
- * Note that if message is successfully sent, - * the caller should not reference the message any - * longer.
- * However, if the function fails, the caller - * still owns the reference to the message. - * That is, caller may attempt another send, - * or may free the memory block, etc. - * @return @ref ICALL_ERRNO_SUCCESS when successful.
- * @ref ICALL_ERRNO_INVALID_SERVICE when the 'dest' - * is unregistered service.
- * @ref ICALL_ERRNO_INVALID_PARAMETER when the 'src' - * is an out of range entity id or when 'dest' is - * is a service that does not receive a message - * (such as ICall primitive service).
- * Note that as far as 'src' is within the range, - * this function won't notice the 'src' entity id - * as invalid. - */ - - -ICall_Errno -ICall_sendServiceMsg(ICall_EntityID src, - ICall_ServiceEnum dest, - ICall_MSGFormat format, void *msg) -{ - ICall_EntityID dstentity = ICall_searchServiceEntity(dest); - - if (dstentity == ICALL_INVALID_ENTITY_ID) - { - return ICALL_ERRNO_INVALID_SERVICE; - } - return (ICall_send(src, dstentity, format, msg)); -} - -/** - * Retrieves a message received at the message queue - * associated with the calling thread. - * - * Note that this function should be used by an application - * which does not expect any message from non-server entity. - * - * @param src pointer to a variable to store the service id - * of the registered server which sent the retrieved - * message - * @param dest pointer to a variable to store the entity id - * of the destination of the message. - * @param msg pointer to a pointer variable to store the - * starting address of the message body being - * retrieved. - * @return @ref ICALL_ERRNO_SUCCESS when the operation was successful - * and a message was retrieved.
- * @ref ICALL_ERRNO_NOMSG when there is no queued message - * at the moment.
- * @ref ICALL_ERRNO_CORRUPT_MSG when a message queued in - * front of the thread's receive queue was not sent by - * a server. Note that in this case, the message is - * not retrieved but thrown away.
- * @ref ICALL_ERRNO_UNKNOWN_THREAD when this function is - * called from a thread which has not registered - * an entity, either through ICall_enrollService() - * or through ICall_registerApp(). - */ -ICall_Errno -ICall_fetchServiceMsg(ICall_ServiceEnum *src, - ICall_EntityID *dest, - void **msg) -{ - ICall_ServiceEnum servId; - ICall_Errno errno = ICall_fetchMsg((ICall_EntityID*)src, dest, msg); - - if (errno == ICALL_ERRNO_SUCCESS) - { - if (ICall_primEntityId2ServiceId(*src, &servId) != - ICALL_ERRNO_SUCCESS) - { - /* Source entity ID cannot be translated to service id */ - ICall_freeMsg(*msg); - return ICALL_ERRNO_CORRUPT_MSG; - } - *src = servId; - } - return (errno); - -} -#if 0 -void convertMilliToTimepec(struct timespec *timeoutPosix,uint32_t timeout) -{ - timeoutPosix->tv_sec = (timeout / 1000); - timeout = timeout % 1000; - - /* 1 millisecond = 1 000 000 nanoseconds */ - timeoutPosix->tv_nsec = timeout * 1000000; -} -#endif - - -/** - * Waits for a signal to the semaphore associated with the calling thread. - * - * Note that the semaphore associated with a thread is signaled - * when a message is queued to the message receive queue of the thread - * or when ICall_signal() function is called onto the semaphore. - * - * @param milliseconds timeout period in milliseconds. - * @return @ref ICALL_ERRNO_SUCCESS when the semaphore is signaled.
- * @ref ICALL_ERRNO_TIMEOUT when designated timeout period - * has passed since the call of the function without - * the semaphore being signaled. - */ -ICall_Errno ICall_wait(uint_fast32_t milliseconds) -{ - TaskHandle_t taskhandle = Task_self(); - ICall_TaskEntry *taskentry = ICall_searchTask(taskhandle); - uint32_t timeout; - uint32_t event; - - int16_t retVal = 0; - - if (!taskentry) - { - return (ICALL_ERRNO_UNKNOWN_THREAD); - } - /* Successful */ - if (milliseconds == 0) - { - timeout = BIOS_NO_WAIT; - } - else if (milliseconds == ICALL_TIMEOUT_FOREVER) - { - timeout = BIOS_WAIT_FOREVER; - } - else - { - /* Convert milliseconds to number of ticks */ - ICall_Errno errno = ICall_msecs2Ticks(milliseconds, &timeout); - if (errno != ICALL_ERRNO_SUCCESS) - { - return (errno); - } - } - -#ifdef FREERTOS - if (HwiP_inISR()) { - xQueueReceiveFromISR(taskentry->syncHandle, (char*)&event, NULL); - } - else { - xQueueReceive(taskentry->syncHandle, (char*)&event, milliseconds*100); - } -#endif - if(retVal != (-1)) - { - return (ICALL_ERRNO_SUCCESS); - } - - return (ICALL_ERRNO_TIMEOUT); -} - -/** - * Signals a semaphore. - * @param msgsem handle of a synchronous object to signal - * @return @ref ICALL_ERRNO_SUCCESS - */ -ICall_Errno ICall_signal(ICall_SyncHandle msgSyncHdl) -{ - /* 0x80000000 is an internal Event_ID */ - uint32_t msg_ptr = 0x80000000; - ICall_Errno status = ICALL_ERRNO_NO_RESOURCE; - -#ifdef FREERTOS - uint8_t statusQ; - if (HwiP_inISR()) { - statusQ = xQueueSendFromISR(msgSyncHdl, (char*)&msg_ptr, NULL); - } - else { - statusQ = xQueueSend(msgSyncHdl, (char*)&msg_ptr, 0); - } - - if (statusQ == pdTRUE) { - status = ICALL_ERRNO_SUCCESS; - } -#endif - return (status); -} - -/** - * Registers a service entity - * @param service service id of the enrolling service - * @param fn handler function which handles function - * calls to the service. - * @param entity pointer to a variable to store the assigned entity id - * @param msgsem pointer to a variable to store the synchronous object handle - * associated with the calling thread. - * @return @ref ICALL_ERRNO_SUCCESS when successful.
- * @ref ICALL_ERRNO_INVALID_PARAMETER when service id is already - * registered by another entity.
- * @ref ICALL_ERRNO_NO_RESOURCE when maximum number of services - * are already registered. - */ -ICall_Errno -ICall_enrollService(ICall_ServiceEnum service, - ICall_ServiceFunc fn, - ICall_EntityID *entity, - ICall_SyncHandle *msgSyncHdl) -{ - size_t i; - ICall_TaskEntry *taskentry = ICall_newTask(Task_self()); - ICall_CSState key; - - /* Note that certain service does not handle a message - * and hence, taskentry might be NULL. - */ - if (taskentry == NULL) - { - return (ICALL_ERRNO_INVALID_PARAMETER); - } - - key = ICall_enterCSImpl(); - for (i = 0; i < ICALL_MAX_NUM_ENTITIES; i++) - { - if (ICall_entities[i].service == ICALL_SERVICE_CLASS_INVALID_ENTRY) - { - /* Use this entry */ - ICall_entities[i].service = service; - ICall_entities[i].task = taskentry; - ICall_entities[i].fn = fn; - *entity = (ICall_EntityID) i; - *msgSyncHdl = taskentry->syncHandle; - - ICall_leaveCSImpl(key); - return (ICALL_ERRNO_SUCCESS); - } - else if (service == ICall_entities[i].service) - { - /* Duplicate service enrollment */ - ICall_leaveCSImpl(key); - return (ICALL_ERRNO_INVALID_PARAMETER); - } - } - /* abort */ - ICALL_HOOK_ABORT_FUNC(); - ICall_leaveCSImpl(key); - return (ICALL_ERRNO_NO_RESOURCE); - -} -#ifdef FREERTOS - -/** - * Allocates a memory block. - * @param size size of the block in bytes. - * @return address of the allocated memory block or NULL - * if allocation fails. - */ - -void *ICall_heapMalloc(uint32_t size) -{ - void* ret = NULL; - ret = malloc(size); - return ret; -} - -/** - * Frees an allocated memory block. - * @param msg pointer to a memory block to free. - */ -void ICall_heapFree(void *msg) -{ - free(msg); -} - - -/** - * Allocates a memory block, but check if enough memory will be left after the allocation. - * @param size size of the block in bytes. - * @return address of the allocated memory block or NULL - * if allocation fails. - */ - -void *ICall_heapMallocLimited(uint_least16_t size) -{ - return malloc(size); -} - -/** - * Get Statistic on Heap. - * @param stats pointer to a heapStats_t structure. - */ - -/* Statistics currently are not supported via ICall apis. - * Please consider to use bget statistics (or any of your internal heap statistics) */ -void ICall_heapGetStats(ICall_heapStats_t *pStats) -{ -} - -#endif // FREERTOS -/** - * Allocates a memory block. - * @param size size of the block in bytes. - * @return address of the allocated memory block or NULL - * if allocation fails. - */ -void *ICall_malloc(uint_least16_t size) -{ - return (ICall_heapMalloc(size)); -} - -/** - * Frees an allocated memory block. - * @param msg pointer to a memory block to free. - */ -void ICall_free(void *msg) -{ - ICall_heapFree(msg); -} - -/** - * Allocates a memory block, but check if enough memory will be left after the allocation. - * @param size size of the block in bytes. - * @return address of the allocated memory block or NULL - * if allocation fails. - */ - -void *ICall_mallocLimited(uint_least16_t size) -{ - return (ICall_heapMallocLimited(size)); -} - -/** - * Get Statistic on Heap. - * @param stats pointer to a heapStats_t structure. - */ -void ICall_getHeapStats(ICall_heapStats_t *pStats) -{ - ICall_heapGetStats(pStats); -} - - -#ifdef HEAPMGR_METRICS -/** - * @brief obtain heap usage metrics - * @param pBlkMax pointer to a variable to store max cnt of all blocks ever seen at once - * @param pBlkCnt pointer to a variable to store current cnt of all blocks - * @param pBlkFree pointer to a variable to store current cnt of free blocks - * @param pMemAlo pointer to a variable to store current total memory allocated - * @param pMemMax pointer to a variable to store max total memory ever allocated at once - * @param pMemUB pointer to a variable to store the upper bound of memory usage - */ -void ICall_getHeapMgrGetMetrics(uint32_t *pBlkMax, - uint32_t *pBlkCnt, - uint32_t *pBlkFree, - uint32_t *pMemAlo, - uint32_t *pMemMax, - uint32_t *pMemUB) -{ - ICall_heapMgrGetMetrics( pBlkMax, - pBlkCnt, - pBlkFree, - pMemAlo, - pMemMax, - pMemUB); -} - -#endif -/** - * Sends a message to an entity. - * @param src entity id of the sender - * @param dest entity id of the destination of the message. - * @param format message format. See ICall_sendServiceMsg(). - * @param msg pointer to the message body. - * @return @ref ICALL_ERRNO_SUCCESS when successful.
- * @ref ICALL_ERRNO_INVALID_PARAMETER when either src - * or dest is not a valid entity id or when - * dest is an entity id of an entity that does - * not receive a message - * (e.g., ICall primitive service entity). - */ -ICall_Errno ICall_send(ICall_EntityID src, - ICall_EntityID dest, - ICall_MSGFormat format, - void *msg) -{ - ICall_CSState key; - ICall_MsgHdr *hdr = (ICall_MsgHdr *) msg - 1; - - if (dest >= ICALL_MAX_NUM_ENTITIES || - src >= ICALL_MAX_NUM_ENTITIES) - { - return (ICALL_ERRNO_INVALID_PARAMETER); - } - key = ICall_enterCSImpl(); - if (!ICall_entities[dest].task) - { - ICall_leaveCSImpl(key); - return (ICALL_ERRNO_INVALID_PARAMETER); - } - - ICall_leaveCSImpl(key); - /* Note that once the entry is valid, - * the value does not change and hence it is OK - * to leave the critical section. - */ - - hdr->srcentity = src; - hdr->dstentity = dest; - hdr->format = format; - - ICall_msgEnqueue(&ICall_entities[dest].task->queue, msg); -/* 0x80000000 is an internal event number */ - uint32_t msg_ptr = 0x80000000; -#ifdef FREERTOS - uint8_t status; - - if (HwiP_inISR()) - { - status = xQueueSendFromISR(ICall_entities[dest].task->syncHandle, (char *) &msg_ptr, NULL); - } - else - { - status = xQueueSend(ICall_entities[dest].task->syncHandle, (char *) &msg_ptr, 0); - } - - if (status != pdPASS) - { - return status; - } -#endif - return (ICALL_ERRNO_SUCCESS); -} - -/** - * Retrieves a message, queued to receive queue of the calling thread. - * - * @param src pointer to a variable to store the sender entity id - * of the received message. - * @param dest pointer to a variable to store the destination entity id - * of the received message. - * @param msg pointer to a pointer variable to store the starting - * address of a received message body. - * @return @ref ICALL_ERRNO_SUCCESS when a message was successfully - * retrieved.
- * @ref ICALL_ERRNO_NOMSG when no message was queued to - * the receive queue at the moment.
- * @ref ICALL_ERRNO_UNKNOWN_THREAD when the calling thread - * does not have a received queue associated with it. - * This happens when neither ICall_enrollService() nor - * ICall_registerApp() was ever called from the calling - * thread. - */ -ICall_Errno ICall_fetchMsg(ICall_EntityID *src, - ICall_EntityID *dest, - void **msg) -{ - void *msgTemp; - TaskHandle_t taskhandle = Task_self(); - ICall_TaskEntry *taskentry = ICall_searchTask(taskhandle); - ICall_MsgHdr *hdr; - - if (!taskentry) - { - return (ICALL_ERRNO_UNKNOWN_THREAD); - } - /* Successful */ - msgTemp = ICall_msgDequeue(&taskentry->queue); - - if (msgTemp == NULL) - { - return (ICALL_ERRNO_NOMSG); - } - hdr = (ICall_MsgHdr *) msgTemp - 1; - *src = hdr->srcentity; - *dest = hdr->dstentity; - *msg = msgTemp; - return (ICALL_ERRNO_SUCCESS); - -} - -/** - * Transforms and entityId into a serviceId. - * Note that this function is useful in case an application - * waits for messages from both a server and another application, - * in which case, the application can only use ICall_fetchMsg(), - * not ICall_fetchServiceMsg() because the latter will return - * @ref ICALL_ERRNO_CORRUPT_MSG when a message sent by the other - * application is about to be fetched.
- * This function, then, is useful to retrieve service id - * matching the source entity id in case the source entity - * id is not that of the other application. - * - * @param entityId entity id - * @param servId pointer to a variable to store - * the resultant service id - * @return @ref ICALL_ERRNO_SUCCESS if the transformation was successful.
- * @ref ICALL_ERRNO_INVALID_SERVICE if no matching service - * is found for the entity id. - */ -ICall_Errno ICall_entityId2ServiceId(ICall_EntityID entityId, - ICall_ServiceEnum *servId) -{ - return ICall_primEntityId2ServiceId(entityId, servId); -} - -/** - * Aborts. - * - * This is preferred over C runtime abort() function, - * in an external image since the C runtime abort() is only - * guaranteed in a root image which contains the C runtime - * entry function that is executed upon startup. - */ -ICall_Errno -ICall_abort(void) -{ -#ifdef HALNODEBUG -#elif defined(EXT_HAL_ASSERT) - HAL_ASSERT(HAL_ASSERT_CAUSE_ICALL_ABORT); -#else - { - volatile uint8_t j=1; - while(j); - } -#endif /* EXT_HAL_ASSERT */ - ICALL_HOOK_ABORT_FUNC(); - return(ICALL_ERRNO_SUCCESS); -} - -/** - * Enables interrupt. - * @param intnum interrupt number - * @return @ref ICALL_ERRNO_SUCCESS. - */ -ICall_Errno -ICall_enableint(int intnum) -{ - Hwi_enableinterrupt(intnum); - return (ICALL_ERRNO_SUCCESS); -} - -/** - * Disables interrupt - * @param intnum interrupt number - * @return @ref ICALL_ERRNO_SUCCESS - */ -ICall_Errno -ICall_disableint(int intnum) -{ - Hwi_disableinterrupt(intnum); - return (ICALL_ERRNO_SUCCESS); -} - - - -/** - * Gets the current tick counter value. - * @return current tick counter value - */ -uint_fast32_t -ICall_getTicks(void) -{ - return (ClockP_getSystemTicks()); -} - -/** - * Gets the tick period. - * @return tick period in microseconds. - */ -uint_fast32_t -ICall_getTickPeriod(void) -{ - return CLOCK_TICKS_PERIOD; -} - -/** - * Gets the maximum timeout period supported by - * ICall_setTimerMSecs() function. - * - * @return maximum timeout period in milliseconds - */ -uint_fast32_t -ICall_getMaxMSecs(void) -{ - - uint_fast64_t tmp = ((uint_fast64_t) 0x7ffffffful) * (ICall_getTickPeriod()); - tmp /= 1000; - if (tmp >= 0x80000000ul) - { - tmp = 0x7ffffffful; - } - return ((uint_least32_t) tmp); -} - -/** - * Set up or restart a timer. - * Note that the timer setup initially by this function may be restarted - * using ICall_setTimer() function as well. - * - * @param msecs timeout period in milliseconds after which callback function - * shall be called. - * @param cback callback function pointer - * @param arg argument to pass to the callback function - * @param id pointer to the timer ID. - * If a new timer must be set up, the value of the timer ID - * must be set to @ref ICALL_INVALID_TIMER_ID when making this - * call and when the function returns successfully, the variable - * will be assigned a new timer ID value. - * The value other than @ref ICALL_INVALID_TIMER_ID shall be - * regarded as a request to restart the earlier set timer. - * @return @ref ICALL_ERRNO_SUCCESS when successful;
- * @ref ICALL_ERRNO_INVALID_PARAMETER when msecs is greater than - * maximum value supported;
- * @ref ICALL_ERRNO_NO_RESOURCE when ran out of resource. - * Check ICall heap size and OS heap size if this happens. - * - * @see ICall_getMaxMSecs() - */ -ICall_Errno -ICall_setTimerMSecs(uint_fast32_t msecs, - ICall_TimerCback cback, - void *arg, - ICall_TimerID *id) -{ - uint32_t ticks; - uint32_t timeout; - /* Convert to tick time */ - ICall_Errno errno = ICall_msecs2Ticks(msecs, &ticks); - - if (errno != ICALL_ERRNO_SUCCESS) - { - return (errno); - } - timeout = ticks; - ICall_setTimer(timeout, cback, arg, id); - - return (errno); -} - -/** - * Set up or restart a timer. - * Note that the timer setup initially by this function may be restarted - * using ICall_setTimerMSecs() function as well. - * - * @param ticks timeout period in ticks after which the callback function - * shall be called. - * @param cback callback function pointer - * @param arg argument to pass to the callback function - * @param id pointer to the timer ID. - * If a new timer must be set up, the value of the timer ID - * must be set to @ref ICALL_INVALID_TIMER_ID when making this - * call and when the function returns successfully, the variable - * will be assigned a new timer ID value. - * The value other than @ref ICALL_INVALID_TIMER_ID shall be - * regarded as a request to restart the earlier set timer. - * @return @ref ICALL_ERRNO_SUCCESS when successful;
- * @ref ICALL_ERRNO_NO_RESOURCE when ran out of resource. - * Check ICall heap size and OS heap size if this happens. - * - * @see ICall_getTickPeriod() - */ - - -ICall_Errno -ICall_setTimer(uint32_t ticks, - ICall_TimerCback cback, - void *arg, - ICall_TimerID *id) -{ - - ICall_ScheduleEntry *entry; - - if (*id == ICALL_INVALID_TIMER_ID) - { - ClockP_Params params; - - /* Create a new timer */ - entry = ICall_heapMalloc(sizeof(ICall_ScheduleEntry)); - if (entry == NULL) - { - /* allocation failed */ - return (ICALL_ERRNO_NO_RESOURCE); - } - ClockP_Params_init(¶ms); - params.startFlag = FALSE; - params.period = 0; - params.arg = (uintptr_t) entry; - - entry->clockP = ClockP_create(ICall_clockFunc, - ticks, - ¶ms); - if (!entry->clockP) - { - /* abort */ - ICall_abort(); - ICall_heapFree(entry); - return (ICALL_ERRNO_NO_RESOURCE); - } - entry->cback = cback; - entry->arg = arg; - *id = (ICall_TimerID) entry; - } - else - { - ICall_CSState key; - - entry = (ICall_ScheduleEntry *) *id; - - /* Critical section is entered to disable interrupts that might cause call - * to callback due to race condition */ - key = ICall_enterCriticalSection(); - ClockP_stop(entry->clockP); - entry->arg = arg; - ICall_leaveCriticalSection(key); - } - ClockP_setTimeout(entry->clockP, ticks); - - ClockP_start(entry->clockP); - - return (ICALL_ERRNO_SUCCESS); - -} - -/** - * Stops a timer. - * - * @param id timer ID. - */ -void -ICall_stopTimer(ICall_TimerID id) -{ - ICall_ScheduleEntry *entry = (ICall_ScheduleEntry *) id; - - if (id == ICALL_INVALID_TIMER_ID) - { - return; - } - - ClockP_stop(entry->clockP); -} - -/** - * Increments or decrements power activity counter. - * - * When power activity counter is greater than zero, - * the device shall stay in the active power state. - * The caller has to make sure that it decrements the counter - * as many times as it has incremented the counter - * when there is no activity that requires the active power state. - * It is recommended that each client increments the counter by just one, - * but it is not mandated to be so. - * - * @param incFlag TRUE to indicate incrementing the counter.
- * FALSE to indicate decrementing the counter. - * @return @ref TRUE if power is required.
- * @ref FALSE if power is not required.
- */ -bool -ICall_pwrUpdActivityCounter(bool incFlag) -{ - ICall_PwrUpdActivityCounterArgs args; - args.incFlag = incFlag; - ICallPlatform_pwrUpdActivityCounter(&args); - return (args.pwrRequired); -} - -/** - * Configures power constraint/dependency set/release actions upon - * activity counter change. - * - * When activity counter value drops to zero, all constraints and - * dependencies configured by this function shall be released.
- * When activity counter value increments to one, all constraints - * and dependencies configured by this function shall be set. - * - * @param bitmap a bitmap of constraint or dependency flags.
- * The flag definition is specific to each platform. - * For instance, see ICallCC26xxDefs.h. - * - * @return @ref ICALL_ERRNO_SUCCESS when successful
- * @ref ICALL_ERRNO_INVALID_PARAMETER when an invalid - * flag in the bitmap is detected.
- */ -ICall_Errno -ICall_pwrConfigACAction(ICall_PwrBitmap_t bitmap) -{ - ICall_PwrBitmapArgs args; - args.bitmap = bitmap; - return (ICallPlatform_pwrConfigACAction(&args)); -} - -/** - * Sets power constraints and dependencies. - * - * @param bitmap a bitmap of constraint or dependency flags.
- * The flag definition is specific to each platform. - * For instance, see ICallCC26xxDefs.h. - * - * @return @ref ICALL_ERRNO_SUCCESS when successful
- * @ref ICALL_ERRNO_INVALID_PARAMETER when an invalid - * flag in the bitmap is detected.
- */ -ICall_Errno -ICall_pwrRequire(ICall_PwrBitmap_t bitmap) -{ - ICall_PwrBitmapArgs args; - args.bitmap = bitmap; - return (ICallPlatform_pwrRequire(&args)); -} - -/** - * Releases power constraints and dependencies. - * - * @param bitmap a bitmap of constraint or dependency flags.
- * The flag definition is specific to each platform. - * For instance, see ICallCC26xxDefs.h. - * - * @return @ref ICALL_ERRNO_SUCCESS when successful
- * @ref ICALL_ERRNO_INVALID_PARAMETER when an invalid - * flag in the bitmap is detected.
- */ -ICall_Errno -ICall_pwrDispense(ICall_PwrBitmap_t bitmap) -{ - ICall_PwrBitmapArgs args; - args.bitmap = bitmap; - return (ICallPlatform_pwrDispense(&args)); -} - -/** - * Checks whether HF XOSC is stable. - * This function must be called after HF XOSC is turned on - * (through power dependency). - * - * @return TRUE when HF XOSC is stable.
- * FALSE when HF XOSC is not stable.
- */ -bool -ICall_pwrIsStableXOSCHF(void) -{ - ICall_GetBoolArgs args; - (void) ICallPlatform_pwrIsStableXOSCHF(&args); - return (args.value); -} - -/** - * Switch clock source to HF XOSC. - * This function must be called after HF XOSC is stable. - * - * @return @ref ICALL_ERRNO_SUCCESS - */ -ICall_Errno -ICall_pwrSwitchXOSCHF(void) -{ - ICall_FuncArgsHdr args; - return (ICallPlatform_pwrSwitchXOSCHF(&args)); -} - -/** - * Gets the estimated crystal oscillator startup time. - * - * @return estimated crystal oscillator startup time - */ -uint32_t -ICall_pwrGetXOSCStartupTime(uint_fast32_t timeUntilWakeupInMs) -{ - ICall_PwrGetXOSCStartupTimeArgs args; - args.timeUntilWakeupInMs = timeUntilWakeupInMs; - (void) ICallPlatform_pwrGetXOSCStartupTime(&args); - return (args.value); -} - -/** - * Registers a power state transition notify function. - * - * The registered notify function shall be called when the power state - * changes. - * - * @param fn notify function pointer - * @param obj pointer to data object to be passed to notify function.
- * This pointer must not be NULL and can point to an aggregate type - * containing the @ref ICall_PwrNotifyData. - * The object must not be released. - * @return @ref ICALL_ERRNO_SUCCESS when successful
- * @ref ICALL_ERRNO_NO_RESOURCE when registration failed
- */ -ICall_Errno -ICall_pwrRegisterNotify(ICall_PwrNotifyFn fn, ICall_PwrNotifyData *obj) -{ - ICall_PwrRegisterNotifyArgs args; - args.hdr.service = ICALL_SERVICE_CLASS_PRIMITIVE; - args.hdr.func = ICALL_PRIMITIVE_FUNC_PWR_REGISTER_NOTIFY; - args.fn = fn; - args.obj = obj; - return (ICallPlatform_pwrRegisterNotify(&args)); -} - -/** - * Retrieves power transition state. - * - * @return Implementation specific transition state when successful
- * Zero when the function is not implemented.
- */ -uint_fast8_t -ICall_pwrGetTransitionState(void) -{ - ICall_PwrGetTransitionStateArgs args; - ICall_Errno errno; - - errno = ICallPlatform_pwrGetTransitionState(&args); - - if (errno == ICALL_ERRNO_SUCCESS) - { - return (args.state); - } - return (0); -} - -/** - * Creates a new RTOS task. - * - * @param entryfn task entry function. - * @param priority task priority as understood by the underlying RTOS - * @param stacksize stack size as understood by the underlying RTOS - * @param arg argument to pass to the task entry function - * - * @return @ref ICALL_ERRNO_SUCCESS when successful
- * @ref ICALL_ERRNO_NO_RESOURCE when creation failed
- */ - - -#ifdef ICALL_RTOS_SEMAPHORE_API -/** - * Creates a semaphore. - * - * @param mode Semaphore mode
- * @ref ICALL_SEMAPHORE_MODE_COUNTING, or
- * @ref ICALL_SEMAPHORE_MODE_BINARY - * @param initcount initial count value - * @return created semaphore when successful
- * NULL when creation failed
- */ -ICall_Semaphore -ICall_createSemaphore(uint_fast8_t mode, int initcount) -{ - /* Semaphore_Params is a huge structure. - * To reduce stack usage, heap is used instead. - * This implies that ICall_createSemaphore() must be called before heap - * space may be exhausted. - */ - ICall_Semaphore sem; - Semaphore_Params *semParams = - (Semaphore_Params *) ICall_heapMalloc(sizeof(Semaphore_Params)); - - if (semParams == NULL) - { - return (NULL); - } - - Semaphore_Params_init(semParams); - if (mode == ICALL_SEMAPHORE_MODE_BINARY) - { - semParams->mode = Semaphore_Mode_BINARY; - } - - sem = Semaphore_create(args->initcount, semParams, NULL); - ICall_heapFree(semParams); - - return (sem); - -} -#endif - -#ifdef ICALL_RTOS_SEMAPHORE_API -/** - * Post on a semaphore - * - * @param sem semaphore. - * - * @return @ref ICALL_ERRNO_SUCCESS when the operation was successful - */ -ICall_Errno -ICall_postSemaphore(ICall_Semaphore sem) -{ - Semaphore_post(sem); - return (ICALL_ERRNO_SUCCESS); -} -#endif /* ICALL_RTOS_SEMAPHORE_API */ - -#ifdef ICALL_RTOS_EVENTS_API -/** - * Creates a event. - * - * @return created event when successful
- * NULL when creation failed
- */ -ICall_Event -ICall_createEvent(void) -{ - ICall_Event event = Event_create(NULL, NULL); - return (event); - - - ICall_CreateEventArgs args; - ICall_Errno errno; - - args.hdr.service = ICALL_SERVICE_CLASS_PRIMITIVE; - args.hdr.func = ICALL_PRIMITIVE_FUNC_CREATE_EVENT; - errno = ICall_dispatcher(&args.hdr); - if (errno == ICALL_ERRNO_SUCCESS) - { - return (args.event); - } - return (NULL); -} - -/** - * Post on an event - * - * @param event event. - * - * @return @ref ICALL_ERRNO_SUCCESS when the operation was successful - */ -ICall_Errno -ICall_postEvent(ICall_Event event, uint32_t events) -{ - Event_post(event, events); - return (ICALL_ERRNO_SUCCESS); -} -/** - * Waits on a event for ICALL_MSG_EVENT_ID - * - * @param event event. - * @param milliseconds timeout in milliseconds - * or @ref ICALL_TIMEOUT_FOREVER to wait forever - * - * @return @ref ICALL_ERRNO_SUCCESS when the operation was successful - * and event was received.
- * @ref ICALL_ERRNO_TIMEOUT when designated timeout period - * has passed since the call of the function without - * the event being signaled. - */ -ICall_Errno -ICall_waitEvent(ICall_Event event, uint_fast32_t milliseconds) -{ - uint32_t timeout; - - if (milliseconds == 0) - { - timeout = BIOS_NO_WAIT; - } - else if (milliseconds == ICALL_TIMEOUT_FOREVER) - { - timeout = BIOS_WAIT_FOREVER; - } - else - { - ICall_Errno errno = ICall_msecs2Ticks(milliseconds, &timeout); - if (errno != ICALL_ERRNO_SUCCESS) - { - return (errno); - } - } - - if (Event_pend(event, 0, ICALL_MSG_EVENT_ID, timeout)) - { - return (ICALL_ERRNO_SUCCESS); - } - return (ICALL_ERRNO_TIMEOUT); -} -#endif /* ICALL_RTOS_EVENTS_API */ - -#ifdef ICALL_RTOS_SEMAPHORE_API -/** - * Waits on a semaphore - * - * @param sem semaphore. - * @param milliseconds timeout in milliseconds - * or @ref ICALL_TIMEOUT_FOREVER to wait forever - * - * @return @ref ICALL_ERRNO_SUCCESS when the operation was successful - * and semaphore was acquired.
- * @ref ICALL_ERRNO_TIMEOUT when designated timeout period - * has passed since the call of the function without - * the semaphore being signaled. - */ -ICall_Errno -ICall_waitSemaphore(ICall_Semaphore sem, uint_fast32_t milliseconds) -{ - uint32_t timeout; - - if (milliseconds == 0) - { - timeout = BIOS_NO_WAIT; - } - else if (milliseconds == ICALL_TIMEOUT_FOREVER) - { - timeout = BIOS_WAIT_FOREVER; - } - else - { - ICall_Errno errno = ICall_msecs2Ticks(milliseconds, &timeout); - if (errno != ICALL_ERRNO_SUCCESS) - { - return (errno); - } - } - if (Semaphore_pend(sem, timeout)) - { - return (ICALL_ERRNO_SUCCESS); - } - return (ICALL_ERRNO_TIMEOUT); -} -#endif /* ICALL_RTOS_SEMAPHORE_API */ - - -#if 0 -/* Util function that take time in ticks and convert it into ms - relate to system clock (returns system clock + converted ms) */ -static void AbsoluteTimeInMilliPlusTimer(uint_least32_t timeout,struct timespec *tsTimer) -{ - - clock_gettime(CLOCK_REALTIME, tsTimer); - - tsTimer->tv_sec += (timeout / 1000); - tsTimer->tv_nsec += (timeout % 1000) * 1000000; -} -#endif - -/** - * Waits for and retrieves a message received at the message queue - * associated with the calling thread, which matches a certain condition. - * - * @param milliseconds timeout period in milliseconds. - * @param matchFn pointer to a function that would return TRUE when - * the message matches its condition. - * @param src pointer to a variable to store the service id - * of the registered server which sent the retrieved - * message, or NULL if not interested in storing service id. - * @param dest pointer to a variable to store the entity id - * of the destination of the message, - * of NULL if not interested in storing the destination entity id. - * @param msg pointer to a pointer variable to store the - * starting address of the message body being - * retrieved. The pointer must not be NULL. - * @return @ref ICALL_ERRNO_SUCCESS when the operation was successful - * and a message was retrieved.
- * @ref ICALL_ERRNO_TIMEOUT when designated timeout period - * has passed since the call of the function without - * the semaphore being signaled. - * @ref ICALL_ERRNO_UNKNOWN_THREAD when this function is - * called from a thread which has not registered - * an entity, either through ICall_enrollService() - * or through ICall_registerApp(). - */ -ICall_Errno -ICall_waitMatch(uint_least32_t milliseconds, - ICall_MsgMatchFn matchFn, - ICall_ServiceEnum *src, - ICall_EntityID *dest, - void **msg) -{ - TaskHandle_t taskhandle = Task_self(); - ICall_TaskEntry *taskentry = ICall_searchTask(taskhandle); - ICall_MsgQueue prependQueue = NULL; -#ifndef ICALL_EVENTS - uint_fast16_t consumedCount = 0; -#endif - uint32_t timeout; - uint_fast32_t timeoutStamp; - ICall_Errno errno; - - if (!taskentry) - { - return (ICALL_ERRNO_UNKNOWN_THREAD); - } - /* Successful */ - if (milliseconds == 0) - { - timeout = BIOS_NO_WAIT; - } - else if (milliseconds == ICALL_TIMEOUT_FOREVER) - { - timeout = BIOS_WAIT_FOREVER; - } - else - { - /* Convert milliseconds to number of ticks */ - errno = ICall_msecs2Ticks(milliseconds, &timeout); - if (errno != ICALL_ERRNO_SUCCESS) - { - return (errno); - } - } - - errno = ICALL_ERRNO_TIMEOUT; - - timeoutStamp = ICall_getTicks() + timeout; - -#ifdef ICALL_LITE - - uint32_t events; - -#ifdef FREERTOS - //TODO: Investigate ICALL Wait tick period (Last parameter) - while( xQueueReceive(taskentry->syncHandle, (char*)&events, milliseconds*1000) == pdPASS ) -#endif -#else /* !ICALL_LITE */ - while (ICALL_SYNC_HANDLE_PEND(taskentry->syncHandle, timeout)) -#endif /* ICALL_LITE */ - { - ICall_EntityID fetchSrc; - ICall_EntityID fetchDst; - ICall_ServiceEnum servId; - void *fetchMsg; - errno = ICall_fetchMsg(&fetchSrc, &fetchDst, &fetchMsg); - if (errno == ICALL_ERRNO_SUCCESS) - { - if (ICall_primEntityId2ServiceId(fetchSrc, &servId) == - ICALL_ERRNO_SUCCESS) - { - if (matchFn(servId, fetchDst, fetchMsg)) - { - /* Matching message found*/ - if (src != NULL) - { - *src = servId; - } - if (dest != NULL) - { - *dest = fetchDst; - } - *msg = fetchMsg; - errno = ICALL_ERRNO_SUCCESS; - break; - } - } - /* Message was received but it wasn't expected one. - * Add to the prepend queue */ - ICall_msgEnqueue(&prependQueue, fetchMsg); -#ifdef ICALL_EVENTS - /* Event are binary semaphore, so if several messsages are posted while - * we are processing one, it's possible that some of them are 'missed' and - * not processed. Sending a event to ourself force this loop to run until - * all the messages in the queue are processed. - */ -#ifdef ICALL_LITE - /* 0x20000000 is an internal Event_ID */ - uint32_t msg_ptr = (0x20000000); //Event_Id_29; - -#ifdef FREERTOS - - uint8_t status; - if (HwiP_inISR()) - { - status = xQueueSendFromISR(taskentry->syncHandle, (char *) &msg_ptr, NULL); - } - else - { - status = xQueueSend(taskentry->syncHandle, (char *) &msg_ptr, 0); - } - - if (status != pdTRUE) - { - return status; - } -#endif - - -#else /* !ICALL_LITE */ - ICALL_SYNC_HANDLE_POST(taskentry->syncHandle); -#endif /* ICALL_LITE*/ -#endif /* ICALL_EVENTS */ - } - - /* Prepare for timeout exit */ - errno = ICALL_ERRNO_TIMEOUT; - -#ifndef ICALL_EVENTS - /* Keep the decremented semaphore count */ - consumedCount++; -#endif /* ICALL_EVENTS */ - if (timeout != BIOS_WAIT_FOREVER && - timeout != BIOS_NO_WAIT) - { - /* Readjust timeout */ - uint32_t newTimeout = timeoutStamp - ICall_getTicks(); - - if (newTimeout == 0 || newTimeout > timeout) - { - break; - } - timeout = newTimeout; - } - } - - - /* Prepend retrieved irrelevant messages */ - ICall_msgPrepend(&taskentry->queue, prependQueue); -#ifndef ICALL_EVENTS - /* Re-increment the consumed semaphores */ - for (; consumedCount > 0; consumedCount--) - { - Semaphore_post(taskentry->syncHandle); - } -#endif /* ICALL_EVENTS */ - return (errno); -} - -/** - * Retrieves an entity ID of (arbitrary) one of the entities registered - * from the calling thread. - * - * Note that, if multiple entities were registered from the same thread, - * this function shall arbitrarily pick one of the entities. - * - * @return A valid entity ID or @ref ICALL_INVALID_ENTITY_ID - * when no entity was registered from the calling thread. - */ -ICall_EntityID -ICall_getEntityId(void) -{ - ICall_EntityID id; - TaskHandle_t taskhandle = Task_self(); - ICall_CSState key; - size_t i; - key = ICall_enterCSImpl(); - for (i = 0; i < ICALL_MAX_NUM_ENTITIES; i++) - { - if (ICall_entities[i].service == ICALL_SERVICE_CLASS_INVALID_ENTRY) - { - /* Not found */ - break; - } - if (ICall_entities[i].task->task == (TaskHandle_t)taskhandle) - { - /* Found */ - id = i; - ICall_leaveCSImpl(key); - return (id); - } - } - ICall_leaveCSImpl(key); - return ICALL_INVALID_ENTITY_ID; - -} - -/** - * Checks whether the calling thread provides the designated service. - * - * @param service Service enumeration value for the service. - * - * @return Non-zero if the current thread provides the designated service. - * Zero, otherwise. - */ -uint_fast8_t -ICall_threadServes(ICall_ServiceEnum service) -{ - uint_fast8_t res = 0; - TaskHandle_t taskhandle; - ICall_CSState key; - size_t i; - taskhandle = Task_self(); - - key = ICall_enterCSImpl(); - for (i = 0; i < ICALL_MAX_NUM_ENTITIES; i++) - { - if (ICall_entities[i].service == ICALL_SERVICE_CLASS_INVALID_ENTRY) - { - /* Not found */ - break; - } - else if (ICall_entities[i].service == service) - { - res = (uint_fast8_t) - (ICall_entities[i].task->task == taskhandle); - } - } - ICall_leaveCSImpl(key); - return (res); -} - -/** - * Retrieves an internal ID understood only by a service entity, - * corresponding to an ICall entity ID. - * - * This function is used when a message body includes a field indicating a - * software entity and the destination of the message has its own internal - * message routing mechanism with its own entity enumeration system. - * - * @param service Service enumeration value for the service. - * Currently @ref ICALL_SERVICE_CLASS_BLE_MSG is supported. - * @param entity ICall entity ID. - * - * @return Stack specific 8 bit ID or 0xFF when failed. - */ -uint_fast8_t -ICall_getLocalMsgEntityId(ICall_ServiceEnum service, ICall_EntityID entity) -{ - ICall_GetLocalMsgEntityIdArgs args; - ICall_Errno errno; - args.hdr.service = service; - args.hdr.func = ICALL_MSG_FUNC_GET_LOCAL_MSG_ENTITY_ID; - args.entity = entity; - errno = ICall_dispatcher(&args.hdr); - if (errno == ICALL_ERRNO_SUCCESS) - { - return (args.localId); - } - return (0xFF); -} - -#endif /* ICALL_JT */ - -#ifdef ICALL_LITE - /******************************************************************************* - * @fn matchLiteCS - */ -static bool matchLiteCS(ICall_ServiceEnum src, - ICall_EntityID dest, const void *msg) -{ - (void) src; - (void) dest; - ICall_LiteCmdStatus *pMsg = (ICall_LiteCmdStatus *)msg; - return (pMsg->cmdId == ICALL_LITE_DIRECT_API_DONE_CMD_ID); -} - /******************************************************************************* - * @fn icall_directAPI - * see headers for details. - */ -uint32_t icall_directAPI( uint8_t service , icall_lite_id_t id, ... ) -{ - va_list argp; - uint32_t res; - icallLiteMsg_t liteMsg; - - // The following will push all parameter in the runtime stack. - // This need to be call before any other local declaration of variable.... - va_start(argp, id); - - // Todo - add string for every icall API function, instead of printing function address - BLE_LOG_INT_INT(0, BLE_LOG_MODULE_APP, "APP : icall_directAPI to BLE func=0x%x, status=%d\n", id, 0); - // Create the message that will be send to the requested service.. - liteMsg.hdr.len = sizeof(icallLiteMsg_t); - liteMsg.hdr.next = NULL; - liteMsg.hdr.dest_id = ICALL_UNDEF_DEST_ID; - liteMsg.msg.directAPI = id; - liteMsg.msg.pointerStack = (uint32_t*)(*((uint32_t*)(&argp))); - ICall_sendServiceMsg(ICall_getEntityId(), service, - ICALL_MSG_FORMAT_DIRECT_API_ID, &(liteMsg.msg)); - - // Since stack needs to always have a higher priority than the thread calling - // the API, when we reach this point the API has been executed by the stack. - // This implies the following: - // - API are not called in critical section or in section where task - // switching is disabled - // It is possible that the stack is blocking on this API, in this case a - // sync object needs to be used in order for this call to resume only when - // the API has been process in full. - { - ICall_Errno errno; - void *pCmdStatus = NULL; - - errno = ICall_waitMatch(ICALL_TIMEOUT_PREDEFINE, matchLiteCS, NULL, NULL, - (void **)&pCmdStatus); - if (errno == ICALL_ERRNO_TIMEOUT) - { -#ifdef HALNODEBUG -#elif defined(EXT_HAL_ASSERT) - HAL_ASSERT(HAL_ASSERT_CAUSE_ICALL_TIMEOUT); -#else /* !EXT_HAL_ASSERT */ - ICall_abort(); -#endif /* EXT_HAL_ASSERT */ - } - else if (errno == ICALL_ERRNO_SUCCESS) - { - if (pCmdStatus) - { - ICall_freeMsg(pCmdStatus); - } - } - else - { -#ifdef HALNODEBUG -#else /* ! HALNODEBUG */ - ICall_abort(); -#endif /* HALNODEBUG */ - } - } - - // The return parameter is set in the runtime stack, at the location of the - // first parameter. - res = liteMsg.msg.pointerStack[0]; - - va_end(argp); - - return (res); -} - - /******************************************************************************* - * @fn ICall_sendServiceComplete - * see headers for details. - */ -ICall_Errno ICall_sendServiceComplete(ICall_EntityID src, - ICall_EntityID dest, - ICall_MSGFormat format, - void *msg) -{ - ICall_CSState key; - ICall_MsgHdr *hdr = (ICall_MsgHdr *) msg - 1; - - if (dest >= ICALL_MAX_NUM_ENTITIES || - src >= ICALL_MAX_NUM_ENTITIES) - { - return (ICALL_ERRNO_INVALID_PARAMETER); - } - key = ICall_enterCSImpl(); - if (!ICall_entities[dest].task) - { - ICall_leaveCSImpl(key); - return (ICALL_ERRNO_INVALID_PARAMETER); - } - - ICall_leaveCSImpl(key); - /* Note that once the entry is valid, - * the value does not change and hence it is OK - * to leave the critical section. - */ - - hdr->srcentity = src; - hdr->dstentity = dest; - hdr->format = format; - ICall_msgEnqueue(&ICall_entities[dest].task->queue, msg); - - /* 0x20000000 is an internal Event_ID */ - uint32_t msg_ptr = (0x20000000); //Event_Id_29; -#ifdef FREERTOS - uint8_t status; - if (HwiP_inISR()) - { - status = xQueueSendFromISR(ICall_entities[dest].task->syncHandle, (char *) &msg_ptr, NULL); - } - else - { - status = xQueueSend(ICall_entities[dest].task->syncHandle, (char *) &msg_ptr, 0); - } - - if (status != pdTRUE) - { - return status; - } -#endif - return (ICALL_ERRNO_SUCCESS); -} -#endif /* ICALL_LITE*/ diff --git a/src/platform/cc13xx_26xx/icall_FreeRTOS.cpp b/src/platform/cc13xx_26xx/icall_FreeRTOS.cpp new file mode 100644 index 00000000000000..469ef9b3e0074c --- /dev/null +++ b/src/platform/cc13xx_26xx/icall_FreeRTOS.cpp @@ -0,0 +1,3926 @@ +/****************************************************************************** + @file icall_FreeRTOS.c + + @brief Indirect function Call dispatcher implementation on top of OS. + + This implementation uses heapmgr.h to implement a simple heap with low + memory overhead but large processing overhead.
+ The size of the heap is determined with HEAPMGR_SIZE macro, which can + be overridden with a compile option. + Note: The ICall layer (e.g. this file) is using TI internal implementation of POSIX. + For now, the ICall layer is not supports using outer POSIX on the application layer. + + Group: WCS, LPC, BTS + Target Device: cc13xx_cc26xx + + ****************************************************************************** + + Copyright (c) 2013-2024, Texas Instruments Incorporated + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of Texas Instruments Incorporated nor the names of + its contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + ****************************************************************************** + + + *****************************************************************************/ + +#ifdef FREERTOS +#include "bget.h" +#include +#include +#endif + +#ifdef FREERTOS +#include +#include +#include +#endif + +#include +#include +#define Hwi_disable HwiP_disable +#define Hwi_restore HwiP_restore +#define Hwi_disableinterrupt HwiP_disableInterrupt +#define Hwi_enableinterrupt HwiP_enableInterrupt +#define Swi_restore SwiP_restore +#define Swi_disable SwiP_disable +#define BIOS_WAIT_FOREVER (~(0U)) +#define BIOS_NO_WAIT (0U) + +#include "icall.h" +#include "icall_platform.h" +#include "osal.h" +#include +#include + +#ifndef ICALL_FEATURE_SEPARATE_IMGINFO +#include +#endif /* ICALL_FEATURE_SEPARATE_IMGINFO */ + +#ifndef Task_self +#define Task_self ICall_taskSelf +#endif + +#ifndef ICALL_MAX_NUM_ENTITIES +/** + * Maximum number of entities that use ICall, including service entities + * and application entities. + * The value may be overridden by a compile option. + * Note that there are at least, + * Primitive service, Stack services along with potentially generic + * framework service for the stack thread. + */ +#define ICALL_MAX_NUM_ENTITIES 6 +#endif + +#ifndef ICALL_MAX_NUM_TASKS +/** + * Maximum number of threads which include entities. + * The value may be overridden by a compile option. + */ +#define ICALL_MAX_NUM_TASKS 2 +#endif + +/** + * @internal + * Service class value used to indicate an invalid (unused) entry + */ +#define ICALL_SERVICE_CLASS_INVALID_ENTRY 0x0000 + +/** + * @internal + * Service class value used to indicate an entry for an application entity + */ +#define ICALL_SERVICE_CLASS_APPLICATION ICALL_SERVICE_CLASS_MASK + +/** + * @internal + * Primitive service entity ID + */ +#define ICALL_PRIMITIVE_ENTITY_ID 0 + +/** + * @internal + * Accessor macro to get a header field (next) from a message pointer + */ +#define ICALL_MSG_NEXT(_p) (((ICall_MsgHdr *) (_p) -1)->next) + +/** + * @internal + * Accessor macro to get a header field (dest_id) from a message pointer + */ +#define ICALL_MSG_DEST_ID(_p) (((ICall_MsgHdr *) (_p) -1)->dest_id) + +#ifndef ICALL_TIMER_TASK_STACK_SIZE +/** + * @internal + * Timer thread stack size + */ +#define ICALL_TIMER_TASK_STACK_SIZE (512) +#endif // ICALL_TIMER_TASK_STACK_SIZE + +/** + * @internal + * Creation of the synchronous object between application and service + */ + +#ifdef ICALL_EVENTS +#define ICALL_SYNC_HANDLE_CREATE() (Event_create(NULL, NULL)) +#else /* ICALL_EVENTS */ +#define ICALL_SYNC_HANDLE_CREATE() (Semaphore_create(0, NULL, NULL)) +#endif /* ICALL_EVENTS */ + +/** + * @internal + * post the synchronous object between application and service + */ +#ifdef ICALL_EVENTS +#define ICALL_SYNC_HANDLE_POST(x) (Event_post(x, ICALL_MSG_EVENT_ID)) +#define ICALL_SYNC_HANDLE_POST_WM(x) (Event_post(x, ICALL_WAITMATCH_EVENT_ID)) +#else /* ICALL_EVENTS */ +#define ICALL_SYNC_HANDLE_POST(x) (Semaphore_post(x)) +#define ICALL_SYNC_HANDLE_POST_WM(x) (Semaphore_post(x)) /* Semaphore does not have event ID */ +#endif /* ICALL_EVENTS */ + +/** + * @internal + * pend for the synchronous object between application and service + */ +#ifdef ICALL_EVENTS +#define ICALL_SYNC_HANDLE_PEND(x, t) (Event_pend(x, 0, ICALL_MSG_EVENT_ID, t)) +#define ICALL_SYNC_HANDLE_PEND_WM(x, t) (Event_pend(x, 0, ICALL_WAITMATCH_EVENT_ID, t)) +#else /* ICALL_EVENTS */ +#define ICALL_SYNC_HANDLE_PEND(x, t) (Semaphore_pend(x, t)) +#define ICALL_SYNC_HANDLE_PEND_WM(x, t) (Semaphore_pend(x, t)) /* Semaphore does not have event ID */ +#endif /* ICALL_EVENTS */ + +/** + * @internal + * ticks + */ +#define CLOCK_TICKS_PERIOD (10) + +/** + * @internal + * Data structure used to access critical section + * state variable. + * Without this data structure, C code will violate + * C89 or C99 strict aliasing rule. + */ +typedef union _icall_cs_state_union_t +{ + /** critical section variable as declared in the interface */ + ICall_CSState state; + /** @internal field used to access internal data */ + struct _icall_cs_state_aggr_t + { + /** field to store Swi_disable() return value */ + uint_least16_t swikey; + /** field to store Hwi_disable() return value */ + uint_least16_t hwikey; + } each; +} ICall_CSStateUnion; + +/** + * @internal Primitive service handler function type + */ +typedef ICall_Errno (*ICall_PrimSvcFunc)(ICall_FuncArgsHdr *); + +#ifdef ICALL_FEATURE_SEPARATE_IMGINFO +/* Image information shall be in separate module */ + +/** + * Array of entry function addresses of external images. + * + * Note that function address must be odd number for Thumb mode functions. + */ +extern const ICall_RemoteTaskEntry ICall_imgEntries[]; +/** + * Array of task priorities of external images. + * One task is created per image to start off the image entry function. + * Each element of this array correspond to the task priority of + * each entry function defined in @ref ICall_imgEntries. + */ +extern const int ICall_imgTaskPriorities[]; + +/** + * Array of task stack sizes of external images. + * One task is created per image to start off the image entry function. + * Each element of this array correspond to the task stack size of + * each entry function defined in @ref ICall_imgEntries. + */ +extern const size_t ICall_imgTaskStackSizes[]; + +/** + * Array of custom initialization parameters (pointers). + * Each initialization parameter (pointer) is passed to each corresponding + * image entry function defined in @ref ICall_imgEntries; + */ +extern const void * ICall_imgInitParams[]; + +/** + * Number of external images. + */ +extern const uint_least8_t ICall_numImages; + +#define icall_threadEntries ICall_imgEntries +#define ICall_threadPriorities ICall_imgTaskPriorities +#define ICall_threadStackSizes ICall_imgTaskStackSizes +#define ICall_getInitParams(_i) (ICall_imgInitParams[i]) +#define ICALL_REMOTE_THREAD_COUNT ICall_numImages +#else /* ICALL_FEATURE_SEPARATE_IMGINFO */ +/** + * @internal + * Array of entry function of external images. + */ +static const ICall_RemoteTaskEntry icall_threadEntries[] = ICALL_ADDR_MAPS; + +/** @internal external image count */ +#define ICALL_REMOTE_THREAD_COUNT (sizeof(icall_threadEntries) / sizeof(icall_threadEntries[0])) + +/** @internal thread priorities to be assigned to each remote thread */ +#ifndef BLE_STACK_TASK_PRIORITY +static const int ICall_threadPriorities[] = { ICALL_TASK_PRIORITIES }; +#else +static const int ICall_threadPriorities[] = { BLE_STACK_TASK_PRIORITY }; +#endif + +/** @internal thread stack max depth for each remote thread */ +static const size_t ICall_threadStackSizes[] = ICALL_TASK_STACK_SIZES; + +/** @internal initialization parameter (pointer) for each remote thread */ +#ifdef ICALL_CUSTOM_INIT_PARAMS +static const void * ICall_initParams[] = ICALL_CUSTOM_INIT_PARAMS; +#define ICall_getInitParams(_i) (ICall_initParams[i]) +#else /* ICALL_CUSTOM_INIT_PARAMS */ +#define ICall_getInitParams(_i) NULL +#endif /* ICALL_CUSTOM_INIT_PARAMS */ + +#endif /* ICALL_FEATURE_SEPARATE_IMGINFO */ + +/** @internal message queue */ +typedef void * ICall_MsgQueue; + +/** @internal data structure about a task using ICall module */ +typedef struct _icall_task_entry_t +{ + TaskHandle_t task; + ICall_SyncHandle syncHandle; + ICall_MsgQueue queue; +} ICall_TaskEntry; + +/** @internal data structure about an entity using ICall module */ +typedef struct _icall_entity_entry_t +{ + ICall_ServiceEnum service; + ICall_TaskEntry * task; + ICall_ServiceFunc fn; +} ICall_entityEntry; + +/** @internal storage to track all tasks using ICall module */ +static ICall_TaskEntry ICall_tasks[ICALL_MAX_NUM_TASKS]; + +/** @internal storage to track all entities using ICall module */ +static ICall_entityEntry ICall_entities[ICALL_MAX_NUM_ENTITIES]; + +#ifndef FREERTOS +extern mqd_t g_EventsQueueID; +#endif +/** + * @internal + * Wakeup schedule data structure definition + */ + +#ifdef FREERTOS +void ICALL_Task_restore(UBaseType_t * OriginalParam); +void ICALL_Task_disable(UBaseType_t * OriginalParam); +#else + +void ICALL_Task_restore(struct sched_param * OriginalParam); +void ICALL_Task_disable(struct sched_param * OriginalParam); +#endif +typedef struct _icall_schedule_t +{ + ClockP_Handle clockP; + ICall_TimerCback cback; + void * arg; +} ICall_ScheduleEntry; + +/* For now critical sections completely disable hardware interrupts + * because they are used from ISRs in MAC layer implementation. + * If MAC layer implementation changes, critical section + * implementation may change to reduce overall interrupt latency. + */ +/* Enter critical section implementation. See header file for comment. */ +ICall_CSState ICall_enterCSImpl(void) +{ + + ICall_CSStateUnion cu; + cu.each.swikey = (uint_least16_t) Swi_disable(); + cu.each.hwikey = (uint_least16_t) Hwi_disable(); + return cu.state; +} +#ifdef FREERTOS +TaskHandle_t ICall_taskSelf(void) +#else +Task_Handle ICall_taskSelf(void) +#endif +{ + + TaskHandle_t task = NULL; +#ifdef FREERTOS + task = (TaskHandle_t) xTaskGetCurrentTaskHandle(); +#else + task = ; +#endif // FREERTOS + return (task); +} + +/* See header file for comment */ +ICall_EnterCS ICall_enterCriticalSection = ICall_enterCSImpl; + +/* leave critical section implementation. See header file for comment */ +void ICall_leaveCSImpl(ICall_CSState key) +{ + ICall_CSStateUnion * cu = (ICall_CSStateUnion *) &key; + Hwi_restore((uint32_t) cu->each.hwikey); + Swi_restore((uint32_t) cu->each.swikey); +} + +/* See header file for comment */ +ICall_LeaveCS ICall_leaveCriticalSection = ICall_leaveCSImpl; + +/* Implementing a simple heap using heapmgr.h template. + * This simple heap depends on critical section implementation + * and hence the template is used after critical section definition. */ +void * ICall_heapMalloc(uint32_t size); +void * ICall_heapRealloc(void * blk, uint32_t size); +void ICall_heapFree(void * blk); + +#define HEAPMGR_INIT ICall_heapInit +#define HEAPMGR_MALLOC ICall_heapMalloc +#define HEAPMGR_FREE ICall_heapFree +#define HEAPMGR_REALLOC ICall_heapRealloc +#define HEAPMGR_GETSTATS ICall_heapGetStats +#define HEAPMGR_MALLOC_LIMITED ICall_heapMallocLimited + +void ICall_heapMgrGetMetrics(uint32_t * pBlkMax, uint32_t * pBlkCnt, uint32_t * pBlkFree, uint32_t * pMemAlo, uint32_t * pMemMax, + uint32_t * pMemUB); +#ifdef HEAPMGR_METRICS +#define HEAPMGR_GETMETRICS ICall_heapMgrGetMetrics +#endif + +#define HEAPMGR_LOCK() \ + do \ + { \ + ICall_heapCSState = ICall_enterCSImpl(); \ + } while (0) +#define HEAPMGR_UNLOCK() \ + do \ + { \ + ICall_leaveCSImpl(ICall_heapCSState); \ + } while (0) +#define HEAPMGR_IMPL_INIT() +/* Note that a static variable can be used to contain critical section + * state since heapmgr.h template ensures that there is no nested + * lock call. */ + +#if defined(HEAPMGR_CONFIG) && ((HEAPMGR_CONFIG == 0) || (HEAPMGR_CONFIG == 0x80)) +#include +#elif defined(HEAPMGR_CONFIG) && ((HEAPMGR_CONFIG == 1) || (HEAPMGR_CONFIG == 0x81)) +#include +#elif defined(HEAPMGR_CONFIG) && ((HEAPMGR_CONFIG == 2) || (HEAPMGR_CONFIG == 0x82)) +#include +#elif defined(FREERTOS) +#include "TI_heap_wrapper.h" +#else +static ICall_CSState ICall_heapCSState; +#include +#endif + +/** + * @internal Searches for a task entry within @ref ICall_tasks. + * @param taskhandle OS task handle + * @return Pointer to task entry when found, or NULL. + */ +static ICall_TaskEntry * ICall_searchTask(TaskHandle_t taskhandle) +{ + size_t i; + ICall_CSState key; + + key = ICall_enterCSImpl(); + for (i = 0; i < ICALL_MAX_NUM_TASKS; i++) + { + if (!ICall_tasks[i].task) + { + /* Empty slot */ + break; + } + if ((TaskHandle_t) taskhandle == (TaskHandle_t) ICall_tasks[i].task) + { + ICall_leaveCSImpl(key); + return &ICall_tasks[i]; + } + } + ICall_leaveCSImpl(key); + return NULL; +} + +/** + * @internal Searches for a task entry within @ref ICall_tasks or + * build an entry if the entry table is empty. + * @param taskhandle OS task handle + * @return Pointer to task entry when found, or NULL. + */ + +static ICall_TaskEntry * ICall_newTask(TaskHandle_t taskhandle) +{ + size_t i; + ICall_CSState key; + + key = ICall_enterCSImpl(); + for (i = 0; i < ICALL_MAX_NUM_TASKS; i++) + { + if (!ICall_tasks[i].task) + { + /* Empty slot */ + ICall_TaskEntry * taskentry = &ICall_tasks[i]; + taskentry->task = taskhandle; + taskentry->queue = NULL; + +#ifdef FREERTOS + taskentry->syncHandle = xQueueCreate(20, sizeof(uint32_t)); +#endif + + if (taskentry->syncHandle == 0) + { + /* abort */ + ICALL_HOOK_ABORT_FUNC(); + } + + ICall_leaveCSImpl(key); + return taskentry; + } + if (taskhandle == (TaskHandle_t) ICall_tasks[i].task) + { + ICall_leaveCSImpl(key); + return &ICall_tasks[i]; + } + } + ICall_leaveCSImpl(key); + return NULL; +} + +/* See header file for comments. */ +ICall_EntityID ICall_searchServiceEntity(ICall_ServiceEnum service) +{ + size_t i; + ICall_CSState key; + + key = ICall_enterCSImpl(); + for (i = 0; i < ICALL_MAX_NUM_ENTITIES; i++) + { + if (ICall_entities[i].service == ICALL_SERVICE_CLASS_INVALID_ENTRY) + { + /* Empty slot */ + break; + } + if (service == ICall_entities[i].service) + { + ICall_leaveCSImpl(key); + return (ICall_EntityID) i; + } + } + ICall_leaveCSImpl(key); + return ICALL_INVALID_ENTITY_ID; +} + +/** + * @internal Searches for a service entity entry. + * @param service service id + * @return Pointer to entity entry of the service or + * NULL when none found. + */ +static ICall_entityEntry * ICall_searchService(ICall_ServiceEnum service) +{ + ICall_EntityID entity = ICall_searchServiceEntity(service); + if (entity == ICALL_INVALID_ENTITY_ID) + { + return NULL; + } + return &ICall_entities[entity]; +} + +/* Dispatcher implementation. See ICall_dispatcher declaration + * for comment. */ +static ICall_Errno ICall_dispatch(ICall_FuncArgsHdr * args) +{ + ICall_entityEntry * entity; + + entity = ICall_searchService(args->service); + if (!entity) + { + return ICALL_ERRNO_INVALID_SERVICE; + } + if (!entity->fn) + { + return ICALL_ERRNO_INVALID_FUNCTION; + } + + return entity->fn(args); +} + +/* See header file for comments */ +ICall_Dispatcher ICall_dispatcher = ICall_dispatch; + +/* Static instance of ICall_RemoteTaskArg to pass to + * remote task entry function. + * See header file for comments */ +static const ICall_RemoteTaskArg ICall_taskEntryFuncs = { ICall_dispatch, ICall_enterCSImpl, ICall_leaveCSImpl }; + +/** + * @internal Thread entry function wrapper that complies with + * OS. + * @param arg0 actual entry function + * @param arg1 ignored + */ +TaskHandle_t RemoteTask = NULL; + +// pthread_t RemoteTask; + +struct argsForPosixTaskStart +{ + void * arg0; + void * arg1; +}; +struct argsForPosixTaskStart POSIX_args; + +typedef void (*TaskFunction_t)(void *); + +static void ICall_taskEntry(void * arg) + +{ + void * arg0 = ((struct argsForPosixTaskStart *) (arg))->arg0; + void * arg1 = ((struct argsForPosixTaskStart *) (arg))->arg1; + + ICall_CSState key; + key = ICall_enterCSImpl(); + if (ICall_newTask(ICall_taskSelf()) == NULL) + { + /* abort */ + ICALL_HOOK_ABORT_FUNC(); + } + ICall_leaveCSImpl(key); + + /* Attempt to yield prior to running task */ + taskYIELD(); + + ICall_RemoteTaskEntry entryfn = (ICall_RemoteTaskEntry) arg0; + + entryfn(&ICall_taskEntryFuncs, (void *) arg1); + + // return NULL; +} + +#ifndef ICALL_JT +/* forward reference */ +static void ICall_initPrim(void); +#endif /* ICALL_JT */ + +/* See header file for comments. */ +void ICall_init(void) +{ + size_t i; + + for (i = 0; i < ICALL_MAX_NUM_TASKS; i++) + { + ICall_tasks[i].task = NULL; + ICall_tasks[i].queue = NULL; + } + for (i = 0; i < ICALL_MAX_NUM_ENTITIES; i++) + { + ICall_entities[i].service = ICALL_SERVICE_CLASS_INVALID_ENTRY; + } + +#ifndef ICALL_JT + /* Initialize primitive service */ + ICall_initPrim(); +#else + /* Initialize heap */ +#ifndef FREERTOS + ICall_heapInit(); +#endif // FREERTOS +#endif +} + +/* See header file for comments */ +void ICall_createRemoteTasksAtRuntime(ICall_RemoteTask_t * remoteTaskTable, uint8_t nbElems) +{ + size_t i; + /* ICALL_Task_disable is a cheap locking mechanism to lock tasks + * which may attempt to access the service call dispatcher + * till all services are registered. + */ + UBaseType_t OriginalParam; + ICALL_Task_disable(&OriginalParam); + for (i = 0; i < nbElems; i++) + { +#ifdef FREERTOS + BaseType_t xReturned; + + /* Pass the args via external sturct (POSIX use only single arg) */ + POSIX_args.arg0 = (void *) remoteTaskTable[i].startupEntry; + POSIX_args.arg1 = (void *) remoteTaskTable[i].ICall_imgInitParam; + + xReturned = xTaskCreate(ICall_taskEntry, /* Function that implements the task. */ + "x", /* Text name for the task. */ + remoteTaskTable[i].imgTaskStackSize / sizeof(uint32_t), /* Stack size in words, not bytes. */ + (void *) &POSIX_args, /* Parameter passed into the task. */ + remoteTaskTable[i].imgTaskPriority, /* Priority at which the task is created. */ + &RemoteTask); /* Used to pass out the created task's handle. */ + + if (xReturned == errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY) + { + /* Creation of FreeRTOS task failed */ + while (1) + ; + } + } + ICALL_Task_restore(&OriginalParam); +#endif +} + +/* See header file for comments */ +void ICall_createRemoteTasks(void) +{ + size_t i; + ICall_RemoteTask_t remoteTaskTable[ICALL_REMOTE_THREAD_COUNT]; + + for (i = 0; i < ICALL_REMOTE_THREAD_COUNT; i++) + { + remoteTaskTable[i].imgTaskPriority = ICall_threadPriorities[i]; + remoteTaskTable[i].imgTaskStackSize = ICall_threadStackSizes[i]; + remoteTaskTable[i].startupEntry = icall_threadEntries[i]; + remoteTaskTable[i].ICall_imgInitParam = (void *) ICall_getInitParams(i); + } + ICall_createRemoteTasksAtRuntime(remoteTaskTable, ICALL_REMOTE_THREAD_COUNT); +} + +#ifdef FREERTOS +void ICALL_Task_disable(UBaseType_t * OriginalParam) + +#else + void ICALL_Task_disable(struct sched_param * OriginalParam) +#endif +{ + +#ifdef FREERTOS + TaskStatus_t pxTaskStatus; + vTaskGetInfo(ICall_taskSelf(), &pxTaskStatus, pdFALSE, eInvalid); + *OriginalParam = pxTaskStatus.uxCurrentPriority; + + vTaskPrioritySet(ICall_taskSelf(), configMAX_PRIORITIES - 1); +#endif +} +#ifdef FREERTOS +void ICALL_Task_restore(UBaseType_t * OriginalParam) +#else + void ICALL_Task_restore(struct sched_param * OriginalParam) +#endif +{ + +#ifdef FREERTOS + vTaskPrioritySet(ICall_taskSelf(), *OriginalParam); + +#else + pthread_t pthreadID = pthread_self(); + pthread_setschedparam(pthreadID, 0, OriginalParam); +#endif +} + +/* See header file for comments */ +ICall_TaskHandle ICall_getRemoteTaskHandle(uint8 index) +{ + TaskHandle_t * task = NULL; + + UBaseType_t OriginalParam; + ICALL_Task_disable(&OriginalParam); + + if (index < ICALL_MAX_NUM_TASKS) + { + task = &ICall_tasks[index].task; + } + + ICALL_Task_restore(&OriginalParam); + + return ((ICall_TaskHandle) task); +} + +/* Primitive service implementation follows */ + +#ifndef ICALL_JT +/** + * @internal Enrolls a service + * @param args arguments + * @return @ref ICALL_ERRNO_SUCCESS when successful.
+ * @ref ICALL_ERRNO_INVALID_PARAMETER when service id is already + * registered by another entity.
+ * @ref ICALL_ERRNO_NO_RESOURCE when maximum number of services + * are already registered. + */ +static ICall_Errno ICall_primEnroll(ICall_EnrollServiceArgs * args) +{ + size_t i; + ICall_TaskEntry * taskentry = ICall_newTask(Task_self()); + ICall_CSState key; + + /* Note that certain service does not handle a message + * and hence, taskentry might be NULL. + */ + if (taskentry == NULL) + { + return ICALL_ERRNO_INVALID_PARAMETER; + } + + key = ICall_enterCSImpl(); + for (i = 0; i < ICALL_MAX_NUM_ENTITIES; i++) + { + if (ICall_entities[i].service == ICALL_SERVICE_CLASS_INVALID_ENTRY) + { + /* Use this entry */ + ICall_entities[i].service = args->service; + ICall_entities[i].task = taskentry; + ICall_entities[i].fn = args->fn; + args->entity = (ICall_EntityID) i; + args->msgSyncHdl = taskentry->syncHandle; + ICall_leaveCSImpl(key); + return ICALL_ERRNO_SUCCESS; + } + else if (args->service == ICall_entities[i].service) + { + /* Duplicate service enrollment */ + ICall_leaveCSImpl(key); + return ICALL_ERRNO_INVALID_PARAMETER; + } + } + /* abort */ + ICALL_HOOK_ABORT_FUNC(); + ICall_leaveCSImpl(key); + return ICALL_ERRNO_NO_RESOURCE; +} + +/** + * @internal Registers an application + * @param args arguments + * @return @ref ICALL_ERRNO_SUCCESS when successful.
+ * @ref ICALL_ERRNO_NO_RESOURCE when ran out of resource. + */ +static ICall_Errno ICall_primRegisterApp(ICall_RegisterAppArgs * args) +{ + size_t i; + ICall_TaskEntry * taskentry = ICall_newTask(Task_self()); + ICall_CSState key; + + if (!taskentry) + { + /* abort */ + ICALL_HOOK_ABORT_FUNC(); + return ICALL_ERRNO_NO_RESOURCE; + } + + key = ICall_enterCSImpl(); + for (i = 0; i < ICALL_MAX_NUM_ENTITIES; i++) + { + if (ICall_entities[i].service == ICALL_SERVICE_CLASS_INVALID_ENTRY) + { + /* Use this entry */ + ICall_entities[i].service = ICALL_SERVICE_CLASS_APPLICATION; + ICall_entities[i].task = taskentry; + ICall_entities[i].fn = NULL; + args->entity = (ICall_EntityID) i; + args->msgSyncHdl = taskentry->syncHandle; + ICall_leaveCSImpl(key); + return ICALL_ERRNO_SUCCESS; + } + } + /* abort */ + ICALL_HOOK_ABORT_FUNC(); + ICall_leaveCSImpl(key); + return ICALL_ERRNO_NO_RESOURCE; +} + +/** + * @internal Allocates memory block for a message. + * @param args arguments + */ +static ICall_Errno ICall_primAllocMsg(ICall_AllocArgs * args) +{ + ICall_MsgHdr * hdr = (ICall_MsgHdr *) ICall_heapMalloc(sizeof(ICall_MsgHdr) + args->size); + + if (!hdr) + { + return ICALL_ERRNO_NO_RESOURCE; + } + hdr->len = args->size; + hdr->next = NULL; + hdr->dest_id = ICALL_UNDEF_DEST_ID; + args->ptr = (void *) (hdr + 1); + return ICALL_ERRNO_SUCCESS; +} + +/** + * @internal Frees the memory block allocated for a message. + * @param args arguments + * @return @ref ICALL_ERRNO_SUCCESS + */ +static ICall_Errno ICall_primFreeMsg(ICall_FreeArgs * args) +{ + ICall_MsgHdr * hdr = (ICall_MsgHdr *) args->ptr - 1; + ICall_heapFree(hdr); + return ICALL_ERRNO_SUCCESS; +} + +/** + * Allocates a memory block. + * Note that this function is for use by ICall implementation. + * + * @param size size in bytes + * @return pointer to the allocated memory block or NULL + */ +void * ICall_mallocImpl(uint_fast16_t size) +{ + return ICall_heapMalloc(size); +} + +/** + * Frees a memory block. + * Note that this function is for use by ICall implementation. + * + * @param ptr pointer to the memory block + */ +void ICall_freeImpl(void * ptr) +{ + ICall_heapFree(ptr); +} + +/** + * @internal Allocates a memory block + * @param args arguments + * @return @ref ICALL_ERRNO_SUCCESS when successful.
+ * @ref ICALL_ERRNO_NO_RESOURCE when memory block cannot + * be allocated. + */ +static ICall_Errno ICall_primMalloc(ICall_AllocArgs * args) +{ + args->ptr = ICall_heapMalloc(args->size); + if (args->ptr == NULL) + { + return ICALL_ERRNO_NO_RESOURCE; + } + return ICALL_ERRNO_SUCCESS; +} + +/** + * @internal Frees a memory block + * @param args arguments + * @return @ref ICALL_ERRNO_SUCCESS + */ +static ICall_Errno ICall_primFree(ICall_FreeArgs * args) +{ + ICall_heapFree(args->ptr); + return ICALL_ERRNO_SUCCESS; +} +#endif /* ICALL_JT */ + +/** + * @internal Queues a message to a message queue. + * @param q_ptr message queue + * @param msg_ptr message pointer + */ +static void ICall_msgEnqueue(ICall_MsgQueue * q_ptr, void * msg_ptr) +{ + void * list; + ICall_CSState key; + + // Hold off interrupts + key = ICall_enterCSImpl(); + + ICALL_MSG_NEXT(msg_ptr) = NULL; + // If first message in queue + if (*q_ptr == NULL) + { + *q_ptr = msg_ptr; + } + else + { + // Find end of queue + for (list = *q_ptr; ICALL_MSG_NEXT(list) != NULL; list = ICALL_MSG_NEXT(list)) + ; + + // Add message to end of queue + ICALL_MSG_NEXT(list) = msg_ptr; + } + + // Re-enable interrupts + ICall_leaveCSImpl(key); +} + +/** + * @internal Dequeues a message from a message queue + * @param q_ptr message queue pointer + * @return Dequeued message pointer or NULL if none. + */ +static void * ICall_msgDequeue(ICall_MsgQueue * q_ptr) +{ + void * msg_ptr = NULL; + ICall_CSState key; + + // Hold off interrupts + key = ICall_enterCSImpl(); + + if (*q_ptr != NULL) + { + // Dequeue message + msg_ptr = *q_ptr; + *q_ptr = ICALL_MSG_NEXT(msg_ptr); + ICALL_MSG_NEXT(msg_ptr) = NULL; + ICALL_MSG_DEST_ID(msg_ptr) = ICALL_UNDEF_DEST_ID; + } + + // Re-enable interrupts + ICall_leaveCSImpl(key); + + return msg_ptr; +} + +/** + * @internal Prepends a list of messages to a message queue + * @param q_ptr message queue pointer + * @param head message list to prepend + */ +static void ICall_msgPrepend(ICall_MsgQueue * q_ptr, ICall_MsgQueue head) +{ + void * msg_ptr = NULL; + ICall_CSState key; + + // Hold off interrupts + key = ICall_enterCSImpl(); + + if (head != NULL) + { + /* Find the end of the queue */ + msg_ptr = head; + while (ICALL_MSG_NEXT(msg_ptr) != NULL) + { + msg_ptr = ICALL_MSG_NEXT(msg_ptr); + } + ICALL_MSG_NEXT(msg_ptr) = *q_ptr; + *q_ptr = head; + } + + // Re-enable interrupts + ICall_leaveCSImpl(key); +} + +#ifndef ICALL_JT +/** + * @internal Sends a message to an entity. + * @param args arguments + * @return @ref ICALL_ERRNO_SUCCESS when successful.
+ * @ref ICALL_ERRNO_INVALID_PARAMETER when either src + * or dest is not a valid entity id or when + * dest is an entity id of an entity that does + * not receive a message + * (e.g., ICall primitive service entity). + */ +static ICall_Errno ICall_primSend(ICall_SendArgs * args) +{ + ICall_CSState key; + ICall_MsgHdr * hdr = (ICall_MsgHdr *) args->msg - 1; + + if (args->dest.entityId >= ICALL_MAX_NUM_ENTITIES || args->src >= ICALL_MAX_NUM_ENTITIES) + { + return ICALL_ERRNO_INVALID_PARAMETER; + } + key = ICall_enterCSImpl(); + if (!ICall_entities[args->dest.entityId].task) + { + ICall_leaveCSImpl(key); + return ICALL_ERRNO_INVALID_PARAMETER; + } + + ICall_leaveCSImpl(key); + /* Note that once the entry is valid, + * the value does not change and hence it is OK + * to leave the critical section. + */ + + hdr->srcentity = args->src; + hdr->dstentity = args->dest.entityId; + hdr->format = args->format; + ICall_msgEnqueue(&ICall_entities[args->dest.entityId].task->queue, args->msg); + ICALL_SYNC_HANDLE_POST(ICall_entities[args->dest.entityId].task->syncHandle); + + return ICALL_ERRNO_SUCCESS; +} + +/** + * @internal Retrieves a message, queued to receive queue of the calling thread. + * + * @param args arguments + * @return @ref ICALL_ERRNO_SUCCESS when a message was successfully + * retrieved.
+ * @ref ICALL_ERRNO_NOMSG when no message was queued to + * the receive queue at the moment.
+ * @ref ICALL_ERRNO_UNKNOWN_THREAD when the calling thread + * does not have a received queue associated with it. + * This happens when neither ICall_enrollService() nor + * ICall_registerApp() was ever called from the calling + * thread. + */ +static ICall_Errno ICall_primFetchMsg(ICall_FetchMsgArgs * args) +{ + Task_Handle taskhandle = Task_self(); + ICall_TaskEntry * taskentry = ICall_searchTask(taskhandle); + ICall_MsgHdr * hdr; + + if (!taskentry) + { + return ICALL_ERRNO_UNKNOWN_THREAD; + } + /* Successful */ + args->msg = ICall_msgDequeue(&taskentry->queue); + + if (args->msg == NULL) + { + return ICALL_ERRNO_NOMSG; + } + hdr = (ICall_MsgHdr *) args->msg - 1; + args->src.entityId = hdr->srcentity; + args->dest = hdr->dstentity; + return ICALL_ERRNO_SUCCESS; +} +#endif /* ICALL_JT */ + +/** + * @internal + * Transforms and entityId into a serviceId. + * @param entityId entity id + * @param servId pointer to a variable to store + * the resultant service id + * @return @ICALL_ERRNO_SUCCESS if the transformation was successful. + * @ICALL_ERRNO_INVALID_SERVICE if no matching service + * is found for the entity id. + */ +static ICall_Errno ICall_primEntityId2ServiceId(ICall_EntityID entityId, ICall_ServiceEnum * servId) +{ + if (entityId >= ICALL_MAX_NUM_ENTITIES || ICall_entities[entityId].service == ICALL_SERVICE_CLASS_INVALID_ENTRY || + ICall_entities[entityId].service == ICALL_SERVICE_CLASS_APPLICATION) + { + return ICALL_ERRNO_INVALID_SERVICE; + } + *servId = ICall_entities[entityId].service; + return ICALL_ERRNO_SUCCESS; +} + +#ifndef ICALL_JT +/** + * @internal Transforms and entityId into a serviceId. + * @param args arguments + * @return return values corresponding to those of ICall_entityId2ServiceId() + */ +static ICall_Errno ICall_primE2S(ICall_EntityId2ServiceIdArgs * args) +{ + return ICall_primEntityId2ServiceId(args->entityId, &args->servId); +} + +/** + * @internal Sends a message to a registered server. + * @param args arguments corresponding to those of ICall_sendServiceMsg(). + * @return @ref ICALL_ERRNO_SUCCESS when successful.
+ * @ref ICALL_ERRNO_INVALID_SERVICE when the 'dest' + * is unregistered service.
+ * @ref ICALL_ERRNO_INVALID_PARAMETER when the 'src' + * is not a valid entity id or when 'dest' is + * is a service that does not receive a message + * (such as ICall primitive service). + */ +static ICall_Errno ICall_primSendServiceMsg(ICall_SendArgs * args) +{ + ICall_EntityID dstentity = ICall_searchServiceEntity(args->dest.servId); + + if (dstentity == ICALL_INVALID_ENTITY_ID) + { + return ICALL_ERRNO_INVALID_SERVICE; + } + args->dest.entityId = dstentity; + return ICall_primSend(args); +} + +/** + * @internal Retrieves a message received at the message queue + * associated with the calling thread. + * + * Note that this function should be used by an application + * which does not expect any message from non-server entity. + * + * @param args arguments corresponding to those of ICall_fetchServiceMsg() + * @return @ref ICALL_ERRNO_SUCCESS when the operation was successful + * and a message was retrieved.
+ * @ref ICALL_ERRNO_NOMSG when there is no queued message + * at the moment.
+ * @ref ICALL_ERRNO_CORRUPT_MSG when a message queued in + * front of the thread's receive queue was not sent by + * a server. Note that in this case, the message is + * not retrieved but thrown away.
+ * @ref ICALL_ERRNO_UNKNOWN_THREAD when this function is + * called from a thread which has not registered + * an entity, either through ICall_enrollService() + * or through ICall_registerApp(). + */ +static ICall_Errno ICall_primFetchServiceMsg(ICall_FetchMsgArgs * args) +{ + ICall_ServiceEnum servId; + ICall_Errno errno = ICall_primFetchMsg(args); + if (errno == ICALL_ERRNO_SUCCESS) + { + if (ICall_primEntityId2ServiceId(args->src.entityId, &servId) != ICALL_ERRNO_SUCCESS) + { + /* Source entity ID cannot be translated to service id */ + ICall_freeMsg(args->msg); + return ICALL_ERRNO_CORRUPT_MSG; + } + args->src.servId = servId; + +#ifdef ICALL_EVENTS + /* + * Because Events are binary flags, the task's queue must be checked for + * any remaining messages. If there are the ICall event flag must be + * re-posted due to it being cleared on the last pend. + */ + ICall_primRepostSync(); +#endif // ICALL_EVENTS + } + return errno; +} +#endif /* ICALL_JT */ +/** + * @internal + * Converts milliseconds to number of ticks. + * @param msecs milliseconds + * @param ticks pointer to a variable to store the resultant number of ticks + * @return @ref ICALL_ERRNO_SUCCESS when successful
+ * @ref ICALL_ERRNO_INVALID_PARAMETER when conversion failed + * as the input goes out of range for the output data type. + */ +static ICall_Errno ICall_msecs2Ticks(uint_fast32_t msecs, uint32_t * ticks) +{ + uint_fast64_t intermediate = msecs; + + /*convert to microSec*/ + intermediate *= 1000; + /*divide with the ticks perios*/ + intermediate /= ICall_getTickPeriod(); + if (intermediate >= ((uint_fast64_t) 1 << (sizeof(uint32_t) * 8 - 1))) + { + /* Out of range. + * Note that we use only half of the range so that client can + * determine whether the time has passed or time has yet to come. + */ + return ICALL_ERRNO_INVALID_PARAMETER; + } + *ticks = (uint32_t) intermediate; + return ICALL_ERRNO_SUCCESS; +} + +#ifndef ICALL_JT +/** + * @internal + * Waits for a signal to the synchronization object associated with the calling + * thread. + * + * Note that the synchronization object associated with a thread is signaled + * when a message is queued to the message receive queue of the thread + * or when ICall_signal() function is called onto the synchronization object. + * + * @param args arguments corresponding to those of ICall_wait(). + * @return @ref ICALL_ERRNO_SUCCESS when the synchronization object is + * signaled.
+ * @ref ICALL_ERRNO_TIMEOUT when designated timeout period + * has passed since the call of the function without + * the synchronization object being signaled.
+ * @ref ICALL_ERRNO_INVALID_PARAMETER when the milliseconds + * is greater than the value of ICall_getMaxMSecs(). + */ +static ICall_Errno ICall_primWait(ICall_WaitArgs * args) +{ + Task_Handle taskhandle = Task_self(); + ICall_TaskEntry * taskentry = ICall_searchTask(taskhandle); + uint32_t timeout; + + { + BIOS_ThreadType threadtype = BIOS_getThreadType(); + + if (threadtype == BIOS_ThreadType_Hwi || threadtype == BIOS_ThreadType_Swi) + { + /* Blocking call is not allowed from Hwi or Swi. + * Note that though theoretically, Swi or lower priority Hwi may block + * on an event to be generated by a higher priority Hwi, it is not a + * safe practice and hence it is disabled. + */ + return ICALL_ERRNO_UNKNOWN_THREAD; + } + } + + if (!taskentry) + { + return ICALL_ERRNO_UNKNOWN_THREAD; + } + /* Successful */ + if (args->milliseconds == 0) + { + timeout = BIOS_NO_WAIT; + } + else if (args->milliseconds == ICALL_TIMEOUT_FOREVER) + { + timeout = BIOS_WAIT_FOREVER; + } + else + { + /* Convert milliseconds to number of ticks */ + ICall_Errno errno = ICall_msecs2Ticks(args->milliseconds, &timeout); + if (errno != ICALL_ERRNO_SUCCESS) + { + return errno; + } + } + + if (ICALL_SYNC_HANDLE_PEND(taskentry->syncHandle, timeout)) + { + return ICALL_ERRNO_SUCCESS; + } + + return ICALL_ERRNO_TIMEOUT; +} + +/** + * @internal signals a synchronziation object. + * @param args arguments corresponding to those of ICall_signal() + * @return return value corresponding to those of ICall_signal() + */ +static ICall_Errno ICall_primSignal(ICall_SignalArgs * args) +{ + ICALL_SYNC_HANDLE_POST(args->syncHandle); + return ICALL_ERRNO_SUCCESS; +} + +/** + * @internal aborts program + * @param args arguments corresponding to those of ICall_abort() + * @return return value corresponding to those of ICall_abort() + */ +static ICall_Errno ICall_primAbort(ICall_FuncArgsHdr * args) +{ + ICALL_HOOK_ABORT_FUNC(); + return ICALL_ERRNO_SUCCESS; +} + +/** + * @internal Enables an interrupt. + * @param args arguments corresponding to those of ICall_enableint() + * @return return values corresponding to those of ICall_enableint() + */ +static ICall_Errno ICall_primEnableint(ICall_intNumArgs * args) +{ + Hwi_enableinterrupt(args->intnum); + return ICALL_ERRNO_SUCCESS; +} + +/** + * @internal Disables an interrupt. + * @param args arguments corresponding to those of ICall_disableint() + * @return return values corresponding to those of ICall_disableint() + */ +static ICall_Errno ICall_primDisableint(ICall_intNumArgs * args) +{ + Hwi_disableinterrupt(args->intnum); + return ICALL_ERRNO_SUCCESS; +} + +/** + * @internal Enables master interrupt and context switching. + * @param args arguments corresponding to those of ICall_enableMint() + * @return return values corresponding to those of ICall_enableMint() + */ +static ICall_Errno ICall_primEnableMint(ICall_FuncArgsHdr * args) +{ + Hwi_enable(); + Swi_enable(); + return ICALL_ERRNO_SUCCESS; +} + +/** + * @internal Disables master interrupt and context switching. + * @param args arguments corresponding to those of ICall_disableMint() + * @return return values corresponding to those of ICall_disableMint() + */ +static ICall_Errno ICall_primDisableMint(ICall_FuncArgsHdr * args) +{ + Swi_disable(); + Hwi_disable(); + return ICALL_ERRNO_SUCCESS; +} + +/** + * @internal registers an interrupt service routine + * @param args arguments corresponding to those of ICall_registerISR() + * @return return values corresponding to those of ICall_registerISR() + */ +static ICall_Errno ICall_primRegisterISR(ICall_RegisterISRArgs * args) +{ + Hwi_Params hwiParams; + + Hwi_Params_init(&hwiParams); + hwiParams.priority = 0xE0; // default all registered ints to lowest priority + + if (Hwi_create(args->intnum, (void (*)((void *) )) args->isrfunc, &hwiParams, NULL) == NULL) + { + ICALL_HOOK_ABORT_FUNC(); + return ICALL_ERRNO_NO_RESOURCE; + } + return ICALL_ERRNO_SUCCESS; +} + +/** + * @internal registers an interrupt service routine + * @param args arguments corresponding to those of ICall_registerISR_Ext() + * @return return values corresponding to those of ICall_registerISR_ext() + */ +static ICall_Errno ICall_primRegisterISR_Ext(ICall_RegisterISRArgs_Ext * args) +{ + Hwi_Params hwiParams; + + Hwi_Params_init(&hwiParams); + hwiParams.priority = args->intPriority; + + if (Hwi_create(args->intnum, (void (*)((void *) )) args->isrfunc, &hwiParams, NULL) == NULL) + { + ICALL_HOOK_ABORT_FUNC(); + return ICALL_ERRNO_NO_RESOURCE; + } + return ICALL_ERRNO_SUCCESS; +} + +/** + * @internal Gets tick counter value + * @param args arguments corresponding to those of ICall_getTicks() + * @return return values corresponding to those of ICall_getTicks() + */ +static ICall_Errno ICall_primGetTicks(ICall_Getuint32_tArgs * args) +{ + args->value = Clock_getTicks(); + return ICALL_ERRNO_SUCCESS; +} +#endif /* ICALL_JT */ + +/** + * @internal + * Clock event handler function. + * This function is used to implement the wakeup scheduler. + * + * @param arg an @ref ICall_ScheduleEntry + */ + +static void ICall_clockFunc(uintptr_t arg) +{ + ICall_ScheduleEntry * entry = (ICall_ScheduleEntry *) arg; + + entry->cback(entry->arg); +} + +#ifndef ICALL_JT +/** + * @internal + * Set up or restart a timer. + * + * @param args arguments corresponding to those of ICall_setTimer() + * @return @ref ICALL_ERRNO_SUCCESS when successful;
+ * @ref ICALL_ERRNO_INVALID_PARAMETER if timer designated by the + * timer ID value was not set up before. + * @ref ICALL_ERRNO_NO_RESOURCE when ran out of resource. + * Check ICall heap size and OS heap size if this happens. + */ +static ICall_Errno ICall_primSetTimer(ICall_SetTimerArgs * args) +{ + ICall_ScheduleEntry * entry; + + if (args->timerid == ICALL_INVALID_TIMER_ID) + { + Clock_Params params; + + /* Create a new timer */ + entry = ICall_heapMalloc(sizeof(ICall_ScheduleEntry)); + if (entry == NULL) + { + /* allocation failed */ + return ICALL_ERRNO_NO_RESOURCE; + } + Clock_Params_init(¶ms); + params.startFlag = FALSE; + params.period = 0; + params.arg = ((void *) ) entry; + entry->clock = Clock_create(ICall_clockFunc, args->timeout, ¶ms, NULL); + if (!entry->clock) + { + /* abort */ + ICall_abort(); + ICall_heapFree(entry); + return ICALL_ERRNO_NO_RESOURCE; + } + entry->cback = args->cback; + entry->arg = args->arg; + args->timerid = (ICall_TimerID) entry; + } + else + { + ICall_CSState key; + + entry = (ICall_ScheduleEntry *) args->timerid; + + /* Critical section is entered to disable interrupts that might cause call + * to callback due to race condition */ + key = ICall_enterCriticalSection(); + Clock_stop(entry->clock); + entry->arg = args->arg; + ICall_leaveCriticalSection(key); + } + + Clock_setTimeout(entry->clock, args->timeout); + Clock_start(entry->clock); + + return ICALL_ERRNO_SUCCESS; +} + +/** + * @internal + * Set up or restart a timer. + * + * @param args arguments corresponding to those of ICall_setTimerMSecs() + * @return @ref ICALL_ERRNO_SUCCESS when successful;
+ * @ref ICALL_ERRNO_INVALID_PARAMETER when msecs is greater than + * maximum value supported. + * @ref ICALL_ERRNO_NO_RESOURCE when ran out of resource. + * Check ICall heap size and OS heap size if this happens. + */ +static ICall_Errno ICall_primSetTimerMSecs(ICall_SetTimerArgs * args) +{ + uint32_t ticks; + /* Convert to tick time */ + ICall_Errno errno = ICall_msecs2Ticks(args->timeout, &ticks); + + if (errno != ICALL_ERRNO_SUCCESS) + { + return errno; + } + args->timeout = ticks; + return ICall_primSetTimer(args); +} + +/** + * @internal + * Stops a timer. + * + * @param args arguments corresponding to those of ICall_stopTimer() + * + * @return @ref ICALL_ERRNO_SUCCESS when successful;
+ * @ref ICALL_ERRNO_INVALID_PARAMETER + * if id is @ref ICALL_INVALID_TIMER_ID. + */ +static ICall_Errno ICall_primStopTimer(ICall_StopTimerArgs * args) +{ + ICall_ScheduleEntry * entry = (ICall_ScheduleEntry *) args->timerid; + + if (args->timerid == ICALL_INVALID_TIMER_ID) + { + return ICALL_ERRNO_INVALID_PARAMETER; + } + + Clock_stop(entry->clock); + return ICALL_ERRNO_SUCCESS; +} + +/** + * @internal Gets tick period + * @param args arguments corresponding to those of ICall_getTickPeriod() + * @return return values corresponding to those of ICall_getTickPeriod() + */ +static ICall_Errno ICall_primGetTickPeriod(ICall_Getuint32_tArgs * args) +{ + args->value = Clock_tickPeriod; + return ICALL_ERRNO_SUCCESS; +} + +/** + * @internal Gets maximum period supported + * @param args arguments corresponding to those of ICall_getMaxMSecs() + * @return return values corresponding to those of ICall_getMaxMSecs() + */ +static ICall_Errno ICall_primGetMaxMSecs(ICall_Getuint32_tArgs * args) +{ + uint_fast64_t tmp = ((uint_fast64_t) 0x7ffffffful) * Clock_tickPeriod; + tmp /= 1000; + if (tmp >= 0x80000000ul) + { + tmp = 0x7ffffffful; + } + args->value = (uint_least32_t) tmp; + return ICALL_ERRNO_SUCCESS; +} + +/** + * @internal + * Waits for a message that matches comparison + * + * @param args arguments corresponding to those of ICall_waitMatch(). + * @return @ref ICALL_ERRNO_SUCCESS when the synchronization object is + * signaled.
+ * @ref ICALL_ERRNO_TIMEOUT when designated timeout period + * has passed since the call of the function without + * the semaphore being signaled.
+ * @ref ICALL_ERRNO_INVALID_PARAMETER when the milliseconds + * is greater than the value of ICall_getMaxMSecs(). + */ +static ICall_Errno ICall_primWaitMatch(ICall_WaitMatchArgs * args) +{ + Task_Handle taskhandle = Task_self(); + ICall_TaskEntry * taskentry = ICall_searchTask(taskhandle); + ICall_MsgQueue prependQueue = NULL; +#ifndef ICALL_EVENTS + uint_fast16_t consumedCount = 0; +#endif + uint32_t timeout; + uint_fast32_t timeoutStamp; + ICall_Errno errno; + + { + BIOS_ThreadType threadtype = BIOS_getThreadType(); + + if (threadtype == BIOS_ThreadType_Hwi || threadtype == BIOS_ThreadType_Swi) + { + /* Blocking call is not allowed from Hwi or Swi. + * Note that though theoretically, Swi or lower priority Hwi may block + * on an event to be generated by a higher priority Hwi, it is not a + * safe practice and hence it is disabled. + */ + return ICALL_ERRNO_UNKNOWN_THREAD; + } + } + + if (!taskentry) + { + return ICALL_ERRNO_UNKNOWN_THREAD; + } + /* Successful */ + if (args->milliseconds == 0) + { + timeout = BIOS_NO_WAIT; + } + else if (args->milliseconds == ICALL_TIMEOUT_FOREVER) + { + timeout = BIOS_WAIT_FOREVER; + } + else + { + /* Convert milliseconds to number of ticks */ + errno = ICall_msecs2Ticks(args->milliseconds, &timeout); + if (errno != ICALL_ERRNO_SUCCESS) + { + return errno; + } + } + + errno = ICALL_ERRNO_TIMEOUT; + timeoutStamp = Clock_getTicks() + timeout; + while (ICALL_SYNC_HANDLE_PEND(taskentry->syncHandle, timeout)) + { + ICall_FetchMsgArgs fetchArgs; + ICall_ServiceEnum servId; + errno = ICall_primFetchMsg(&fetchArgs); + if (errno == ICALL_ERRNO_SUCCESS) + { + if (ICall_primEntityId2ServiceId(fetchArgs.src.entityId, &servId) == ICALL_ERRNO_SUCCESS) + { + if (args->matchFn(servId, fetchArgs.dest, fetchArgs.msg)) + { + /* Matching message found*/ + args->servId = servId; + args->dest = fetchArgs.dest; + args->msg = fetchArgs.msg; + errno = ICALL_ERRNO_SUCCESS; + break; + } + } + /* Message was received but it wasn't expected one. + * Add to the prepend queue */ + ICall_msgEnqueue(&prependQueue, fetchArgs.msg); +#ifdef ICALL_EVENTS + /* Event are binary semaphore, so if several messsages are posted while + * we are processing one, it's possible that some of them are 'missed' and + * not processed. Sending a event to ourself force this loop to run until + * all the messages in the queue are processed. + */ + ICALL_SYNC_HANDLE_POST(taskentry->syncHandle); +#endif + } + + /* Prepare for timeout exit */ + errno = ICALL_ERRNO_TIMEOUT; + +#ifndef ICALL_EVENTS + /* Keep the decremented semaphore count */ + consumedCount++; +#endif /* ICALL_EVENTS */ + if (timeout != BIOS_WAIT_FOREVER && timeout != BIOS_NO_WAIT) + { + /* Readjust timeout */ + uint32_t newTimeout = timeoutStamp - Clock_getTicks(); + if (newTimeout == 0 || newTimeout > timeout) + { + break; + } + timeout = newTimeout; + } + } + +#ifdef ICALL_EVENTS + /* + * Because Events are binary semaphores, the task's queue must be checked for + * any remaining messages. If there are, the ICall event flag must be + * re-posted due to it being cleared on the last pend. + */ + ICall_primRepostSync(); +#endif // ICALL_EVENTS + + /* Prepend retrieved irrelevant messages */ + ICall_msgPrepend(&taskentry->queue, prependQueue); +#ifndef ICALL_EVENTS + /* Re-increment the consumed semaphores */ + for (; consumedCount > 0; consumedCount--) + { + Semaphore_post(taskentry->syncHandle); + } +#endif /* ICALL_EVENTS */ + return errno; +} + +/** + * @internal + * Retrieves an entity ID of an entity associated with the calling thread. + * + * @param args arguments corresponding to those of ICall_getEntityId(). + * @return @ref ICALL_ERRNO_SUCCESS when successful.
+ * @ref ICALL_ERRNO_UNKNOWN_THREAD when no entity was associated + * with the calling thread. + */ +static ICall_Errno ICall_primGetEntityId(ICall_GetEntityIdArgs * args) +{ + Task_Handle taskhandle = Task_self(); + ICall_CSState key; + size_t i; + + { + BIOS_ThreadType threadtype = BIOS_getThreadType(); + + if (threadtype == BIOS_ThreadType_Hwi || threadtype == BIOS_ThreadType_Swi) + { + return ICALL_ERRNO_UNKNOWN_THREAD; + } + } + + key = ICall_enterCSImpl(); + for (i = 0; i < ICALL_MAX_NUM_ENTITIES; i++) + { + if (ICall_entities[i].service == ICALL_SERVICE_CLASS_INVALID_ENTRY) + { + /* Not found */ + break; + } + if (ICall_entities[i].task->task == taskhandle) + { + /* Found */ + args->entity = i; + ICall_leaveCSImpl(key); + return ICALL_ERRNO_SUCCESS; + } + } + ICall_leaveCSImpl(key); + return ICALL_ERRNO_UNKNOWN_THREAD; +} + +/** + * @internal + * Checks whether the calling thread provides the designated service. + * + * @param args arguments corresponding to those of ICall_threadServes(). + * @return @ref ICALL_ERRNO_SUCCESS when successful.
+ * @ref ICALL_ERRNO_UNKNOWN_THREAD when the calling thread is + * unrecognized. + * @ref ICALL_ERRNO_INVALID_SERVICE if the service id is not enrolled + * by any thread. + */ +static ICall_Errno ICall_primThreadServes(ICall_ThreadServesArgs * args) +{ + Task_Handle taskhandle; + ICall_CSState key; + size_t i; + + { + BIOS_ThreadType threadtype = BIOS_getThreadType(); + + if (threadtype == BIOS_ThreadType_Hwi || threadtype == BIOS_ThreadType_Swi) + { + return ICALL_ERRNO_UNKNOWN_THREAD; + } + } + + taskhandle = Task_self(); + + key = ICall_enterCSImpl(); + for (i = 0; i < ICALL_MAX_NUM_ENTITIES; i++) + { + if (ICall_entities[i].service == ICALL_SERVICE_CLASS_INVALID_ENTRY) + { + /* Not found */ + break; + } + else if (ICall_entities[i].service == args->servId) + { + args->result = (uint_fast8_t) (ICall_entities[i].task->task == taskhandle); + ICall_leaveCSImpl(key); + return ICALL_ERRNO_SUCCESS; + } + } + ICall_leaveCSImpl(key); + return ICALL_ERRNO_INVALID_SERVICE; +} + +/** + * @internal + * Creates an RTOS task. + * + * @param args arguments corresponding to those of ICall_createTask(). + * @return @ref ICALL_ERRNO_SUCCESS when successful.
+ * @ref ICALL_ERRNO_NO_RESOURCE when task creation failed. + */ +static ICall_Errno ICall_primCreateTask(ICall_CreateTaskArgs * args) +{ + /* Task_Params is a huge structure. + * To reduce stack usage, heap is used instead. + * This implies that ICall_createTask() must be called before heap + * space may be exhausted. + */ + Task_Params * params = (Task_Params *) ICall_heapMalloc(sizeof(Task_Params)); + Task_Handle task; + + if (params == NULL) + { + return ICALL_ERRNO_NO_RESOURCE; + } + + Task_Params_init(params); + params->priority = args->priority; + params->stackSize = args->stacksize; + params->arg0 = args->arg; + + task = Task_create((Task_FuncPtr) args->entryfn, params, NULL); + ICall_heapFree(params); + + if (task == NULL) + { + return ICALL_ERRNO_NO_RESOURCE; + } + return ICALL_ERRNO_SUCCESS; +} +#endif /* ICALL_JT */ + +#ifdef ICALL_RTOS_EVENT_API +/** + * @internal + * Creates an event. + * + * @param args arguments corresponding to those of ICall_createEvent(). + * @return @ref ICALL_ERRNO_SUCCESS when successful.
+ * @ref ICALL_ERRNO_NO_RESOURCE when task creation failed. + */ +static ICall_Errno ICall_primCreateEvent(ICall_CreateEventArgs * args) +{ + args->event = Event_create(NULL, NULL); + + if (args->event == NULL) + { + return ICALL_ERRNO_NO_RESOURCE; + } + return ICALL_ERRNO_SUCCESS; +} +#endif /* ICALL_RTOS_EVENT_API */ +#ifdef ICALL_RTOS_SEMAPHORE_API +/** + * @internal + * Creates a semaphore. + * + * @param args arguments corresponding to those of ICall_createSemaphore(). + * @return @ref ICALL_ERRNO_SUCCESS when successful.
+ * @ref ICALL_ERRNO_NO_RESOURCE when task creation failed. + */ +static ICall_Errno ICall_primCreateSemaphore(ICall_CreateSemaphoreArgs * args) +{ + /* Semaphore_Params is a huge structure. + * To reduce stack usage, heap is used instead. + * This implies that ICall_createSemaphore() must be called before heap + * space may be exhausted. + */ + Semaphore_Params * semParams = (Semaphore_Params *) ICall_heapMalloc(sizeof(Semaphore_Params)); + + if (semParams == NULL) + { + return ICALL_ERRNO_NO_RESOURCE; + } + + Semaphore_Params_init(semParams); + if (args->mode == ICALL_SEMAPHORE_MODE_BINARY) + { + semParams->mode = Semaphore_Mode_BINARY; + } + + args->sem = Semaphore_create(args->initcount, semParams, NULL); + ICall_heapFree(semParams); + + if (args->sem == NULL) + { + return ICALL_ERRNO_NO_RESOURCE; + } + return ICALL_ERRNO_SUCCESS; +} +#endif /* ICALL_RTOS_SEMAPHORE_API */ +#ifdef ICALL_RTOS_EVENT_API +/** + * @internal + * Waits on a ICALL_MSG_EVENT_ID. + * + * @param args arguments corresponding to those of ICall_waitEvent(). + * @return @ref ICALL_ERRNO_SUCCESS when successful.
+ * @ref ICALL_ERRNO_TIMEOUT when timeout occurred. + */ +static ICall_Errno ICall_primWaitEvent(ICall_WaitEventArgs * args) +{ + uint32_t timeout; + + if (args->milliseconds == 0) + { + timeout = BIOS_NO_WAIT; + } + else if (args->milliseconds == ICALL_TIMEOUT_FOREVER) + { + timeout = BIOS_WAIT_FOREVER; + } + else + { + ICall_Errno errno = ICall_msecs2Ticks(args->milliseconds, &timeout); + if (errno != ICALL_ERRNO_SUCCESS) + { + return errno; + } + } + + if (Event_pend(args->event, 0, ICALL_MSG_EVENT_ID, timeout)) + { + return ICALL_ERRNO_SUCCESS; + } + return ICALL_ERRNO_TIMEOUT; +} +#endif /* ICALL_RTOS_EVENT_API */ + +#ifdef ICALL_RTOS_SEMAPHORE_API +/** + * @internal + * Waits on a semaphore. + * + * @param args arguments corresponding to those of ICall_waitSemaphore(). + * @return @ref ICALL_ERRNO_SUCCESS when successful.
+ * @ref ICALL_ERRNO_TIMEOUT when timeout occurred. + */ +static ICall_Errno ICall_primWaitSemaphore(ICall_WaitSemaphoreArgs * args) +{ + uint32_t timeout; + + if (args->milliseconds == 0) + { + timeout = BIOS_NO_WAIT; + } + else if (args->milliseconds == ICALL_TIMEOUT_FOREVER) + { + timeout = BIOS_WAIT_FOREVER; + } + else + { + ICall_Errno errno = ICall_msecs2Ticks(args->milliseconds, &timeout); + if (errno != ICALL_ERRNO_SUCCESS) + { + return errno; + } + } + if (Semaphore_pend(args->sem, timeout)) + { + return ICALL_ERRNO_SUCCESS; + } + return ICALL_ERRNO_TIMEOUT; +} +#endif /* ICALL_RTOS_SEMAPHORE_API */ + +#ifdef ICALL_RTOS_SEMAPHORE_API +/** + * @internal signals a semaphore + * @param args arguments corresponding to those of ICall_signal() + * @return return value corresponding to those of ICall_signal() + */ +static ICall_Errno ICall_primPostSemaphore(ICall_SignalArgs * args) +{ + Semaphore_post(args->syncHandle); + return ICALL_ERRNO_SUCCESS; +} +#endif /* ICALL_RTOS_EVENT_API */ +#ifdef ICALL_RTOS_EVENT_API +/** + * @internal signals an event + * @param args arguments corresponding to those of ICall_signal() + * @return return value corresponding to those of ICall_signal() + */ +static ICall_Errno ICall_primPostEvent(ICall_SignalEventsArgs * args) +{ + Event_post(args->syncHandle, args->events); + return ICALL_ERRNO_SUCCESS; +} +#endif /* ICALL_RTOS_EVENT_API */ +/** + * @internal Primitive service function ID to handler function map + */ +#ifndef ICALL_JT +static const struct _icall_primsvcfunc_map_entry_t +{ +#ifdef COVERAGE_TEST + size_t id; +#endif /* COVERAGE_TEST */ + ICall_PrimSvcFunc func; +} ICall_primSvcFuncs[] = { + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_ENROLL, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICall_primEnroll }, + + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_REGISTER_APP, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICall_primRegisterApp }, + + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_MSG_ALLOC, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICall_primAllocMsg }, + + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_MSG_FREE, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICall_primFreeMsg }, + + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_MALLOC, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICall_primMalloc }, + + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_FREE, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICall_primFree }, + + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_SEND_MSG, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICall_primSend }, + + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_FETCH_MSG, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICall_primFetchMsg }, + + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_SEND_SERV_MSG, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICall_primSendServiceMsg }, + + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_FETCH_SERV_MSG, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICall_primFetchServiceMsg }, + + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_WAIT, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICall_primWait }, + + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_SIGNAL, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICall_primSignal }, + + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_ABORT, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICall_primAbort }, + + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_ENABLE_int, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICall_primEnableint }, + + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_DISABLE_int, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICall_primDisableint }, + + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_ENABLE_Mint, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICall_primEnableMint }, + + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_DISABLE_Mint, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICall_primDisableMint }, + + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_REGISTER_ISR, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICall_primRegisterISR }, + + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_GET_TICKS, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICall_primGetTicks }, + + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_SET_TIMER_MSECS, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICall_primSetTimerMSecs }, + + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_GET_TICK_PERIOD, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICall_primGetTickPeriod }, + + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_GET_MAX_MILLISECONDS, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICall_primGetMaxMSecs }, + + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_ENTITY2SERVICE, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICall_primE2S }, + + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_PWR_UPD_ACTIVITY_COUNTER, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICallPlatform_pwrUpdActivityCounter }, + + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_PWR_REGISTER_NOTIFY, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICallPlatform_pwrRegisterNotify }, + + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_WAIT_MATCH, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICall_primWaitMatch }, + + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_GET_ENTITY_ID, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICall_primGetEntityId }, + + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_SET_TIMER, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICall_primSetTimer }, + + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_STOP_TIMER, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICall_primStopTimer }, + + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_PWR_CONFIG_AC_ACTION, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICallPlatform_pwrConfigACAction }, + + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_PWR_REQUIRE, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICallPlatform_pwrRequire }, + + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_PWR_DISPENSE, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICallPlatform_pwrDispense }, + + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_THREAD_SERVES, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICall_primThreadServes }, + + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_PWR_IS_STABLE_XOSC_HF, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICallPlatform_pwrIsStableXOSCHF }, + + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_PWR_GET_TRANSITION_STATE, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICallPlatform_pwrGetTransitionState }, + + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_CREATE_TASK, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICall_primCreateTask }, + +#ifdef ICALL_RTOS_SEMAPHORE_API + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_CREATE_SEMAPHORE, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICall_primCreateSemaphore }, + + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_WAIT_SEMAPHORE, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICall_primWaitSemaphore }, + +#else /* ICALL_RTOS_SEMAPHORE_API */ + + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_WAIT_SEMAPHORE, +#endif /* COVERAGE_TEST */ + NULL }, + + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_WAIT_SEMAPHORE, +#endif /* COVERAGE_TEST */ + NULL }, +#endif /* ICALL_RTOS_SEMAPHORE_API */ + + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_SWITCH_XOSC_HF, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICallPlatform_pwrSwitchXOSCHF }, + + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_PWR_GET_XOSC_STARTUP_TIME, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICallPlatform_pwrGetXOSCStartupTime }, + + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_REGISTER_ISR_EXT, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICall_primRegisterISR_Ext }, + +#ifdef ICALL_RTOS_SEMAPHORE_API + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_POST_SEMAPHORE, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICall_primPostSemaphore }, +#else /*ICALL_RTOS_SEMAPHORE_API */ + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_POST_SEMAPHORE, +#endif /* COVERAGE_TEST */ + NULL }, /* ICALL_RTOS_SEMAPHORE_API */ +#endif + +#ifdef ICALL_RTOS_EVENT_API + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_CREATE_EVENT, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICall_primCreateEvent }, + + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_WAIT_EVENT, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICall_primWaitEvent }, + + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_POST_EVENT, +#endif /* COVERAGE_TEST */ + (ICall_PrimSvcFunc) ICall_primPostEvent }, +#else /*ICALL_RTOS_EVENT_API */ + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_CREATE_EVENT, +#endif /* COVERAGE_TEST */ + NULL }, + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_WAIT_EVENT, +#endif /* COVERAGE_TEST */ + NULL }, /* ICALL_RTOS_EVENT_API */ + { +#ifdef COVERAGE_TEST + ICALL_PRIMITIVE_FUNC_POST_EVENT, +#endif /* COVERAGE_TEST */ + NULL }, /* ICALL_RTOS_EVENT_API */ +#endif /* ICALL_RTOS_EVENT_API */ +}; +/** + * @internal + * Primitive service registered handler function + * @param args arguments + * @return error code + */ +static ICall_Errno ICall_primService(ICall_FuncArgsHdr * args) +{ + if (args->func >= sizeof(ICall_primSvcFuncs) / sizeof(ICall_primSvcFuncs[0])) + { + return ICALL_ERRNO_INVALID_FUNCTION; + } + return ICall_primSvcFuncs[args->func].func(args); +} + +/** + * @internal Enrolls primitive service + */ +static void ICall_initPrim(void) +{ + ICall_entities[0].service = ICALL_SERVICE_CLASS_PRIMITIVE; + ICall_entities[0].fn = ICall_primService; + + /* Initialize heap */ + ICall_heapInit(); + + /* TODO: Think about freezing permanently allocated memory blocks + * for optimization. + * Now that multiple stack images may share the same heap. + * kick cannot be triggered by a single stack image. + * Hence, maybe there should be an alternative API to + * permanently allocate memory blocks, such as + * by allocating the blocks at the end of the heap space. */ +} +#endif /* ICALL_JT */ + +#ifdef COVERAGE_TEST +/** + * @internal + * Verification function for ICall implementation + */ +void ICall_verify(void) +{ + size_t i; + for (i = 0; i < sizeof(ICall_primSvcFuncs) / sizeof(ICall_primSvcFuncs[0]); i++) + { + if (i != ICall_primSvcFuncs[i].id) + { + ICall_abort(); + } + } +} +#endif /* COVERAGE_TEST */ + +#ifdef ICALL_JT +/** + * Registers an application. + * Note that this function must be called from the thread + * from which ICall_wait() function will be called. + * + * @param entity pointer to a variable to store entity id assigned + * to the application. + * @param msgsem pointer to a variable to store the synchronous object handle + * associated with the calling thread. + * @return @ref ICALL_ERRNO_SUCCESS when successful.
+ * @ref ICALL_ERRNO_NO_RESOURCE when ran out of resource. + */ +ICall_Errno ICall_registerApp(ICall_EntityID * entity, ICall_SyncHandle * msgSyncHdl) +{ + + size_t i; + ICall_TaskEntry * taskentry = ICall_newTask(Task_self()); + ICall_CSState key; + + if (!taskentry) + { + /* abort */ + ICALL_HOOK_ABORT_FUNC(); + return ICALL_ERRNO_NO_RESOURCE; + } + + key = ICall_enterCSImpl(); + for (i = 0; i < ICALL_MAX_NUM_ENTITIES; i++) + { + if (ICall_entities[i].service == ICALL_SERVICE_CLASS_INVALID_ENTRY) + { + /* Use this entry */ + ICall_entities[i].service = ICALL_SERVICE_CLASS_APPLICATION; + ICall_entities[i].task = taskentry; + ICall_entities[i].fn = NULL; + *entity = (ICall_EntityID) i; + *msgSyncHdl = taskentry->syncHandle; + ICall_leaveCSImpl(key); + return ICALL_ERRNO_SUCCESS; + } + } + /* abort */ + ICALL_HOOK_ABORT_FUNC(); + ICall_leaveCSImpl(key); + return (ICALL_ERRNO_NO_RESOURCE); +} + +/** + * Allocates memory block for a message. + * @param size size of the message body in bytes. + * @return pointer to the start of the message body of the newly + * allocated memory block, or NULL if the allocation + * failed. + */ +void * ICall_allocMsg(size_t size) +{ + ICall_MsgHdr * hdr = (ICall_MsgHdr *) ICall_heapMalloc(sizeof(ICall_MsgHdr) + size); + + if (!hdr) + { + return NULL; + } + hdr->len = size; + hdr->next = NULL; + hdr->dest_id = ICALL_UNDEF_DEST_ID; + return ((void *) (hdr + 1)); +} + +/** + * Frees the memory block allocated for a message. + * @param msg pointer to the start of the message body + * which was returned from ICall_allocMsg(). + */ +void ICall_freeMsg(void * msg) +{ + ICall_MsgHdr * hdr = (ICall_MsgHdr *) msg - 1; + ICall_heapFree(hdr); +} + +/** + * Sends a message to a registered server. + * @param src Entity id of the sender of the message + * @param dest Service id + * @param format Message format: + * @ref ICALL_MSG_FORMAT_KEEP, + * @ref ICALL_MSG_FORMAT_1ST_CHAR_TASK_ID or + * @ref ICALL_MSG_FORMAT_3RD_CHAR_TASK_ID. + * Message format indicates whether and which + * field of the message must be transformed + * into a implementation specific sender + * identity for an external image.
+ * When a service message interface is defined, + * it may contain a field that is not understood + * by the client but only understood by + * the system on the server's side. + * The format provides an information to the + * messaging system on such a server + * so that it can generically tag necessary + * information to the message. + * @param msg pointer to the message body to send.
+ * Note that if message is successfully sent, + * the caller should not reference the message any + * longer.
+ * However, if the function fails, the caller + * still owns the reference to the message. + * That is, caller may attempt another send, + * or may free the memory block, etc. + * @return @ref ICALL_ERRNO_SUCCESS when successful.
+ * @ref ICALL_ERRNO_INVALID_SERVICE when the 'dest' + * is unregistered service.
+ * @ref ICALL_ERRNO_INVALID_PARAMETER when the 'src' + * is an out of range entity id or when 'dest' is + * is a service that does not receive a message + * (such as ICall primitive service).
+ * Note that as far as 'src' is within the range, + * this function won't notice the 'src' entity id + * as invalid. + */ + +ICall_Errno ICall_sendServiceMsg(ICall_EntityID src, ICall_ServiceEnum dest, ICall_MSGFormat format, void * msg) +{ + ICall_EntityID dstentity = ICall_searchServiceEntity(dest); + + if (dstentity == ICALL_INVALID_ENTITY_ID) + { + return ICALL_ERRNO_INVALID_SERVICE; + } + return (ICall_send(src, dstentity, format, msg)); +} + +/** + * Retrieves a message received at the message queue + * associated with the calling thread. + * + * Note that this function should be used by an application + * which does not expect any message from non-server entity. + * + * @param src pointer to a variable to store the service id + * of the registered server which sent the retrieved + * message + * @param dest pointer to a variable to store the entity id + * of the destination of the message. + * @param msg pointer to a pointer variable to store the + * starting address of the message body being + * retrieved. + * @return @ref ICALL_ERRNO_SUCCESS when the operation was successful + * and a message was retrieved.
+ * @ref ICALL_ERRNO_NOMSG when there is no queued message + * at the moment.
+ * @ref ICALL_ERRNO_CORRUPT_MSG when a message queued in + * front of the thread's receive queue was not sent by + * a server. Note that in this case, the message is + * not retrieved but thrown away.
+ * @ref ICALL_ERRNO_UNKNOWN_THREAD when this function is + * called from a thread which has not registered + * an entity, either through ICall_enrollService() + * or through ICall_registerApp(). + */ +ICall_Errno ICall_fetchServiceMsg(ICall_ServiceEnum * src, ICall_EntityID * dest, void ** msg) +{ + ICall_ServiceEnum servId; + ICall_Errno errno = ICall_fetchMsg((ICall_EntityID *) src, dest, msg); + + if (errno == ICALL_ERRNO_SUCCESS) + { + if (ICall_primEntityId2ServiceId(*src, &servId) != ICALL_ERRNO_SUCCESS) + { + /* Source entity ID cannot be translated to service id */ + ICall_freeMsg(*msg); + return ICALL_ERRNO_CORRUPT_MSG; + } + *src = servId; + } + return (errno); +} +#if 0 +void convertMilliToTimepec(struct timespec *timeoutPosix,uint32_t timeout) +{ + timeoutPosix->tv_sec = (timeout / 1000); + timeout = timeout % 1000; + + /* 1 millisecond = 1 000 000 nanoseconds */ + timeoutPosix->tv_nsec = timeout * 1000000; +} +#endif + +/** + * Waits for a signal to the semaphore associated with the calling thread. + * + * Note that the semaphore associated with a thread is signaled + * when a message is queued to the message receive queue of the thread + * or when ICall_signal() function is called onto the semaphore. + * + * @param milliseconds timeout period in milliseconds. + * @return @ref ICALL_ERRNO_SUCCESS when the semaphore is signaled.
+ * @ref ICALL_ERRNO_TIMEOUT when designated timeout period + * has passed since the call of the function without + * the semaphore being signaled. + */ +ICall_Errno ICall_wait(uint_fast32_t milliseconds) +{ + TaskHandle_t taskhandle = Task_self(); + ICall_TaskEntry * taskentry = ICall_searchTask(taskhandle); + uint32_t timeout; + uint32_t event; + + int16_t retVal = 0; + + if (!taskentry) + { + return (ICALL_ERRNO_UNKNOWN_THREAD); + } + /* Successful */ + if (milliseconds == 0) + { + timeout = BIOS_NO_WAIT; + } + else if (milliseconds == ICALL_TIMEOUT_FOREVER) + { + timeout = BIOS_WAIT_FOREVER; + } + else + { + /* Convert milliseconds to number of ticks */ + ICall_Errno errno = ICall_msecs2Ticks(milliseconds, &timeout); + if (errno != ICALL_ERRNO_SUCCESS) + { + return (errno); + } + } + +#ifdef FREERTOS + if (HwiP_inISR()) + { + xQueueReceiveFromISR(taskentry->syncHandle, (char *) &event, NULL); + } + else + { + xQueueReceive(taskentry->syncHandle, (char *) &event, milliseconds * 100); + } +#endif + if (retVal != (-1)) + { + return (ICALL_ERRNO_SUCCESS); + } + + return (ICALL_ERRNO_TIMEOUT); +} + +/** + * Signals a semaphore. + * @param msgsem handle of a synchronous object to signal + * @return @ref ICALL_ERRNO_SUCCESS + */ +ICall_Errno ICall_signal(ICall_SyncHandle msgSyncHdl) +{ + /* 0x80000000 is an internal Event_ID */ + uint32_t msg_ptr = 0x80000000; + ICall_Errno status = ICALL_ERRNO_NO_RESOURCE; + +#ifdef FREERTOS + uint8_t statusQ; + if (HwiP_inISR()) + { + statusQ = xQueueSendFromISR(msgSyncHdl, (char *) &msg_ptr, NULL); + } + else + { + statusQ = xQueueSend(msgSyncHdl, (char *) &msg_ptr, 0); + } + + if (statusQ == pdTRUE) + { + status = ICALL_ERRNO_SUCCESS; + } +#endif + return (status); +} + +/** + * Registers a service entity + * @param service service id of the enrolling service + * @param fn handler function which handles function + * calls to the service. + * @param entity pointer to a variable to store the assigned entity id + * @param msgsem pointer to a variable to store the synchronous object handle + * associated with the calling thread. + * @return @ref ICALL_ERRNO_SUCCESS when successful.
+ * @ref ICALL_ERRNO_INVALID_PARAMETER when service id is already + * registered by another entity.
+ * @ref ICALL_ERRNO_NO_RESOURCE when maximum number of services + * are already registered. + */ +ICall_Errno ICall_enrollService(ICall_ServiceEnum service, ICall_ServiceFunc fn, ICall_EntityID * entity, + ICall_SyncHandle * msgSyncHdl) +{ + size_t i; + ICall_TaskEntry * taskentry = ICall_newTask(Task_self()); + ICall_CSState key; + + /* Note that certain service does not handle a message + * and hence, taskentry might be NULL. + */ + if (taskentry == NULL) + { + return (ICALL_ERRNO_INVALID_PARAMETER); + } + + key = ICall_enterCSImpl(); + for (i = 0; i < ICALL_MAX_NUM_ENTITIES; i++) + { + if (ICall_entities[i].service == ICALL_SERVICE_CLASS_INVALID_ENTRY) + { + /* Use this entry */ + ICall_entities[i].service = service; + ICall_entities[i].task = taskentry; + ICall_entities[i].fn = fn; + *entity = (ICall_EntityID) i; + *msgSyncHdl = taskentry->syncHandle; + + ICall_leaveCSImpl(key); + return (ICALL_ERRNO_SUCCESS); + } + else if (service == ICall_entities[i].service) + { + /* Duplicate service enrollment */ + ICall_leaveCSImpl(key); + return (ICALL_ERRNO_INVALID_PARAMETER); + } + } + /* abort */ + ICALL_HOOK_ABORT_FUNC(); + ICall_leaveCSImpl(key); + return (ICALL_ERRNO_NO_RESOURCE); +} +#ifdef FREERTOS + +/** + * Allocates a memory block. + * @param size size of the block in bytes. + * @return address of the allocated memory block or NULL + * if allocation fails. + */ + +void * ICall_heapMalloc(uint32_t size) +{ + void * ret = NULL; + ret = malloc(size); + return ret; +} + +/** + * Frees an allocated memory block. + * @param msg pointer to a memory block to free. + */ +void ICall_heapFree(void * msg) +{ + free(msg); +} + +/** + * Allocates a memory block, but check if enough memory will be left after the allocation. + * @param size size of the block in bytes. + * @return address of the allocated memory block or NULL + * if allocation fails. + */ + +void * ICall_heapMallocLimited(uint_least16_t size) +{ + return malloc(size); +} + +/** + * Get Statistic on Heap. + * @param stats pointer to a heapStats_t structure. + */ + +/* Statistics currently are not supported via ICall apis. + * Please consider to use bget statistics (or any of your internal heap statistics) */ +void ICall_heapGetStats(ICall_heapStats_t * pStats) {} + +#endif // FREERTOS +/** + * Allocates a memory block. + * @param size size of the block in bytes. + * @return address of the allocated memory block or NULL + * if allocation fails. + */ +void * ICall_malloc(uint_least16_t size) +{ + return (ICall_heapMalloc(size)); +} + +/** + * Frees an allocated memory block. + * @param msg pointer to a memory block to free. + */ +void ICall_free(void * msg) +{ + ICall_heapFree(msg); +} + +/** + * Allocates a memory block, but check if enough memory will be left after the allocation. + * @param size size of the block in bytes. + * @return address of the allocated memory block or NULL + * if allocation fails. + */ + +void * ICall_mallocLimited(uint_least16_t size) +{ + return (ICall_heapMallocLimited(size)); +} + +/** + * Get Statistic on Heap. + * @param stats pointer to a heapStats_t structure. + */ +void ICall_getHeapStats(ICall_heapStats_t * pStats) +{ + ICall_heapGetStats(pStats); +} + +#ifdef HEAPMGR_METRICS +/** + * @brief obtain heap usage metrics + * @param pBlkMax pointer to a variable to store max cnt of all blocks ever seen at once + * @param pBlkCnt pointer to a variable to store current cnt of all blocks + * @param pBlkFree pointer to a variable to store current cnt of free blocks + * @param pMemAlo pointer to a variable to store current total memory allocated + * @param pMemMax pointer to a variable to store max total memory ever allocated at once + * @param pMemUB pointer to a variable to store the upper bound of memory usage + */ +void ICall_getHeapMgrGetMetrics(uint32_t * pBlkMax, uint32_t * pBlkCnt, uint32_t * pBlkFree, uint32_t * pMemAlo, uint32_t * pMemMax, + uint32_t * pMemUB) +{ + ICall_heapMgrGetMetrics(pBlkMax, pBlkCnt, pBlkFree, pMemAlo, pMemMax, pMemUB); +} + +#endif +/** + * Sends a message to an entity. + * @param src entity id of the sender + * @param dest entity id of the destination of the message. + * @param format message format. See ICall_sendServiceMsg(). + * @param msg pointer to the message body. + * @return @ref ICALL_ERRNO_SUCCESS when successful.
+ * @ref ICALL_ERRNO_INVALID_PARAMETER when either src + * or dest is not a valid entity id or when + * dest is an entity id of an entity that does + * not receive a message + * (e.g., ICall primitive service entity). + */ +ICall_Errno ICall_send(ICall_EntityID src, ICall_EntityID dest, ICall_MSGFormat format, void * msg) +{ + ICall_CSState key; + ICall_MsgHdr * hdr = (ICall_MsgHdr *) msg - 1; + + if (dest >= ICALL_MAX_NUM_ENTITIES || src >= ICALL_MAX_NUM_ENTITIES) + { + return (ICALL_ERRNO_INVALID_PARAMETER); + } + key = ICall_enterCSImpl(); + if (!ICall_entities[dest].task) + { + ICall_leaveCSImpl(key); + return (ICALL_ERRNO_INVALID_PARAMETER); + } + + ICall_leaveCSImpl(key); + /* Note that once the entry is valid, + * the value does not change and hence it is OK + * to leave the critical section. + */ + + hdr->srcentity = src; + hdr->dstentity = dest; + hdr->format = format; + + ICall_msgEnqueue(&ICall_entities[dest].task->queue, msg); + /* 0x80000000 is an internal event number */ + uint32_t msg_ptr = 0x80000000; +#ifdef FREERTOS + uint8_t status; + + if (HwiP_inISR()) + { + status = xQueueSendFromISR(ICall_entities[dest].task->syncHandle, (char *) &msg_ptr, NULL); + } + else + { + status = xQueueSend(ICall_entities[dest].task->syncHandle, (char *) &msg_ptr, 0); + } + + if (status != pdPASS) + { + return status; + } +#endif + return (ICALL_ERRNO_SUCCESS); +} + +/** + * Retrieves a message, queued to receive queue of the calling thread. + * + * @param src pointer to a variable to store the sender entity id + * of the received message. + * @param dest pointer to a variable to store the destination entity id + * of the received message. + * @param msg pointer to a pointer variable to store the starting + * address of a received message body. + * @return @ref ICALL_ERRNO_SUCCESS when a message was successfully + * retrieved.
+ * @ref ICALL_ERRNO_NOMSG when no message was queued to + * the receive queue at the moment.
+ * @ref ICALL_ERRNO_UNKNOWN_THREAD when the calling thread + * does not have a received queue associated with it. + * This happens when neither ICall_enrollService() nor + * ICall_registerApp() was ever called from the calling + * thread. + */ +ICall_Errno ICall_fetchMsg(ICall_EntityID * src, ICall_EntityID * dest, void ** msg) +{ + void * msgTemp; + TaskHandle_t taskhandle = Task_self(); + ICall_TaskEntry * taskentry = ICall_searchTask(taskhandle); + ICall_MsgHdr * hdr; + + if (!taskentry) + { + return (ICALL_ERRNO_UNKNOWN_THREAD); + } + /* Successful */ + msgTemp = ICall_msgDequeue(&taskentry->queue); + + if (msgTemp == NULL) + { + return (ICALL_ERRNO_NOMSG); + } + hdr = (ICall_MsgHdr *) msgTemp - 1; + *src = hdr->srcentity; + *dest = hdr->dstentity; + *msg = msgTemp; + return (ICALL_ERRNO_SUCCESS); +} + +/** + * Transforms and entityId into a serviceId. + * Note that this function is useful in case an application + * waits for messages from both a server and another application, + * in which case, the application can only use ICall_fetchMsg(), + * not ICall_fetchServiceMsg() because the latter will return + * @ref ICALL_ERRNO_CORRUPT_MSG when a message sent by the other + * application is about to be fetched.
+ * This function, then, is useful to retrieve service id + * matching the source entity id in case the source entity + * id is not that of the other application. + * + * @param entityId entity id + * @param servId pointer to a variable to store + * the resultant service id + * @return @ref ICALL_ERRNO_SUCCESS if the transformation was successful.
+ * @ref ICALL_ERRNO_INVALID_SERVICE if no matching service + * is found for the entity id. + */ +ICall_Errno ICall_entityId2ServiceId(ICall_EntityID entityId, ICall_ServiceEnum * servId) +{ + return ICall_primEntityId2ServiceId(entityId, servId); +} + +/** + * Aborts. + * + * This is preferred over C runtime abort() function, + * in an external image since the C runtime abort() is only + * guaranteed in a root image which contains the C runtime + * entry function that is executed upon startup. + */ +ICall_Errno ICall_abort(void) +{ +#ifdef HALNODEBUG +#elif defined(EXT_HAL_ASSERT) + HAL_ASSERT(HAL_ASSERT_CAUSE_ICALL_ABORT); +#else + { + volatile uint8_t j = 1; + while (j) + ; + } +#endif /* EXT_HAL_ASSERT */ + ICALL_HOOK_ABORT_FUNC(); + return (ICALL_ERRNO_SUCCESS); +} + +/** + * Enables interrupt. + * @param intnum interrupt number + * @return @ref ICALL_ERRNO_SUCCESS. + */ +ICall_Errno ICall_enableint(int intnum) +{ + Hwi_enableinterrupt(intnum); + return (ICALL_ERRNO_SUCCESS); +} + +/** + * Disables interrupt + * @param intnum interrupt number + * @return @ref ICALL_ERRNO_SUCCESS + */ +ICall_Errno ICall_disableint(int intnum) +{ + Hwi_disableinterrupt(intnum); + return (ICALL_ERRNO_SUCCESS); +} + +/** + * Gets the current tick counter value. + * @return current tick counter value + */ +uint_fast32_t ICall_getTicks(void) +{ + return (ClockP_getSystemTicks()); +} + +/** + * Gets the tick period. + * @return tick period in microseconds. + */ +uint_fast32_t ICall_getTickPeriod(void) +{ + return CLOCK_TICKS_PERIOD; +} + +/** + * Gets the maximum timeout period supported by + * ICall_setTimerMSecs() function. + * + * @return maximum timeout period in milliseconds + */ +uint_fast32_t ICall_getMaxMSecs(void) +{ + + uint_fast64_t tmp = ((uint_fast64_t) 0x7ffffffful) * (ICall_getTickPeriod()); + tmp /= 1000; + if (tmp >= 0x80000000ul) + { + tmp = 0x7ffffffful; + } + return ((uint_least32_t) tmp); +} + +/** + * Set up or restart a timer. + * Note that the timer setup initially by this function may be restarted + * using ICall_setTimer() function as well. + * + * @param msecs timeout period in milliseconds after which callback function + * shall be called. + * @param cback callback function pointer + * @param arg argument to pass to the callback function + * @param id pointer to the timer ID. + * If a new timer must be set up, the value of the timer ID + * must be set to @ref ICALL_INVALID_TIMER_ID when making this + * call and when the function returns successfully, the variable + * will be assigned a new timer ID value. + * The value other than @ref ICALL_INVALID_TIMER_ID shall be + * regarded as a request to restart the earlier set timer. + * @return @ref ICALL_ERRNO_SUCCESS when successful;
+ * @ref ICALL_ERRNO_INVALID_PARAMETER when msecs is greater than + * maximum value supported;
+ * @ref ICALL_ERRNO_NO_RESOURCE when ran out of resource. + * Check ICall heap size and OS heap size if this happens. + * + * @see ICall_getMaxMSecs() + */ +ICall_Errno ICall_setTimerMSecs(uint_fast32_t msecs, ICall_TimerCback cback, void * arg, ICall_TimerID * id) +{ + uint32_t ticks; + uint32_t timeout; + /* Convert to tick time */ + ICall_Errno errno = ICall_msecs2Ticks(msecs, &ticks); + + if (errno != ICALL_ERRNO_SUCCESS) + { + return (errno); + } + timeout = ticks; + ICall_setTimer(timeout, cback, arg, id); + + return (errno); +} + +/** + * Set up or restart a timer. + * Note that the timer setup initially by this function may be restarted + * using ICall_setTimerMSecs() function as well. + * + * @param ticks timeout period in ticks after which the callback function + * shall be called. + * @param cback callback function pointer + * @param arg argument to pass to the callback function + * @param id pointer to the timer ID. + * If a new timer must be set up, the value of the timer ID + * must be set to @ref ICALL_INVALID_TIMER_ID when making this + * call and when the function returns successfully, the variable + * will be assigned a new timer ID value. + * The value other than @ref ICALL_INVALID_TIMER_ID shall be + * regarded as a request to restart the earlier set timer. + * @return @ref ICALL_ERRNO_SUCCESS when successful;
+ * @ref ICALL_ERRNO_NO_RESOURCE when ran out of resource. + * Check ICall heap size and OS heap size if this happens. + * + * @see ICall_getTickPeriod() + */ + +ICall_Errno ICall_setTimer(uint32_t ticks, ICall_TimerCback cback, void * arg, ICall_TimerID * id) +{ + + ICall_ScheduleEntry * entry; + + if (*id == ICALL_INVALID_TIMER_ID) + { + ClockP_Params params; + + /* Create a new timer */ + entry = ICall_heapMalloc(sizeof(ICall_ScheduleEntry)); + if (entry == NULL) + { + /* allocation failed */ + return (ICALL_ERRNO_NO_RESOURCE); + } + ClockP_Params_init(¶ms); + params.startFlag = FALSE; + params.period = 0; + params.arg = (uintptr_t) entry; + + entry->clockP = ClockP_create(ICall_clockFunc, ticks, ¶ms); + if (!entry->clockP) + { + /* abort */ + ICall_abort(); + ICall_heapFree(entry); + return (ICALL_ERRNO_NO_RESOURCE); + } + entry->cback = cback; + entry->arg = arg; + *id = (ICall_TimerID) entry; + } + else + { + ICall_CSState key; + + entry = (ICall_ScheduleEntry *) *id; + + /* Critical section is entered to disable interrupts that might cause call + * to callback due to race condition */ + key = ICall_enterCriticalSection(); + ClockP_stop(entry->clockP); + entry->arg = arg; + ICall_leaveCriticalSection(key); + } + ClockP_setTimeout(entry->clockP, ticks); + + ClockP_start(entry->clockP); + + return (ICALL_ERRNO_SUCCESS); +} + +/** + * Stops a timer. + * + * @param id timer ID. + */ +void ICall_stopTimer(ICall_TimerID id) +{ + ICall_ScheduleEntry * entry = (ICall_ScheduleEntry *) id; + + if (id == ICALL_INVALID_TIMER_ID) + { + return; + } + + ClockP_stop(entry->clockP); +} + +/** + * Increments or decrements power activity counter. + * + * When power activity counter is greater than zero, + * the device shall stay in the active power state. + * The caller has to make sure that it decrements the counter + * as many times as it has incremented the counter + * when there is no activity that requires the active power state. + * It is recommended that each client increments the counter by just one, + * but it is not mandated to be so. + * + * @param incFlag TRUE to indicate incrementing the counter.
+ * FALSE to indicate decrementing the counter. + * @return @ref TRUE if power is required.
+ * @ref FALSE if power is not required.
+ */ +bool ICall_pwrUpdActivityCounter(bool incFlag) +{ + ICall_PwrUpdActivityCounterArgs args; + args.incFlag = incFlag; + ICallPlatform_pwrUpdActivityCounter(&args); + return (args.pwrRequired); +} + +/** + * Configures power constraint/dependency set/release actions upon + * activity counter change. + * + * When activity counter value drops to zero, all constraints and + * dependencies configured by this function shall be released.
+ * When activity counter value increments to one, all constraints + * and dependencies configured by this function shall be set. + * + * @param bitmap a bitmap of constraint or dependency flags.
+ * The flag definition is specific to each platform. + * For instance, see ICallCC26xxDefs.h. + * + * @return @ref ICALL_ERRNO_SUCCESS when successful
+ * @ref ICALL_ERRNO_INVALID_PARAMETER when an invalid + * flag in the bitmap is detected.
+ */ +ICall_Errno ICall_pwrConfigACAction(ICall_PwrBitmap_t bitmap) +{ + ICall_PwrBitmapArgs args; + args.bitmap = bitmap; + return (ICallPlatform_pwrConfigACAction(&args)); +} + +/** + * Sets power constraints and dependencies. + * + * @param bitmap a bitmap of constraint or dependency flags.
+ * The flag definition is specific to each platform. + * For instance, see ICallCC26xxDefs.h. + * + * @return @ref ICALL_ERRNO_SUCCESS when successful
+ * @ref ICALL_ERRNO_INVALID_PARAMETER when an invalid + * flag in the bitmap is detected.
+ */ +ICall_Errno ICall_pwrRequire(ICall_PwrBitmap_t bitmap) +{ + ICall_PwrBitmapArgs args; + args.bitmap = bitmap; + return (ICallPlatform_pwrRequire(&args)); +} + +/** + * Releases power constraints and dependencies. + * + * @param bitmap a bitmap of constraint or dependency flags.
+ * The flag definition is specific to each platform. + * For instance, see ICallCC26xxDefs.h. + * + * @return @ref ICALL_ERRNO_SUCCESS when successful
+ * @ref ICALL_ERRNO_INVALID_PARAMETER when an invalid + * flag in the bitmap is detected.
+ */ +ICall_Errno ICall_pwrDispense(ICall_PwrBitmap_t bitmap) +{ + ICall_PwrBitmapArgs args; + args.bitmap = bitmap; + return (ICallPlatform_pwrDispense(&args)); +} + +/** + * Checks whether HF XOSC is stable. + * This function must be called after HF XOSC is turned on + * (through power dependency). + * + * @return TRUE when HF XOSC is stable.
+ * FALSE when HF XOSC is not stable.
+ */ +bool ICall_pwrIsStableXOSCHF(void) +{ + ICall_GetBoolArgs args; + (void) ICallPlatform_pwrIsStableXOSCHF(&args); + return (args.value); +} + +/** + * Switch clock source to HF XOSC. + * This function must be called after HF XOSC is stable. + * + * @return @ref ICALL_ERRNO_SUCCESS + */ +ICall_Errno ICall_pwrSwitchXOSCHF(void) +{ + ICall_FuncArgsHdr args; + return (ICallPlatform_pwrSwitchXOSCHF(&args)); +} + +/** + * Gets the estimated crystal oscillator startup time. + * + * @return estimated crystal oscillator startup time + */ +uint32_t ICall_pwrGetXOSCStartupTime(uint_fast32_t timeUntilWakeupInMs) +{ + ICall_PwrGetXOSCStartupTimeArgs args; + args.timeUntilWakeupInMs = timeUntilWakeupInMs; + (void) ICallPlatform_pwrGetXOSCStartupTime(&args); + return (args.value); +} + +/** + * Registers a power state transition notify function. + * + * The registered notify function shall be called when the power state + * changes. + * + * @param fn notify function pointer + * @param obj pointer to data object to be passed to notify function.
+ * This pointer must not be NULL and can point to an aggregate type + * containing the @ref ICall_PwrNotifyData. + * The object must not be released. + * @return @ref ICALL_ERRNO_SUCCESS when successful
+ * @ref ICALL_ERRNO_NO_RESOURCE when registration failed
+ */ +ICall_Errno ICall_pwrRegisterNotify(ICall_PwrNotifyFn fn, ICall_PwrNotifyData * obj) +{ + ICall_PwrRegisterNotifyArgs args; + args.hdr.service = ICALL_SERVICE_CLASS_PRIMITIVE; + args.hdr.func = ICALL_PRIMITIVE_FUNC_PWR_REGISTER_NOTIFY; + args.fn = fn; + args.obj = obj; + return (ICallPlatform_pwrRegisterNotify(&args)); +} + +/** + * Retrieves power transition state. + * + * @return Implementation specific transition state when successful
+ * Zero when the function is not implemented.
+ */ +uint_fast8_t ICall_pwrGetTransitionState(void) +{ + ICall_PwrGetTransitionStateArgs args; + ICall_Errno errno; + + errno = ICallPlatform_pwrGetTransitionState(&args); + + if (errno == ICALL_ERRNO_SUCCESS) + { + return (args.state); + } + return (0); +} + +/** + * Creates a new RTOS task. + * + * @param entryfn task entry function. + * @param priority task priority as understood by the underlying RTOS + * @param stacksize stack size as understood by the underlying RTOS + * @param arg argument to pass to the task entry function + * + * @return @ref ICALL_ERRNO_SUCCESS when successful
+ * @ref ICALL_ERRNO_NO_RESOURCE when creation failed
+ */ + +#ifdef ICALL_RTOS_SEMAPHORE_API +/** + * Creates a semaphore. + * + * @param mode Semaphore mode
+ * @ref ICALL_SEMAPHORE_MODE_COUNTING, or
+ * @ref ICALL_SEMAPHORE_MODE_BINARY + * @param initcount initial count value + * @return created semaphore when successful
+ * NULL when creation failed
+ */ +ICall_Semaphore ICall_createSemaphore(uint_fast8_t mode, int initcount) +{ + /* Semaphore_Params is a huge structure. + * To reduce stack usage, heap is used instead. + * This implies that ICall_createSemaphore() must be called before heap + * space may be exhausted. + */ + ICall_Semaphore sem; + Semaphore_Params * semParams = (Semaphore_Params *) ICall_heapMalloc(sizeof(Semaphore_Params)); + + if (semParams == NULL) + { + return (NULL); + } + + Semaphore_Params_init(semParams); + if (mode == ICALL_SEMAPHORE_MODE_BINARY) + { + semParams->mode = Semaphore_Mode_BINARY; + } + + sem = Semaphore_create(args->initcount, semParams, NULL); + ICall_heapFree(semParams); + + return (sem); +} +#endif + +#ifdef ICALL_RTOS_SEMAPHORE_API +/** + * Post on a semaphore + * + * @param sem semaphore. + * + * @return @ref ICALL_ERRNO_SUCCESS when the operation was successful + */ +ICall_Errno ICall_postSemaphore(ICall_Semaphore sem) +{ + Semaphore_post(sem); + return (ICALL_ERRNO_SUCCESS); +} +#endif /* ICALL_RTOS_SEMAPHORE_API */ + +#ifdef ICALL_RTOS_EVENTS_API +/** + * Creates a event. + * + * @return created event when successful
+ * NULL when creation failed
+ */ +ICall_Event ICall_createEvent(void) +{ + ICall_Event event = Event_create(NULL, NULL); + return (event); + + ICall_CreateEventArgs args; + ICall_Errno errno; + + args.hdr.service = ICALL_SERVICE_CLASS_PRIMITIVE; + args.hdr.func = ICALL_PRIMITIVE_FUNC_CREATE_EVENT; + errno = ICall_dispatcher(&args.hdr); + if (errno == ICALL_ERRNO_SUCCESS) + { + return (args.event); + } + return (NULL); +} + +/** + * Post on an event + * + * @param event event. + * + * @return @ref ICALL_ERRNO_SUCCESS when the operation was successful + */ +ICall_Errno ICall_postEvent(ICall_Event event, uint32_t events) +{ + Event_post(event, events); + return (ICALL_ERRNO_SUCCESS); +} +/** + * Waits on a event for ICALL_MSG_EVENT_ID + * + * @param event event. + * @param milliseconds timeout in milliseconds + * or @ref ICALL_TIMEOUT_FOREVER to wait forever + * + * @return @ref ICALL_ERRNO_SUCCESS when the operation was successful + * and event was received.
+ * @ref ICALL_ERRNO_TIMEOUT when designated timeout period + * has passed since the call of the function without + * the event being signaled. + */ +ICall_Errno ICall_waitEvent(ICall_Event event, uint_fast32_t milliseconds) +{ + uint32_t timeout; + + if (milliseconds == 0) + { + timeout = BIOS_NO_WAIT; + } + else if (milliseconds == ICALL_TIMEOUT_FOREVER) + { + timeout = BIOS_WAIT_FOREVER; + } + else + { + ICall_Errno errno = ICall_msecs2Ticks(milliseconds, &timeout); + if (errno != ICALL_ERRNO_SUCCESS) + { + return (errno); + } + } + + if (Event_pend(event, 0, ICALL_MSG_EVENT_ID, timeout)) + { + return (ICALL_ERRNO_SUCCESS); + } + return (ICALL_ERRNO_TIMEOUT); +} +#endif /* ICALL_RTOS_EVENTS_API */ + +#ifdef ICALL_RTOS_SEMAPHORE_API +/** + * Waits on a semaphore + * + * @param sem semaphore. + * @param milliseconds timeout in milliseconds + * or @ref ICALL_TIMEOUT_FOREVER to wait forever + * + * @return @ref ICALL_ERRNO_SUCCESS when the operation was successful + * and semaphore was acquired.
+ * @ref ICALL_ERRNO_TIMEOUT when designated timeout period + * has passed since the call of the function without + * the semaphore being signaled. + */ +ICall_Errno ICall_waitSemaphore(ICall_Semaphore sem, uint_fast32_t milliseconds) +{ + uint32_t timeout; + + if (milliseconds == 0) + { + timeout = BIOS_NO_WAIT; + } + else if (milliseconds == ICALL_TIMEOUT_FOREVER) + { + timeout = BIOS_WAIT_FOREVER; + } + else + { + ICall_Errno errno = ICall_msecs2Ticks(milliseconds, &timeout); + if (errno != ICALL_ERRNO_SUCCESS) + { + return (errno); + } + } + if (Semaphore_pend(sem, timeout)) + { + return (ICALL_ERRNO_SUCCESS); + } + return (ICALL_ERRNO_TIMEOUT); +} +#endif /* ICALL_RTOS_SEMAPHORE_API */ + +#if 0 +/* Util function that take time in ticks and convert it into ms - relate to system clock (returns system clock + converted ms) */ +static void AbsoluteTimeInMilliPlusTimer(uint_least32_t timeout,struct timespec *tsTimer) +{ + + clock_gettime(CLOCK_REALTIME, tsTimer); + + tsTimer->tv_sec += (timeout / 1000); + tsTimer->tv_nsec += (timeout % 1000) * 1000000; +} +#endif + +/** + * Waits for and retrieves a message received at the message queue + * associated with the calling thread, which matches a certain condition. + * + * @param milliseconds timeout period in milliseconds. + * @param matchFn pointer to a function that would return TRUE when + * the message matches its condition. + * @param src pointer to a variable to store the service id + * of the registered server which sent the retrieved + * message, or NULL if not interested in storing service id. + * @param dest pointer to a variable to store the entity id + * of the destination of the message, + * of NULL if not interested in storing the destination entity id. + * @param msg pointer to a pointer variable to store the + * starting address of the message body being + * retrieved. The pointer must not be NULL. + * @return @ref ICALL_ERRNO_SUCCESS when the operation was successful + * and a message was retrieved.
+ * @ref ICALL_ERRNO_TIMEOUT when designated timeout period + * has passed since the call of the function without + * the semaphore being signaled. + * @ref ICALL_ERRNO_UNKNOWN_THREAD when this function is + * called from a thread which has not registered + * an entity, either through ICall_enrollService() + * or through ICall_registerApp(). + */ +ICall_Errno ICall_waitMatch(uint_least32_t milliseconds, ICall_MsgMatchFn matchFn, ICall_ServiceEnum * src, ICall_EntityID * dest, + void ** msg) +{ + TaskHandle_t taskhandle = Task_self(); + ICall_TaskEntry * taskentry = ICall_searchTask(taskhandle); + ICall_MsgQueue prependQueue = NULL; +#ifndef ICALL_EVENTS + uint_fast16_t consumedCount = 0; +#endif + uint32_t timeout; + uint_fast32_t timeoutStamp; + ICall_Errno errno; + + if (!taskentry) + { + return (ICALL_ERRNO_UNKNOWN_THREAD); + } + /* Successful */ + if (milliseconds == 0) + { + timeout = BIOS_NO_WAIT; + } + else if (milliseconds == ICALL_TIMEOUT_FOREVER) + { + timeout = BIOS_WAIT_FOREVER; + } + else + { + /* Convert milliseconds to number of ticks */ + errno = ICall_msecs2Ticks(milliseconds, &timeout); + if (errno != ICALL_ERRNO_SUCCESS) + { + return (errno); + } + } + + errno = ICALL_ERRNO_TIMEOUT; + + timeoutStamp = ICall_getTicks() + timeout; + +#ifdef ICALL_LITE + + uint32_t events; + +#ifdef FREERTOS + // TODO: Investigate ICALL Wait tick period (Last parameter) + while (xQueueReceive(taskentry->syncHandle, (char *) &events, milliseconds * 1000) == pdPASS) +#endif +#else /* !ICALL_LITE */ + while (ICALL_SYNC_HANDLE_PEND(taskentry->syncHandle, timeout)) +#endif /* ICALL_LITE */ + { + ICall_EntityID fetchSrc; + ICall_EntityID fetchDst; + ICall_ServiceEnum servId; + void * fetchMsg; + errno = ICall_fetchMsg(&fetchSrc, &fetchDst, &fetchMsg); + if (errno == ICALL_ERRNO_SUCCESS) + { + if (ICall_primEntityId2ServiceId(fetchSrc, &servId) == ICALL_ERRNO_SUCCESS) + { + if (matchFn(servId, fetchDst, fetchMsg)) + { + /* Matching message found*/ + if (src != NULL) + { + *src = servId; + } + if (dest != NULL) + { + *dest = fetchDst; + } + *msg = fetchMsg; + errno = ICALL_ERRNO_SUCCESS; + break; + } + } + /* Message was received but it wasn't expected one. + * Add to the prepend queue */ + ICall_msgEnqueue(&prependQueue, fetchMsg); +#ifdef ICALL_EVENTS + /* Event are binary semaphore, so if several messsages are posted while + * we are processing one, it's possible that some of them are 'missed' and + * not processed. Sending a event to ourself force this loop to run until + * all the messages in the queue are processed. + */ +#ifdef ICALL_LITE + /* 0x20000000 is an internal Event_ID */ + uint32_t msg_ptr = (0x20000000); // Event_Id_29; + +#ifdef FREERTOS + + uint8_t status; + if (HwiP_inISR()) + { + status = xQueueSendFromISR(taskentry->syncHandle, (char *) &msg_ptr, NULL); + } + else + { + status = xQueueSend(taskentry->syncHandle, (char *) &msg_ptr, 0); + } + + if (status != pdTRUE) + { + return status; + } +#endif + +#else /* !ICALL_LITE */ + ICALL_SYNC_HANDLE_POST(taskentry->syncHandle); +#endif /* ICALL_LITE*/ +#endif /* ICALL_EVENTS */ + } + + /* Prepare for timeout exit */ + errno = ICALL_ERRNO_TIMEOUT; + +#ifndef ICALL_EVENTS + /* Keep the decremented semaphore count */ + consumedCount++; +#endif /* ICALL_EVENTS */ + if (timeout != BIOS_WAIT_FOREVER && timeout != BIOS_NO_WAIT) + { + /* Readjust timeout */ + uint32_t newTimeout = timeoutStamp - ICall_getTicks(); + + if (newTimeout == 0 || newTimeout > timeout) + { + break; + } + timeout = newTimeout; + } + } + + /* Prepend retrieved irrelevant messages */ + ICall_msgPrepend(&taskentry->queue, prependQueue); +#ifndef ICALL_EVENTS + /* Re-increment the consumed semaphores */ + for (; consumedCount > 0; consumedCount--) + { + Semaphore_post(taskentry->syncHandle); + } +#endif /* ICALL_EVENTS */ + return (errno); +} + +/** + * Retrieves an entity ID of (arbitrary) one of the entities registered + * from the calling thread. + * + * Note that, if multiple entities were registered from the same thread, + * this function shall arbitrarily pick one of the entities. + * + * @return A valid entity ID or @ref ICALL_INVALID_ENTITY_ID + * when no entity was registered from the calling thread. + */ +ICall_EntityID ICall_getEntityId(void) +{ + ICall_EntityID id; + TaskHandle_t taskhandle = Task_self(); + ICall_CSState key; + size_t i; + key = ICall_enterCSImpl(); + for (i = 0; i < ICALL_MAX_NUM_ENTITIES; i++) + { + if (ICall_entities[i].service == ICALL_SERVICE_CLASS_INVALID_ENTRY) + { + /* Not found */ + break; + } + if (ICall_entities[i].task->task == (TaskHandle_t) taskhandle) + { + /* Found */ + id = i; + ICall_leaveCSImpl(key); + return (id); + } + } + ICall_leaveCSImpl(key); + return ICALL_INVALID_ENTITY_ID; +} + +/** + * Checks whether the calling thread provides the designated service. + * + * @param service Service enumeration value for the service. + * + * @return Non-zero if the current thread provides the designated service. + * Zero, otherwise. + */ +uint_fast8_t ICall_threadServes(ICall_ServiceEnum service) +{ + uint_fast8_t res = 0; + TaskHandle_t taskhandle; + ICall_CSState key; + size_t i; + taskhandle = Task_self(); + + key = ICall_enterCSImpl(); + for (i = 0; i < ICALL_MAX_NUM_ENTITIES; i++) + { + if (ICall_entities[i].service == ICALL_SERVICE_CLASS_INVALID_ENTRY) + { + /* Not found */ + break; + } + else if (ICall_entities[i].service == service) + { + res = (uint_fast8_t) (ICall_entities[i].task->task == taskhandle); + } + } + ICall_leaveCSImpl(key); + return (res); +} + +/** + * Retrieves an internal ID understood only by a service entity, + * corresponding to an ICall entity ID. + * + * This function is used when a message body includes a field indicating a + * software entity and the destination of the message has its own internal + * message routing mechanism with its own entity enumeration system. + * + * @param service Service enumeration value for the service. + * Currently @ref ICALL_SERVICE_CLASS_BLE_MSG is supported. + * @param entity ICall entity ID. + * + * @return Stack specific 8 bit ID or 0xFF when failed. + */ +uint_fast8_t ICall_getLocalMsgEntityId(ICall_ServiceEnum service, ICall_EntityID entity) +{ + ICall_GetLocalMsgEntityIdArgs args; + ICall_Errno errno; + args.hdr.service = service; + args.hdr.func = ICALL_MSG_FUNC_GET_LOCAL_MSG_ENTITY_ID; + args.entity = entity; + errno = ICall_dispatcher(&args.hdr); + if (errno == ICALL_ERRNO_SUCCESS) + { + return (args.localId); + } + return (0xFF); +} + +#endif /* ICALL_JT */ + +#ifdef ICALL_LITE +/******************************************************************************* + * @fn matchLiteCS + */ +static bool matchLiteCS(ICall_ServiceEnum src, ICall_EntityID dest, const void * msg) +{ + (void) src; + (void) dest; + ICall_LiteCmdStatus * pMsg = (ICall_LiteCmdStatus *) msg; + return (pMsg->cmdId == ICALL_LITE_DIRECT_API_DONE_CMD_ID); +} +/******************************************************************************* + * @fn icall_directAPI + * see headers for details. + */ +uint32_t icall_directAPI(uint8_t service, icall_lite_id_t id, ...) +{ + va_list argp; + uint32_t res; + icallLiteMsg_t liteMsg; + + // The following will push all parameter in the runtime stack. + // This need to be call before any other local declaration of variable.... + va_start(argp, id); + + // Todo - add string for every icall API function, instead of printing function address + BLE_LOG_INT_INT(0, BLE_LOG_MODULE_APP, "APP : icall_directAPI to BLE func=0x%x, status=%d\n", id, 0); + // Create the message that will be send to the requested service.. + liteMsg.hdr.len = sizeof(icallLiteMsg_t); + liteMsg.hdr.next = NULL; + liteMsg.hdr.dest_id = ICALL_UNDEF_DEST_ID; + liteMsg.msg.directAPI = id; + liteMsg.msg.pointerStack = (uint32_t *) (*((uint32_t *) (&argp))); + ICall_sendServiceMsg(ICall_getEntityId(), service, ICALL_MSG_FORMAT_DIRECT_API_ID, &(liteMsg.msg)); + + // Since stack needs to always have a higher priority than the thread calling + // the API, when we reach this point the API has been executed by the stack. + // This implies the following: + // - API are not called in critical section or in section where task + // switching is disabled + // It is possible that the stack is blocking on this API, in this case a + // sync object needs to be used in order for this call to resume only when + // the API has been process in full. + { + ICall_Errno errno; + void * pCmdStatus = NULL; + + errno = ICall_waitMatch(ICALL_TIMEOUT_PREDEFINE, matchLiteCS, NULL, NULL, (void **) &pCmdStatus); + if (errno == ICALL_ERRNO_TIMEOUT) + { +#ifdef HALNODEBUG +#elif defined(EXT_HAL_ASSERT) + HAL_ASSERT(HAL_ASSERT_CAUSE_ICALL_TIMEOUT); +#else /* !EXT_HAL_ASSERT */ + ICall_abort(); +#endif /* EXT_HAL_ASSERT */ + } + else if (errno == ICALL_ERRNO_SUCCESS) + { + if (pCmdStatus) + { + ICall_freeMsg(pCmdStatus); + } + } + else + { +#ifdef HALNODEBUG +#else /* ! HALNODEBUG */ + ICall_abort(); +#endif /* HALNODEBUG */ + } + } + + // The return parameter is set in the runtime stack, at the location of the + // first parameter. + res = liteMsg.msg.pointerStack[0]; + + va_end(argp); + + return (res); +} + +/******************************************************************************* + * @fn ICall_sendServiceComplete + * see headers for details. + */ +ICall_Errno ICall_sendServiceComplete(ICall_EntityID src, ICall_EntityID dest, ICall_MSGFormat format, void * msg) +{ + ICall_CSState key; + ICall_MsgHdr * hdr = (ICall_MsgHdr *) msg - 1; + + if (dest >= ICALL_MAX_NUM_ENTITIES || src >= ICALL_MAX_NUM_ENTITIES) + { + return (ICALL_ERRNO_INVALID_PARAMETER); + } + key = ICall_enterCSImpl(); + if (!ICall_entities[dest].task) + { + ICall_leaveCSImpl(key); + return (ICALL_ERRNO_INVALID_PARAMETER); + } + + ICall_leaveCSImpl(key); + /* Note that once the entry is valid, + * the value does not change and hence it is OK + * to leave the critical section. + */ + + hdr->srcentity = src; + hdr->dstentity = dest; + hdr->format = format; + ICall_msgEnqueue(&ICall_entities[dest].task->queue, msg); + + /* 0x20000000 is an internal Event_ID */ + uint32_t msg_ptr = (0x20000000); // Event_Id_29; +#ifdef FREERTOS + uint8_t status; + if (HwiP_inISR()) + { + status = xQueueSendFromISR(ICall_entities[dest].task->syncHandle, (char *) &msg_ptr, NULL); + } + else + { + status = xQueueSend(ICall_entities[dest].task->syncHandle, (char *) &msg_ptr, 0); + } + + if (status != pdTRUE) + { + return status; + } +#endif + return (ICALL_ERRNO_SUCCESS); +} +#endif /* ICALL_LITE*/