diff --git a/src/platform/cc13xx_26xx/BLEManagerImpl.cpp b/src/platform/cc13xx_26xx/BLEManagerImpl.cpp
index fc0a6af0beea94..f1d179c4b39310 100644
--- a/src/platform/cc13xx_26xx/BLEManagerImpl.cpp
+++ b/src/platform/cc13xx_26xx/BLEManagerImpl.cpp
@@ -521,7 +521,7 @@ void BLEManagerImpl::EventHandler_init(void)
/* set the stacks in default states */
DMMPolicy_updateStackState(DMMPolicy_StackRole_BlePeripheral, DMMPOLICY_BLE_IDLE);
- vTaskPrioritySet(xTaskGetCurrentTaskHandle(), 3);
+ vTaskPrioritySet(xTaskGetCurrentTaskHandle(), BLE_MANAGER_TASK_PRIORITY);
// ******************************************************************
// N0 STACK API CALLS CAN OCCUR BEFORE THIS CALL TO ICall_registerApp
@@ -634,7 +634,7 @@ CHIP_ERROR BLEManagerImpl::CreateEventHandler(void)
"ble_hndlr", /* Text name for the task. */
BLEMANAGER_EVENT_HANDLER_STACK_SIZE, /* Stack size in words, not bytes. */
this, /* Parameter passed into the task. */
- ICALL_TASK_PRIORITIES, /* Keep priority the same as ICALL until init is complete */
+ BLE_STACK_TASK_PRIORITY, /* Keep priority the same as ICALL until init is complete */
NULL); /* Used to pass out the created task's handle. */
if (xReturned == errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY)
diff --git a/src/platform/cc13xx_26xx/icall_FreeRTOS.c b/src/platform/cc13xx_26xx/icall_FreeRTOS.c
new file mode 100644
index 00000000000000..469ef9b3e0074c
--- /dev/null
+++ b/src/platform/cc13xx_26xx/icall_FreeRTOS.c
@@ -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*/
diff --git a/third_party/ti_simplelink_sdk/ti_simplelink_sdk.gni b/third_party/ti_simplelink_sdk/ti_simplelink_sdk.gni
index b3aae392cfb39d..2bae18ab2a5db7 100644
--- a/third_party/ti_simplelink_sdk/ti_simplelink_sdk.gni
+++ b/third_party/ti_simplelink_sdk/ti_simplelink_sdk.gni
@@ -360,6 +360,8 @@ template("ti_simplelink_sdk") {
libs = []
defines = [
+ "BLE_MANAGER_TASK_PRIORITY=5",
+ "BLE_STACK_TASK_PRIORITY=6",
"INCLUDE_BGET_STATS",
"USE_DMM",
"NVOCMP_FREERTOS_MUTEX=1",
@@ -523,10 +525,10 @@ template("ti_simplelink_sdk") {
sources = [
"${chip_root}/src/platform/cc13xx_26xx/TI_heap_wrapper.c",
"${chip_root}/src/platform/cc13xx_26xx/chipOBleProfile.c",
+ "${chip_root}/src/platform/cc13xx_26xx/icall_FreeRTOS.c",
"${ti_simplelink_sdk_root}/source/ti/ble5stack/common/cc26xx/freertos/bget.c",
"${ti_simplelink_sdk_root}/source/ti/ble5stack/common/cc26xx/rcosc/rcosc_calibration.c",
"${ti_simplelink_sdk_root}/source/ti/dmm/apps/common/ble_remote_display/stack/osal_icall_ble.c",
- "${ti_simplelink_sdk_root}/source/ti/dmm/apps/common/freertos/icall_FreeRTOS.c",
"${ti_simplelink_sdk_root}/source/ti/dmm/apps/common/freertos/util.c",
"${ti_simplelink_sdk_root}/source/ti/dmm/apps/common/thread/source/activity/dmm_thread_activity.c",
"${ti_simplelink_sdk_root}/source/ti/dmm/dmm_priority_ble_thread.c",