Template:ICall

Indirect Call Framework (ICall) is an module that provides a mechanism for the Application to interface with the protocol stack services (i.e, -Stack APIs) as well as certain primitive services provided by the RTOS (e.g., thread synchronization). Combined, ICall allows both the Application and protocol stack to efficiently operate, communicate and share resources in a unified RTOS environment. The central component of the ICall architecture is the dispatcher which facilitates the application program interface between the Application and the protocol stack task across the dual-image boundary. Although most of the ICall interactions are abstracted within the protocol stack APIs, it is important for the application developer to understand the underlying architecture such that proper  protocol operation is achieved in the multi-threaded RTOS environment. The ICall module source code is provided in the “ICall” &amp; “ICall” IDE folders within the Application project.



ICall Protocol Stack Service
As depicted above, the ICall core use case involves messaging between an ICall server entity (i.e. the Stack task) and a client entity (e.g. the Application task). The reasoning for this architecture is twofold: to enable independent updating of the application / protocol stack and to maintain API consistency as the software is ported from legacy platforms (e.g. OSAL for the CC254x) to the CC2640’s TI-RTOS. The ICall Protocol Stack Service serves as the Application interface to all -Stack APIs. Internally, when a protocol stack API is called by the Application, the ICall module routes (i.e. dispatches) the command to the  protocol stack, and where appropriate, routes messages from the  protocol stack to the Application. Since the ICall module is part of the Application project, the Application task can access ICall with direct function calls. Note that since the protocol stack executes at the highest priority, the Application task will block until the response is received. Certain protocol stack APIs may respond immediately, however the Application thread will block as the API is being dispatched to the protocol stack via ICall. Other protocol stack APIs may also respond asynchronously to the application via ICall (e.g. event updates) with the response sent to the application task’s event handler.

ICall Primitive Service
In addition, ICall includes a primitive service that abstracts various operating system related functions. Due to shared resources and to maintain interprocess communication, the Application should use the following ICall primitive service functions:
 * Messaging and Thread Synchronization
 * Heap Allocation / Management

Messaging and Thread Synchronization
The Messaging and Thread Synchronization functions provided by ICall enable designing an application to protocol stack interface in the multi-threaded RTOS environment. Within ICall, messaging between two tasks is achieved by sending a block of messages from one thread to the other via a message queue. The sender allocates a memory, writes the content of the message into the memory block and then sends (i.e, enqueues) the memory block to the recipient. Notification of message delivery is accomplished using a signalling object such as semaphore or event object. The receiver wakes up on the posted signal, copies the message memory block(s), processes the message and returns (frees) the memory block to the heap.

The signalling mechanism used by ICall is determined via C pre-processor option.

The Stack uses ICall for notifying and sending messages to the Application. These “service messages” (e.g. state change notifications, etc.) are received by the Application task are delivered by ICall and processed in the Application’s task context.

Heap Allocation and Management
ICall provides the Application with a global heap APIs for dynamic memory allocation. The size of the ICall heap is configured with the HEAPMGR_SIZE preprocessor define in the Application project. ICall uses this heap for all protocol stack messaging as well as to obtain memory for other ICall services. It is also recommended that the Application utilize these ICall APIs for dynamic memory allocation within the Application.

ICall Initialization and Registration
To instantiate and initialize the ICall service, the following functions must be called by the application in  before starting the SYS/BIOS kernel scheduler:

 /* Initialize ICall module */ ICall_init; /* Start tasks of external images - Priority 5 */ ICall_createRemoteTasks; 

Calling  initializes the ICall primitive service (e.g., heap manager) and framework. Calling  creates, but does not start, the  protocol stack task.

Prior to using ICall protocol services, both the server and client must enroll and register with ICall. The server enrolls a service which is enumerated at build time. Service function handler registration uses a globally defined unique identifier for each service. For example, uses ICALL_SERVICE_CLASS_ for receiving protocol stack messages via ICall.

The following is a call to enroll the protocol stack service (server) with ICall:

 /* Enroll the service that this stack represents */ ICall_enrollService(ICALL_SERVICE_CLASS_, NULL, &entity, &signal); 

The registration mechanism is used by the client to send and/or receive messages via the ICall dispatcher.

In order for a client (e.g., Application task) to utilize the -Stack APIs, it must first register its task with ICall. This registration is usually done in the application’s task initialization function.

 /*    * Register the current thread as an ICall dispatcher application * so that the application can send and receive messages. */   ICall_registerApp(&selfEntity, &signal); 

The Application supplies the  and   inputs which, upon return of , are initialized for the client’s (e.g., Application) task. These objects are subsequently used be ICall to facilitate messaging between the Application and server tasks.

The  argument represents the semaphore or event used for signalling, whereas the   represents the task’s destination message queue. Each task registering with ICall will have unique  and   identifiers.

ICall Thread synchronization
The ICall module switches between Application and Stack threads through Preemption and Semaphore/Event Synchronization services provided by the RTOS.

The two ICall functions to retrieve and enqueue messages, as mentioned previously, are not blocking functions. That is, they will check whether there is a received message in the queue and if there is no message, the functions will return immediately with ICALL_ERRNO_NOMSG return value. To allow a client or a server thread to block till it receives a message, ICall provides the following function which will block untill the semaphore or event associated with the caller RTOS thread is posted:

 /* static inline ICall_Errno ICall_wait(uint_fast32_t milliseconds) */ ICall_Errno errno = ICall_wait(ICALL_TIMEOUT_FOREVER); 

“milliseconds” is timeout period in milliseconds, after which if the function is not already returned, the function will return with. If  is passed as “milliseconds”, the   shall block forever till the signal is posted. Allowing an application or a server thread to block is important in order to yield the processor resource to other lower priority threads or to conserve energy by shutting down power and/or clock domains whenever possible. The signal associated with an RTOS thread is determined by either of the following conditions:
 * A new message is queued to the Application’s RTOS thread queue.
 * is called for the semaphore/event

is provided so that an application or a server can add its own event to unblock the  and synchronize the thread. accepts signal handle as its sole argument as follows:

 /* static ICall_Errno ICall_signal(ICall_SyncHandle msgSyncHdl) */ ICall_signal(signal); 

The signal handle associated with the thread is obtained through either  call or   call.

Note that it is not possible to call an ICall function from a stack callback. This will cause ICall to abort (with ) and break the system.