This section describes the software architecture used by the Cordio Host.
The software system uses function calls and callback functions in its APIs, as described below.
Message Passing API Functions
Message passing API functions result in a message being sent to the task running the stack. These functions typically involve a complex operation, such as creating a connection, and do not access internal (private) data.
Direct Execute API Functions
Direct execute API functions run entirely in the context of the calling function. These functions typically involve simple operations like reading or setting internal data. Task scheduling is locked when accessing internal data.
Callback functions are implemented by the client using the protocol stack and execute in the context of the stack.
Callback functions are used to send events and data to the client.
Figure 3-1. Message passing and direct execute interfaces.
Event Handlers and Tasks
The Arm software system defines an event handler service that forms a basis for the asynchronous communication mechanisms used in the system. An event handler can receive messages and events. Each software subsystem typically has its own event handler; for example, each layer of the protocol stack has its own event handler.
The stack is designed to be flexible and allow for different task architectures. The software system does not define any tasks but defines some interfaces to tasks. It relies on the target OS to implement tasks and manage the timer and event handler services from target OS tasks. A typical single-chip software system will use separate tasks for the application, stack, and link layer. However there is nothing in the design of the protocol stack or profiles that prevent them from being run in the same task as other software systems.
Figure 3-2. Example system showing event handlers executing within an OS task
This section describes the data flow between applications and the HCI.
The TX data path covers the flow of data as it is sent from the application, through the stack, and then on to HCI.
When copying there can be two data copies in the TX data path:
- When data is sent from the application to the stack
- When data is sent from the stack to HCI
As an optimization Cordio provides zero-copy API’s that use a single data buffer between the application and stack. A zero-copy API is also utilized between the stack and HCI when running on a single CPU architecture.
The stack does not copy data internally between layers.
The allocation and deallocation of data buffers takes place at the point where data is copied. When the application sends data to the stack, a buffer is allocated and data is copied to the buffer.
When data is sent from the stack to the HCI or the link layer, the data is copied to an HCI or link layer buffer and the stack buffer is deallocated.
Figure 3-3. TX data path
In this scenario, the application calls an ATTC API function which initiates transmission of a packet. The ATTC function allocates a buffer and builds an attribute protocol packet, while reserving space at the start of the packet for the L2CAP and HCI headers. ATTC looks up the HCI handle for this instance and calls an L2C function, passing the handle along with the packet and packet length to L2C.
L2C checks that the link for this handle is connected. If it is not, L2C discards the packet.
Note: It is OK to silently discard the packet in this race condition because ATTC will be notified immediately afterwards that the link has been disconnected.
L2C then builds the L2CAP and HCI headers for the packet and calls an HCI function to send the packet to HCI.
HCI then processes the packet. The detailed operation of HCI depends on the system configuration. In general HCI will copy the data, deallocate the buffer, and queue the data.
The RX data path covers the flow of data as it is sent from HCI, through the stack, and then on to the application. Like the TX path, there can be two data copies in the RX data path: when data is sent from the stack to the application and when data is sent from HCI to the stack. The stack does not copy data internally between layers.
Buffers are allocated by the HCI layer and then deallocated internally by the stack.
Figure 3-4. RX data path
HCI receives a data packet. It allocates a WSF buffer and copies the entire data packet, including the HCI handle and length, to the buffer. Then HCI calls an L2C callback function to send the data to L2C.
L2C receives the packet and performs some basic error checking on the length and PSM. If there is an error the packet is discarded and the buffer is deallocated. If the packet is good it is routed to either ATT or SMP. In this example the packet is routed to ATT and L2C calls an ATT callback function.
ATT receives the packet and performs error checking on the length and the attribute opcode. If there is an error the packet is discarded and the buffer is deallocated. If the packet is good it is routed to either ATTC or ATTS. In this example the packet is routed to ATTS and ATT calls an ATTS callback function.
ATTS processes the received packet according to the attribute protocol specification. In this example, the packet is passed to the application for further processing. ATTS calls the application callback function which allocates a WSF message buffer, copies data to the buffer, and sends the message to the application task. After calling the application callback function ATTS deallocates the packet buffer.