NOTICE: The Processors Wiki will End-of-Life on January 15, 2021. It is recommended to download any files or other content you may need that are hosted on processors.wiki.ti.com. The site is now set to read only.

Template:ICall

From Texas Instruments Wiki
Jump to: navigation, search

Indirect Call Framework (ICall) is an module that provides a mechanism for the Application to interface with the BLE protocol stack services (i.e, BLE-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 BLE protocol stack task across the dual-image boundary. Although most of the ICall interactions are abstracted within the BLE protocol stack APIs, it is important for the application developer to understand the underlying architecture such that proper BLE protocol operation is achieved in the multi-threaded RTOS environment. The ICall module source code is provided in the “ICall” & “ICallBLE” IDE folders within the Application project.

ICall protocol stack abstraction.png

ICall BLE Protocol Stack Service[edit]

As depicted above, the ICall core use case involves messaging between an ICall server entity (i.e. the BLE 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 / BLE 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 BLE Protocol Stack Service serves as the Application interface to all BLE-Stack APIs. Internally, when a BLE protocol stack API is called by the Application, the ICall module routes (i.e. dispatches) the command to the BLE protocol stack, and where appropriate, routes messages from the BLE 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 BLE 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 BLE protocol stack via ICall. Other BLE 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[edit]

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[edit]

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 ICALL_EVENT.

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[edit]

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[edit]

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

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

Calling ICall_init() initializes the ICall primitive service (e.g., heap manager) and framework. Calling ICall_createRemoteTasks() creates, but does not start, the BLE 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, BLE uses ICALL_SERVICE_CLASS_BLE for receiving BLE protocol stack messages via ICall.

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

   /* Enroll the service that this stack represents */
   ICall_enrollService(ICALL_SERVICE_CLASS_BLE, 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 BLE-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 selfEntity and signal inputs which, upon return of ICall_registerApp(), 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 signal argument represents the semaphore or event used for signalling, whereas the selfEntity represents the task’s destination message queue. Each task registering with ICall will have unique signal and selfEntity identifiers.

ICall Thread synchronization[edit]

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 ICALL_ERRNO_TIMEOUT. If ICALL_TIMEOUT_FOREVER is passed as “milliseconds”, the ICall_wait() 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.
  • ICall_signal() is called for the semaphore/event

ICall_signal() is provided so that an application or a server can add its own event to unblock the ICall_wait() and synchronize the thread. ICall_signal() 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 ICall_enrollService() call or ICall_registerApp() call.

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