SimpleLink™ Low Power F3 SDK BLE5-Stack User's Guide
3.03.04.00
  • Disclaimer
  • Introduction to the SimpleLink Low Power F3 SDK
  • TI BLE5-Stack Quick Start
  • The CC23xx or CC27xx SDK Platform
  • FreeRTOS (RTOS Kernel) Overview
  • Developing with SimpleLink ® Low Power F3 software development kit
  • BLE5-Stack
    • Overview
    • Generic Access Profile (GAP)
    • Generic Attribute Profile (GATT)
    • GAP GATT Service (GGS)
    • Generic Attribute Profile Service (GATT Service)
    • GATTServApp Module
    • GAP Bond Manager and LE Secure Connections
    • Privacy
    • Logical Link Control and Adaptation Layer Protocol (L2CAP)
      • General L2CAP Terminology
      • L2CAP Modes of Operation
      • L2CAP Channels
        • Fixed Channels
        • Dynamically Allocated Channels
      • L2CAP Frame types
      • Fragmentation/Recombination
      • Segmentation/Reassembly
      • Configuring L2CAP
        • Build Configuration
        • Runtime Configuration
      • L2CAP MTU
        • RAM Considerations
      • Controller to Host Flow Control
      • Connection Oriented Channels Example
    • Link Layer (LL)
    • Channel Selection Algorithm #2
    • Host Controller Interface (HCI)
    • Physical Layer (PHY)
    • Stack Configurations
  • Micro BLE Stack
  • Optimization
  • Debugging
  • Memory Overview
  • MCUboot Over-the-Air Download (OAD)
  • System Configuration Tool (SysConfig)
  • EnergyTrace User Guide
  • Porting and Migration Guides
  • API References
  • Terms and Definitions
SimpleLink™ Low Power F3 SDK BLE5-Stack User's Guide
  • »
  • BLE5-Stack »
  • Logical Link Control and Adaptation Layer Protocol (L2CAP)

Logical Link Control and Adaptation Layer Protocol (L2CAP)¶

The L2CAP layer sits on top of the HCI layer on the host side and transfers data between the upper layers of the host (GAP, GATT, SM, application) and the link layer. This layer is responsible for protocol multiplexing capability, segmentation, and reassembly operation for data exchanged between the host and the protocol stack. All data from the host or application goes through and is encapsulated in an L2CAP packet. L2CAP permits higher-level protocols (such as GATT and SM) and applications to transmit and receive upper layer data packets (L2CAP service data units, SDU) up to 64KB long. See Figure 107. for more information.

Note

The actual L2CAP payload size is limited by the amount of memory available on the specific device being implemented. L2CAP also permits per-channel flow control and retransmission.

../_images/l2cap-architectural-blocks.jpg

Figure 107. L2CAP Architectural blocks.¶

General L2CAP Terminology¶

Table 19. General L2CAP Terminology¶

Term

Description

L2CAP channel

The logical connection between two endpoints in peer devices, characterized by their Channel Identifiers (CIDs)

SDU or L2CAP SDU

Service Data Unit: a packet of data that L2CAP exchanges with the upper layer and transports transparently over an L2CAP channel using the procedures specified in this document. This is the raw payload from the host/app, and does not include L2CAP headers.

PDU or L2CAP PDU

Protocol Data Unit: a packet of data containing L2CAP protocol information fields, control information, and/or upper layer information data. This packet includes L2CAP headers. A single SDU may be split across multiple PDUs.

Maximum Transmission Unit (MTU)

The maximum size of payload data, in octets, that the upper layer entity can accept (that is, the MTU corresponds to the maximum SDU size). Note: This is different than ATT_MTU.

Maximum PDU Payload Size (MPS)

The maximum size of payload data in octets that the L2CAP layer entity can accept (that is, the MPS corresponds to the maximum PDU payload size).

Credit

The number of LE-frames that the device can receive. Credits may range between 1 and 65535, and are used as a flow control mechanism between devices.

L2CAP Basic Header

L2CAP protocol information that is prepended to each PDU. This includes CID and length

Protocol/Service Multiplexer (PSM)

A two octet field that is used to define the interpretation of L2CAP channel data. There are both dynamic and fixed PSMs. Fixed PSMs are assigned by the SIG, while dynamic PSMs may be discovered by GATT.

Fragmentation/Recombination

Fragmentation is the process of breaking down L2CAP PDUs into smaller pieces for the controller to send out. Recombination is the process of the controller reassembling fragments into complete L2CAP PDUs. Fragmentation/Recombination is performed by the controller and is based on the LE Data Length Extension feature. Fragmentation/Recombination operations are transparent to L2CAP.

Segmentation/Reassembly

Segmentation is the process of breaking a single L2CAP SDU up multiple L2CAP packets called SDU segments. Reassembly in the inverse of this operation on the receive side. Each segment is encapsulated in a proper L2CAP header. Both segmentation and reassembly is handled by the L2CAP layer and transparent to lower and higher layers.

Important

The max SDU size supported by the stack is L2CAP_SDU_SIZE.

L2CAP Modes of Operation¶

The BLE5-Stack supports two different modes of operation of the L2CAP layer.

  • Basic L2CAP Mode

  • LE Credit Based Flow Control Mode

Note that the L2CAP section is shared for BR/EDR, BR/EDR/LE (dual mode), and LE only controller implementations. The BLE5-Stack controller implementation is LE only, thus only the modes above are relevant.

L2CAP Channels¶

There are three types of channels in L2CAP:

  • Connection-oriented

  • Connectionless data

  • L2CAP signaling

Each endpoint of an L2CAP channel is referred to by a channel identifier (CID). See the Channel Identifiers section ([Vol 3], Part A, Section 2.1) of the Bluetooth Core Specifications Version 5.3 for more details on L2CAP Channel Identifiers. Connectionless channels are not supported over the LE-U controller, and thus are not used by the BLE5-Stack.

Channels can be divided into fixed and dynamic channels.

Fixed Channels¶

Fixed channels perform a specific L2CAP function, and use CIDs between 0x0001 and 0x003F. The characteristics of each fixed channel (such as MTU) are defined on a per channel basis.

Tip

Higher level protocols such as ATT may enforce their own MTU, which is different than the L2CAP MTU.

The relevant CIDs that are available for use by the stack or application are listed below.

Table 20. L2CAP CIDs¶

CID

Description

Usage

0x0004

Attribute Protocol (ATT)

Sending ATT information

0x0005

LE Signaling Channel

Sending L2CAP commands

0x0006

Security Manager Protocol (SMP)

Sending pairing/security information

0x0040-0x007F

Dynamically Allocated

LE Credit Based Flow control packets

For example, data exchanged over the GATT protocol uses channel 0x0004, SMP (pairing and security) uses 0x0006, and the LE signaling channel uses 0x0005. The ATT, SMP, and signaling channels are not directly accessible via the application as they are used by their associated Host layers. Put another way, when calling a GATT related API, it handles the necessary encapsulation into an L2CAP packet. The signaling channel is used for L2CAP connection parameter update procedure, establishing LE credit based connections on the dynamic channels, and exchanging credits.

Dynamically Allocated Channels¶

A dynamically allocated CID is allocated to identify the logical link and the local endpoint. The local endpoint must be in the range from 0x0040 to 0xFFFF. This endpoint is used in the connection-orientated L2CAP channels described in the following section. Credit Based Flow Control mode is used by the L2CAP layer for Connection-Oriented Channels. These dynamically assigned channels are accessible and managed directly at the application layer. This means that the application is responsible for defining its own protocol on top of L2CAP CoC. L2CAP channels are bidirectional and are analogous to sockets.

When a channel is dynamically allocated, it must have the following parameters set:

  • PSM

  • MTU

  • CID

Fixed PSMs are defined by the Bluetooth SIG, these range between 0x0001 and 0x007F. Dynamic PSMs range between 0x0080 and 0x00FF. PSMs may be fixed on GATT server devices, while GATT clients shall obtain PSMs from the GATT service.

L2CAP Frame types¶

There are two frame types that are used by the BLE5-Stack. These are the Basic frame which is used by the fixed channels in basic mode, and the LE information frame which is used by the dynamic channels in LE credit based flow control mode. L2CAP handles framing of the SDU data from the host or application, but it is important to keep the protocol overhead of each frame in mind as it will affect how much application data ends up in a PDU.

The contents of the L2CAP frames are defined in Vol 3, Part A. The LE information frame is defined in section 3.4 and the basic frame is defined in section 3.1. The headers sizes are summarized here for reference.

Table 21. L2CAP Frames and Overhead¶

L2CAP Frame Type

Header Size (octets)

Header contents

Basic frame

4

Length: 2 octets CID: 2 octets

LE Information Frame

6

Length: 2 octets CID: 2 octets SDU length: 2 octets

Fragmentation/Recombination¶

From an L2CAP perspective, all packets are delivered to and received from the controller as complete packets. This means that fragmentation/recombination (if enabled by LE Data Length Extension) is performed by the controller and not visible to L2CAP. See LE Data Length Extension (DLE) for more information.

When fragmentation is used, larger packets are split into multiple link layer packets and reassembled by the link layer of the peer device. The picture below shows this relationship.

../_images/ditaa-608e85feddc802733c7023cf82d9db56808dcf82.png

Note

The DLE PDU is negotiated by LL_LEN_REQ and LL_LEN_RSP. DLE PDU is NOT the same as L2CAP PDU. For more information regarding how to change the DLE PDU, see LE Data Length Extension (DLE).

Segmentation/Reassembly¶

When operating in Basic Mode, L2CAP will not perform any segmentation or reassembly. However, when operating in LE Credit Based Flow Control mode on a dynamic channel (CoC) segmentation and reassembly at the L2CAP layer may occur.

Configuring L2CAP¶

Build Configuration¶

The L2CAP CoC dynamic channels by default is not enabled in the projects. It can be enabled by the following methods:

SysConfig tool: For projects that support SysConfig tool, you can enable L2CAP CoC dynamic channels by checking L2CAP Connection Oriented Channels box. Please refer to Figure 182. for BLE5-Stack feature overview.

  • build_config.opt: For projects that do not support SysConfig tool, you can enable L2CAP CoC dynamic channels by adding -DV41_FEATURES=L2CAP_COC_CFG to build_config.opt file.

Runtime Configuration¶

Tip

This is a bit of a misnomer because generally these parameters are set via #define but they are in fact initialized dynamically at the time of the stack boot. In this case, runtime means that they not fixed by the protocol stack library and may be changed by the user.

These L2CAP parameters are passed into the BLE5-Stack at initialization via the .opt file. These include:

  • L2CAP_NUM_PSM : Number of Protocol/Service multiplexers

  • L2CAP_NUM_CO_CHANNELS : Number of allowed dynamic CoCs.

  • MAX_PDU_SIZE: Max PDU buffer size that the controller accepts

  • MAX_NUM_PDU: Number of L2CAP TX PDU buffers in the controller

    For more information for how to change the above parameters, please see Stack Configurations

L2CAP MTU¶

As mentioned in General L2CAP Terminology, the L2CAP MTU is the maximum payload that can be processed by the L2CAP layer. The MTU size is the largest SDU that L2CAP will accept.

However, the MTU used by L2CAP will vary depending on the mode and channel type

  • Signaling channel will use the L2CAP_SIG_MTU_SIZE

  • Fixed channel packets are limited by MAX_PDU_SIZE - L2CAP_HDR_SIZE

  • CoC packets depend on the PSM’s MTU and are limited by L2CAP_SDU_SIZE

For fixed channel MTU is defined by a higher level protocol such as ATT. On dynamic connection oriented channels, the MTU is bound by the minimum of L2CAP_SDU_SIZE and the peer’s supported MTU.

RAM Considerations¶

Care must be taken with respect to RAM when enabling these features as they will consume heap memory. Additionally, since L2CAP is responsible for encapsulating packets from higher layers, the higher level protocols may have requirements on how L2CAP is configured.

Table 22. L2CAP RAM Usage¶

L2CAP Frame Type

Heap Allocation

Alloc time

L2CAP_NUM_PSM

sizeof(l2capPsm_t)*L2CAP_NUM_PSM

L2CAP init

L2CAP_NUM_CO_CHANNELS

sizeof(l2capChannel_t)* (MAX_NUM_BLE_CONNS + L2CAP_NUM_CO_CHANNELS)

L2CAP Init

L2CAP_NUM_CO_CHANNELS

sizeof( l2capCoChannel_t )

Channel creation

MAX_PDU_SIZE

Depends on application usage, can be up to MAX_PDU_SIZE*MAX_NUM_PDU in TX case. In the RX case it depends on RX throughput

Runtime

MAX_NUM_PDU

See above

Runtime

The two parameters are only used by dynamic connection oriented channels, and do not need to be considered if the feature is not used. MAX_PDU_SIZE and MAX_NUM_PDU as they do affect both the fixed channels used by ATT and SM as well as the dynamic connection oriented channels.

When using connection oriented channels, L2CAP will allocate space for each TX segment of the SDU before passing to the controller. The size is based on the max packet size that is negotiated by the controller.

On RX, L2CAP will allocate the size of the entire SDU on receiving the first packet based on the length field in the header.

For signaling commands on the fixed channels, L2CAP will allocate the memory for the packet itself, based on L2CAP_SIG_MTU_SIZE which is the MTU of the signaling channel.

Tip

For data packet payloads, the higher level protocol (ATT, SM, Application) is responsible for allocating using L2CAP_bm_alloc(...). In the case of ATT and SM, this is done transparent to the user. For CoC SDUs, the user owns the memory associated with the payload.

Controller to Host Flow Control¶

As mentioned above, MAX_NUM_PDU defines the max number of TX packets that can be queued up to the controller at a time. Attempting to send more packets will result in a failure code being returned by the high level API and the packet not being queued up by the controller.

The application may not know how many packets are queued up at a given time so it is best to always check return codes. Additionally, the application can increase the efficiency at which is queues packets up by registering for flow control notifications from the L2CAP layer.

This can be done with L2CAP_RegisterFlowCtrlTask(). When enabled, the API will notify the application with L2CAP_NUM_CTRL_DATA_PKT_EVT with the number of data packets that are available for sending. This event is triggered each time a new buffer becomes available.

Connection Oriented Channels Example¶

The BLE5-Stack provides APIs to create L2CAP CoC channels to transfer bidirectional data between two Bluetooth Low Energy devices supporting this feature. Following are the steps and generic code example which are needed to create L2CAP CoC channels communication using basic_ble framework.

  1. Enable L2CAP CoC Feature, please refer to Build Configuration

  2. Create file app_l2cap.c and add it to the project –> app folder. This file will contain most of the changes needed for using L2CAP CoC Channels. Therefore, create a new file app_l2cap.c inside the app folder of the basic_ble project.

  3. Includes. The new created file should contain the following includes.

    Listing 114. Includes of app_l2cap.c¶
    1//*****************************************************************************
    2//! Includes
    3//*****************************************************************************
    4#include <stdio.h>
    5#include <string.h>
    6#include "ti_ble_config.h"
    7#include <ti/bleapp/ble_app_util/inc/bleapputil_api.h>
    8#include <ti/bleapp/menu_module/menu_module.h>
    9#include <app_main.h>
    
  4. Define APP_L2CAP_SPSM. Since this constant needs to get accessed from several files, this definition should be placed in app_main.h.

    Listing 115. Define of APP_L2CAP_SPSM in app_main.h.¶
    1//The valid range for SPSM is 0x0080 ~ 0x00FF, 0x0080 is used as an example.
    2#define APP_L2CAP_SPSM      0x0080
    
  5. Event Handlers. The L2CAP CoC implementation requires the setup and registration of two event handlers with its corresponding masks, one for L2CAP signals and one for L2CAP data.

    Listing 116. Event Handlers of app_l2cap.c¶
     1//*****************************************************************************
     2//! Globals
     3//*****************************************************************************
     4
     5static void L2CAP_SIGNAL_EventHandler(uint32 event, BLEAppUtil_msgHdr_t *pMsgData);
     6static void L2CAP_DATA_EventHandler(uint32 event, BLEAppUtil_msgHdr_t *pMsgData);
     7
     8// Events handlers struct, contains the handlers and event masks
     9// of the application data module
    10BLEAppUtil_EventHandler_t data_L2CACAP_SIGNAL_Handler =
    11{
    12    .handlerType    = BLEAPPUTIL_L2CAP_SIGNAL_TYPE,
    13    .pEventHandler  = L2CAP_SIGNAL_EventHandler,
    14    .eventMask      = BLEAPPUTIL_L2CAP_CHANNEL_ESTABLISHED_EVT |
    15                      BLEAPPUTIL_L2CAP_CHANNEL_TERMINATED_EVT |
    16                      BLEAPPUTIL_L2CAP_SEND_SDU_DONE_EVT
    17};
    18
    19BLEAppUtil_EventHandler_t data_L2CACAP_DATA_Handler =
    20{
    21    .handlerType    = BLEAPPUTIL_L2CAP_DATA_TYPE,
    22    .pEventHandler  = L2CAP_DATA_EventHandler
    23};
    24
    25...
    26
    27// Holds the connection ID
    28static uint16_t cocCID;
    29
    30bStatus_t Application_sendL2capData(void);
    

    The registration of the event handlers will be done as part of the L2CAP initialization function.

    Listing 117. L2cap_start function of app_l2cap.c¶
     1//*****************************************************************************
     2//! Functions
     3//*****************************************************************************
     4
     5/*********************************************************************
     6 * @fn      L2cap_start
     7 *
     8 * @brief   This function is called after stack initialization,
     9 *          the purpose of this function is to initialize and
    10 *          register the L2CAP CoC functionality.
    11 *
    12 * @return  SUCCESS, errorInfo
    13 */
    14bStatus_t L2cap_start( void )
    15{
    16    bStatus_t status = SUCCESS;
    17
    18    // Register the handlers
    19    status = BLEAppUtil_registerEventHandler( &data_L2CACAP_SIGNAL_Handler );
    20    status = BLEAppUtil_registerEventHandler( &data_L2CACAP_DATA_Handler );
    21
    22    // ...
    23}
    
  6. L2CAP Initialization. As briefly mentioned earlier in this chapter, the L2CAP CoC initialization is done with function L2cap_start. This function also setting up and registering the SPSM (Simplified Protocol/Service Multiplexer).

    Listing 118. Initialize L2CAP in app_l2cap.c¶
     1bStatus_t L2cap_start( void )
     2{
     3    // ...
     4
     5    // Setup SPSM
     6    l2capPsm_t psm;
     7    l2capPsmInfo_t psmInfo;
     8
     9    if (L2CAP_PsmInfo(APP_L2CAP_SPSM, &psmInfo) == INVALIDPARAMETER)
    10    {
    11      // Prepare the PSM parameters
    12      psm.initPeerCredits = 0xFFFF; //give peer maximum credit
    13      psm.maxNumChannels = MAX_NUM_BLE_CONNS;
    14      psm.mtu = MAX_PDU_SIZE;
    15      psm.peerCreditThreshold = 0;
    16      psm.pfnVerifySecCB = NULL;
    17      psm.psm = APP_L2CAP_SPSM;
    18      psm.taskId = ICall_getLocalMsgEntityId(ICALL_SERVICE_CLASS_BLE_MSG, BLEAppUtil_getSelfEntity());
    19
    20      // Register SPSM with L2CAP task
    21      status = L2CAP_RegisterPsm(&psm);
    22    }
    23    else
    24    {
    25      // L2CAP setup failed
    26      status = FAILURE;
    27    }
    28
    29    // Return status value
    30    return( status );
    31}
    

    Call L2cap_start from the App_StackInitDoneHandler in file app_main.c.

    Listing 119. L2cap_start in app_main.c¶
    1void App_StackInitDoneHandler(gapDeviceInitDoneEvent_t *deviceInitDoneData)
    2{
    3    ...
    4
    5    status =  L2cap_start();
    6    if(status != SUCCESS)
    7    {
    8        // Call Error Handler
    9    }
    
  7. Central or peripheral device sends L2CAP LE Credit Based Connection Request. This request can be done at the end of the BLEAPPUTIL_LINK_ESTABLISHED_EVENT in app_connection.c.

    Listing 120. app_connection.c Sends out L2CAP LE Credit Based Connection Request¶
     1void Connection_ConnEventHandler(uint32 event, BLEAppUtil_msgHdr_t *pMsgData)
     2{
     3    ...
     4
     5    case BLEAPPUTIL_LINK_ESTABLISHED_EVENT:
     6    {
     7        ...
     8
     9        // Send out L2CAP_LE_CREDIT_BASED_CONNECTION_REQ, only one side needs to do this
    10        L2CAP_ConnectReq(gapEstMsg->connectionHandle, APP_L2CAP_SPSM, APP_L2CAP_SPSM);
    11
    12        break;
    13    }
    

    Note

    Both central and peripheral device can request to establish L2CAP CoC channels. As long as one of the device requests, the link establishment request will be sent. There is no need to add this part of the code for both devices. In this example the code is added for the central device only.

    Once the L2CAP credit based connection establishment is successful, the BLE5-Stack will send BLEAPPUTIL_L2CAP_SIGNAL_TYPE through the application data module with opcode BLEAPPUTIL_L2CAP_CHANNEL_ESTABLISHED_EVT for both central and peripheral devices. Therefore, we will implement a event handler function to handle L2CAP messages in app_l2cap.c.

    Listing 121. app_l2cap.c Process L2CAP signal event¶
     1//*****************************************************************************
     2//! Functions
     3//*****************************************************************************
     4
     5...
     6
     7/*********************************************************************
     8 * @fn      L2CAP_SIGNAL_EventHandler
     9 *
    10 * @brief   The purpose of this function is to handle L2CAP signal
    11 *          events which were registered in
    12 *          @ref BLEAppUtil_registerEventHandler
    13 *
    14 * @param   event - message event.
    15 * @param   pMsgData - pointer to message data.
    16 *
    17 * @return  none
    18 */
    19static void L2CAP_SIGNAL_EventHandler(uint32 event, BLEAppUtil_msgHdr_t *pMsgData)
    20{
    21  l2capSignalEvent_t *l2capMsg = ( l2capSignalEvent_t * )pMsgData;
    22
    23  switch (event)
    24  {
    25    case BLEAPPUTIL_L2CAP_CHANNEL_ESTABLISHED_EVT:
    26      {
    27          l2capChannelEstEvt_t *pEstEvt = &(l2capMsg->cmd.channelEstEvt);
    28
    29          if (l2capMsg->connHandle != LINKDB_CONNHANDLE_INVALID && l2capMsg->connHandle < MAX_NUM_BLE_CONNS)
    30          {
    31            // Successfully establish link over L2CAP
    32            // Extract the CID and store in the application layer
    33            // This will be useful when sending data over L2CAP channels
    34            cocCID = pEstEvt->CID;
    35          }
    36          else
    37          {
    38            // Could not establish an L2CAP link
    39          }
    40
    41          // Give max credits to the other side
    42          L2CAP_FlowCtrlCredit(pEstEvt->CID, 0xFFFF);
    43
    44          // Send test data
    45          Application_sendL2capData();
    46      }
    47      break;
    48
    49    case BLEAPPUTIL_L2CAP_SEND_SDU_DONE_EVT:
    50      {
    51          if (l2capMsg->hdr.status == SUCCESS)
    52          {
    53              // Successfully sending data over L2CAP
    54          }
    55      }
    56      break;
    57
    58    case BLEAPPUTIL_L2CAP_CHANNEL_TERMINATED_EVT:
    59      {
    60          // L2CAP channel has been terminated
    61          MenuModule_printf(13, 0, "L2CAP terminated");
    62      }
    63      break;
    64
    65    default:
    66      break;
    67  }
    68}
    

    Note

    Both peripheral and central devices need to exchange L2CAP Credits. After the link is established, devices can distribute credit using L2CAP_FlowCtrlCredit as shown in the listing above.

  8. Send data using L2CAP CoC channel. In order to send data over L2CAP, L2CAP_SendSDU() is needed. Therefore, we will implement a function Application_sendL2capData in app_l2cap.c and executed it for the BLEAPPUTIL_L2CAP_CHANNEL_ESTABLISHED_EVT. After successfully sending data over the air, the BLE5-Stack will send BLEAPPUTIL_L2CAP_SIGNAL_TYPE through the application data module with opcode BLEAPPUTIL_L2CAP_SEND_SDU_DONE_EVT.

    Listing 122. Sending data over L2CAP in app_l2cap.c¶
     1//*****************************************************************************
     2//! Functions
     3//*****************************************************************************
     4
     5...
     6
     7uint8_t appData[] = "Test Data!";
     8
     9bStatus_t Application_sendL2capData(void)
    10{
    11  l2capPacket_t pkt;
    12  bStatus_t status = SUCCESS;
    13
    14  // Tell L2CAP the desired Channel ID
    15  pkt.CID = cocCID;
    16
    17  // Allocate space for payload
    18  pkt.pPayload = L2CAP_bm_alloc(sizeof(appData));
    19
    20  /* Copy payload data */
    21  memcpy(pkt.pPayload, appData, sizeof(appData));
    22
    23  if (pkt.pPayload != NULL)
    24  {
    25    pkt.len = (sizeof(appData));
    26
    27    // Print transmit data to serial terminal, expected data is /0 terminated
    28    MenuModule_printf(11, 0, "L2CAP Data TX - %s", pkt.pPayload);
    29
    30    // Send packet
    31    status = L2CAP_SendSDU(&pkt);
    32
    33    // Check that the packet was sent
    34    if (SUCCESS != status)
    35    {
    36      // If SDU wasn't sent, free
    37      BM_free(pkt.pPayload);
    38    }
    39  }
    40  else
    41  {
    42    status = bleMemAllocError;
    43  }
    44
    45  return (status);
    46}
    

    When the device receives data from L2CAP, the BLE5-Stack will send BLEAPPUTIL_L2CAP_DATA_TYPE to the application data module. Therefore, we will implement a function to handle L2CAP data in app_l2cap.c.

    Listing 123. Received data over L2CAP¶
     1//*****************************************************************************
     2//! Functions
     3//*****************************************************************************
     4
     5...
     6
     7/*********************************************************************
     8 * @fn      L2CAP_DATA_EventHandler
     9 *
    10 * @brief   The purpose of this function is to handle L2CAP data
    11 *          events that rise from the GAP and were registered in
    12 *          @ref BLEAppUtil_RegisterGAPEvent
    13 *
    14 * @param   event - message event.
    15 * @param   pMsgData - pointer to message data.
    16 *
    17 * @return  none
    18 */
    19static void L2CAP_DATA_EventHandler(uint32 event, BLEAppUtil_msgHdr_t *pMsgData)
    20{
    21  if (!pMsgData)
    22  {
    23    // Caller needs to figure out by himself that pMsg is NULL
    24    return;
    25  }
    26
    27  l2capDataEvent_t *l2capDataEventData = ( l2capDataEvent_t * )pMsgData;
    28
    29  // Print received data to serial terminal, expected data is /0 terminated
    30  MenuModule_printf(12, 0, "L2CAP Data RX - %s", l2capDataEventData->pkt.pPayload);
    31}
    
  9. Close L2CAP CoC channel. If no longer needed, you can disconnect a L2CAP CoC channel with the following function call, for example after data was sent successfully in function Application_sendL2capData.

    Listing 124. Close the L2CAP CoC channel in app_l2cap.c¶
     1bStatus_t Application_sendL2capData(void)
     2{
     3   // ...
     4
     5   // Send packet
     6   status = L2CAP_SendSDU(&pkt);
     7
     8   // Check that the packet was sent
     9   if (SUCCESS != status)
    10   {
    11       // If SDU wasn't sent, free
    12       BM_free(pkt.pPayload);
    13   }
    14   else
    15   {
    16        status = L2CAP_DisconnectReq(cocCID);
    17   }
    18
    19   // ...
    

    The disconnect will then trigger the BLEAPPUTIL_L2CAP_CHANNEL_TERMINATED_EVT in the L2CAP_SIGNAL_EventHandler. Here you could also deregister the SPSM by calling the function L2CAP_DeregisterPsm.

The Figure 108. shows a sample connection and data exchange process between central and peripheral device using a L2CAP connection-oriented channel in LE Credit Based Flow Control Mode.

 @startuml
  participant Central
  participant Peripheral

  rnote over Central
  Resgister PSM
  end note

  rnote over Peripheral
  Register PSM
  end note

  == Connection Established  ==

  Central --> Peripheral : L2CAP_ConnectReq()
  Central -> Central : L2CAP_SIGNAL_EVENT\nL2CAP_CHANNEL_ESTABLISHED_EVT
  Peripheral -> Peripheral : L2CAP_SIGNAL_EVENT\nL2CAP_CHANNEL_ESTABLISHED_EVT

  Central <--> Peripheral : L2CAP_FlowCtrlCredit()

  group Central device sends data to peripheral device
    Central --> Peripheral : L2CAP_SendSDU()
    Central -> Central: L2CAP_SIGNAL_EVENT\nL2CAP_SEND_SDU_DONE_EVT
    Peripheral-> Peripheral: L2CAP_DATA_EVENT
    rnote over Peripheral
      App task process data
    end note
  end

  group Peripheral device sends data to central device
    Peripheral --> Central : L2CAP_SendSDU()
    Peripheral -> Peripheral: L2CAP_SIGNAL_EVENT\nL2CAP_SEND_SDU_DONE_EVT
    Central-> Central: L2CAP_DATA_EVENT
    rnote over Central
      App task process data
    end note
  end

  Central --> Peripheral : L2CAP_DisconnectReq()
  Central -> Central : L2CAP_SIGNAL_EVENT\nL2CAP_CHANNEL_TERMINATED_EVT
  Peripheral -> Peripheral : L2CAP_SIGNAL_EVENT\nL2CAP_CHANNEL_TERMINATED_EVT

  Central <-> Peripheral : L2CAP_DeregisterPsm()
@enduml

Figure 108. L2CAP Connection Oriented Channels Example¶

Previous Next

© Copyright 2010-2024, Texas Instruments.