.. _link_layer:

Link Layer (LL)
===============
The link layer is the interface to the physical layer (PHY) and it controls
the RF state of the device. In BLE, there are 5 states a device can be in.

   - Standby
   - Advertising
   - Scanning
   - Initiating
   - Connected

Since LL controls the RF state of the device, it means that it is also
responsible for the scheduling (For example: :term:`Anchor Point`), 
physical channel to be on and length of the packets.

The following events need to be taken care of by the scheduler:

  - Initiating
  - Advertising
  - Scanning
  - Connection

In TI |STACK|, we categorize those events into primary and secondary
tasks. Only connection events are a primary task. The rest are secondary tasks.

By default, when there is a timing conflict between a primary task and secondary task,
the LL will prioritize the primary task and push the secondary task
to a later time. However, if the application layer specifies that the secondary 
task has higher priority than the primary task and the primary task has not 
reached half of its supervision timeout or entered connection establishment phase,
the LL will prioritize the secondary task over the primary task.


.. _sec-ll-primary-tasks:

Link Layer Primary Task
-----------------------
When devices enter connection state, they are either central or peripheral
devices.  

.. _sec-ll-central-role:

Central Role
^^^^^^^^^^^^
The central device has full control over anchor points, therefore, 
it is possible to avoid timing conflicts. 

In our |STACK|, as a central device, there are 2 options for the LL scheduler to 
form anchor points.

  - The anchor points are formed randomly with no restriction on timing. This 
    is the case for all our out of box examples.
  - The anchor points will be formed after previous connection event with 5ms guard time. This 
    is achieved when you modify it through Sysconfig --> Advanced Setting --> 
    Extended Stack Settings --> Guard Time. 
    

When operating in the central role, the |DEVICE| supports a different number of
connections depending on the model. See the :ref:`cc23xx-device-comparison` for specifics.

.. note::

  TI |STACK| will not move the anchor points after connection parameter
  updates if using the same set of connection parameters.

However, there is also a chance for central role to have timing conflicts when
managing multiple connections, thus in TI |STACK| we implemented a connection
fairness mechanism to handle this. For more information, please refer to :ref:`sec-connection-fairness` .

.. _sec-ll-peripheral-role:

Peripheral Role
^^^^^^^^^^^^^^^
Since the peripheral device has little to no control over anchor points,
we use the connection fairness mechanism to handle any potential timing 
conflicts.

.. warning:: 
   |DEVICE_LOW| does **NOT** support the multi-role configuration.

.. _sec-connection-fairness:

Connection Fairness
^^^^^^^^^^^^^^^^^^^
Connection fairness is implemented in the LL to make sure that each connection 
has an equal number of scheduled opportunities to transmit if the priorities 
are the same.

Before going into the detail, we need to understand how the LL determines whether
there will be collision among connections.

For each connection, the LL will calculate the minimum time required for the
whole connection event(``connMinLength``) based on the following parameters:

 - A single event which means it assumes there is no :term:`MD` in the same connection
   event.
 - Phy used in the connection.
 - If PDU size is specified by application layer, then |STACK| will take that into 
   calculation. Otherwise, the Max PDU size is taken into account if users do not 
   specify PDU size for the specific connection. 
 - The processing time for the radio core and |STACK| which is set to 500us.

Before each connection happens, the LL will sort all the connections based on
the future start time and calculate the time difference(``ConnDiff``) between 
two next connection events. Then do a comparison between ``ConnDiff`` and
``connMinLength``.  If ``ConnDiff`` is smaller than/equal to
``connMinLength``, then LL will conclude there is collision.

.. ditaa::
   :--no-separation:
   :--no-shadows:

     LL goes through the first two connections to find if there is collision.

                                               +-------+ 
                                               | Conn 3| 
                      +-------+          +-----+-+     |         +-------+
                      | Conn 1|          | Conn 2|     |         | Conn n|
                      | cGRE  |          | cGRE  | cAAA|   ..... | cAAA  |
                      |       |          |       |     |         |       |
     -----------------+-------+----------+-------+-----+---------+-------+---------
                      <------------------>                                                                       
                         connDiff              

     /--------------------------------\ 
     | cFFF Not scheduled connections |
     +--------------------------------+
     |cGRE Connections in comparison  |
     +--------------------------------+
     | cAAA Unchecked connections     |
     \--------------------------------/


If there is no collision between connection 1 and connection 2, then
connection 1 will be selected and scheduled to send out with connection cut
off time(``connMaxLength``) set to one of the following:

#. 95% of the connection interval of the selected connection if the selected
   connection has the highest priority.

#. 95% of the connection interval of the selected connection if the connection
   interval of the selected connection is smaller than time difference between
   selected connection and the highest priority connection.

#. Time difference between selected connection and the highest priority
   connection.

If there is collision between connection 1 and connection 2, then LL will
start looking into the priority between these two connections. This is when
connection fairness comes into play. Connection fairness takes the following
factors into consideration and the list below is in order of priorities from
high to low:

 - Connection reaches half of its supervision time-out.
 - Connection is in the establishment phase, which means the first 6 connection
   events.
 - Connection is in a instant. For example: connection parameter update,
   channel map update or phy update.
 - Connection priority, which can be configured from application layer.
 - Connection with higher miss count.
 - Connection with earliest start time.    

   .. note:: 
     Miss count here only represents the number of missed connection events
     caused by running connection fairness algorithm. The miss count will be reset
     to 0 if the connection event is scheduled and the peer device meets at the
     connection event. 
     If the connection is chosen to be scheduled by LL but the peer device disappeared
     from the connection, then the miss count will not be incremented. 
     This ensures the miss count of other connections that currently are 
     in conflicts will eventually be higher and get to be scheduled(if not 
     reaching half of its supervision timeout already). 

After sorting out the priority between connection 1 and connection 2, if we
assume that connection 2 has higher priority over connection 1 due to the above
reasons, then LL will remove connection 1 from its queue and the miss count
for connection 1 will be incremented by 1. Afterwards, LL will continue to find
out whether there is collision between connection 2 and connection 3. 

.. ditaa::
   :--no-separation:
   :--no-shadows:

     LL goes through the second and the third connection to determine if there is collision.


                                               +-------+ 
                                               | Conn 3| 
                      +-------+          +-----+-+     |   +-------+       +-------+
                      | Conn 1|          | Conn 2|     |   | Conn 4|       | Conn n|
                      |  cFFF |          | cGRE  | cGRE|   | cAAA  | ..... | cAAA  |
                      |       |          |       |     |   |       |       |       |
    ------------------+-------+----------+-------+-----+---+-------+-------+-------+-------
                                         <----->
                                          conn
                                          Diff                              

     LL determines there is collision between connection 2 and connection 3,
     and connection 2 has higher priority over connection 3, connection
     3 will not be scheduled and its miss count will be incremented by 1. 
     LL continues going through the rest of connections until it finds no collision.

                                                +-------+ 
                                                | Conn 3| 
                       +-------+          +-----+-+     |   +-------+       +-------+
                       | Conn 1|          | Conn 2|     |   | Conn 4|       | Conn n|
                       |  cFFF |          | cGRE  | cFFF|   | cGRE  | ..... | cAAA  |
                       |       |          |       |     |   |       |       |       |
     ------------------+-------+----------+-------+-----+---+-------+-------+-------+-------
                                          <----------------->
                                                connDiff 
 
     /--------------------------------\ 
     | cFFF Not scheduled connections |
     +--------------------------------+
     |cGRE Connections in comparison  |
     +--------------------------------+
     | cAAA Unchecked connections     |
     \--------------------------------/        


.. _sec-ll-primary-task-user-config:

Primary Task User Configuration
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Previously we mentioned that there are certain parameters that users
can set to affect how LL treats connections.

You can do it by configuring per connection after it has been formed
or all the connections made afterwards.

Configuration per Connection
""""""""""""""""""""""""""""
To achieve this, you can use :ble_api:`HCI_EXT_SetQOSParameters`.
By using this function, you can specify priority and the max/min
connection length for specific connection.

One of the input for :ble_api:`HCI_EXT_SetQOSParameters` is taskHandle,
which in this case is the connection handle.
That also means you can change the connection priority, max/min
connection length on the fly.

The parameters of interest for this function are as following and
you can find more information regarding the valid range/options/units
by looking at :ble_api:`HCI_EXT_SetQOSParameters`.

  .. table:: HCI_EXT_SetQOSParameters Parameter Type Descriptions

    +-----------------------------+------------------------------------------------+
    | Parameter Type              |    Description                                 |
    +=============================+================================================+
    | LL_QOS_TYPE_PRIORITY        | Task priority                                  |
    +-----------------------------+------------------------------------------------+
    | LL_QOS_TYPE_CONN_MIN_LENGTH | Minimum time required for the connection       |
    +-----------------------------+------------------------------------------------+
    | LL_QOS_TYPE_CONN_MAX_LENGTH | Maximum time required for the connection       |
    +-----------------------------+------------------------------------------------+

.. warning:: 
   :ble_api:`HCI_EXT_SetQOSParameters` can only be used for an already
   made connection.

Configuration for all subsequent Connections
""""""""""""""""""""""""""""""""""""""""""""
If you do not want to deal with all the extra parameters other than 
connection priority, then you can use
:ble_api:`HCI_EXT_SetQOSDefaultParameters`. By default, the priority for all
the connections is ``LL_QOS_MEDIUM_PRIORITY``. To change that you can do the
following. All the connections that are made after this call will have the new
priority other than default. 

.. code-block:: c
  :caption: Change priority to low for the new connections

   HCI_EXT_SetQOSDefaultParameters(LL_QOS_LOW_PRIORITY, LL_QOS_TYPE_PRIORITY, LL_QOS_CONN_TASK_TYPE);

.. warning:: 
   :ble_api:`HCI_EXT_SetQOSDefaultParameters` can only be used before
   wanted connections are formed. It can not be used to change priority
   for already formed connections and can not be used to specify priority for
   a certain connection.

.. _sec-ll-secondary-tasks:

Link Layer Secondary Task
-------------------------
By default, link layer schedules the secondary tasks in a round robin fashion,
which means there is no priority among the secondary tasks. 

The link layer executes these tasks in a pre-defined order: Initiating --> 
Advertising --> Scanning. Each task will get its time and will be executed 
eventually. 

In certain cases, if all the connections use up the radio time, the secondary
tasks might be starved. To avoid this, we can configure the priority of
secondary tasks to make sure that they get the radio time.

Following is the logic that |STACK| Link Layer uses when choosing between
primary task and secondary task.


.. ditaa::
   :--no-separation:
   :--no-shadows:
                     
                         +-------------------------+
                         |       Phase 1           |
           /------------>| Get next secondary task |----------------------------\
           |             |         cCFF            |                            |
           |             +-------------------------+                            |
           |                           ^                                        |
           |                           |                                        v
           |                           |                           +------------------------+
    +-----------------+                |             No            |        Phase 2         |
    | Phase 5 option 1|                |     /---------------------| Are there connections? |
    | Schedule primary|                |     |                     |       c3FF             |
    | task            |                |     |                     +------------------------+
    |   c189          |                |     |                                | Yes, get next
    +-----------------+                |     |                                | primary task.
            ^                          |     v                                v
            |                       +------------------+            +------------------------+
            |                       | Phase 5 option 2 |            |        Phase 3         |
            |                       | Schedule next    |            | Do we have enough time |
            |                       | secondary task   |<-----------|  for secondary task?   |
            |                       |  c189            |    Yes     |         c0CC           |
            |                       +------------------+            +------------------------+
            |                                ^                                 |
            |                                |                                 | 
            |                                |Yes                              |
            |                                |                                 |No
            |                                |                                 |
            |                        +---------------------+                   |
            |                        |      Phase 4        |                   |
            |        No              | Does secondary task |                   |
            \------------------------| has higher priority |<------------------/
                                     | than primary task   |                    
                                     | and primary task has|                    
                                     | not reached 1/2     |
                                     | supervision timeout |
                                     | or not in connection|
                                     | establishment phase?|
                                     |     c0BC            | 
                                     +---------------------+

.. _sec-ll-secondary-task-user-config:

Secondary Task User Configuration
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Due to the potential secondary tasks starvation, the |STACK| allows
application layer to set priority for secondary task when users see fit.

When a secondary task has conflict with primary task, the link layer will
compare the priorities between chosen primary task and chosen secondary task.

If the chosen secondary task has higher priority than chosen primary task,
then the secondary task will be scheduled. However, if the connection has reached
half of its supervision time-out or the connection has just entered the connection 
establishment phase, then the primary task will be scheduled instead no matter 
what the result of priority comparison is. The secondary task will continue to the 
next round of selection when the scheduler does a comparison again.

.. warning:: 
   Care must be taken when setting secondary tasks with higher priority than
   primary task. When secondary tasks have higher priority than primary
   tasks, the LL will skip connection events when there is timing conflict,
   and this might lead to the starvation of the connection and/or link update 
   procedure failures (ex. Connection parameter update/Phy Update...etc). 
   Therefore, it is recommended to:

   1. Only make secondary tasks with higher priority than primary task 
      for **a short period of time** in order to avoid the aforementioned
      problems.

   2. Only make secondary tasks with higher priority than primary task
      **after all the link update processes have completed**.   



Configuration per Secondary Task
""""""""""""""""""""""""""""""""
To achieve this, you can use :ble_api:`HCI_EXT_SetQOSParameters`.
By using this function, you can specify priority for specific secondary tasks.

For example, since a peripheral device can have multiple advertising sets
(multiple secondary tasks that are advertising) and each advertising set has its
own handle, you can specify the priority for each advertising set by using
:ble_api:`HCI_EXT_SetQOSParameters`. 

.. code-block:: c
  :caption: Change priority to high for advertising 

   // Advertising handle
   static uint8 advHandle;

   GapAdv_create(&Application_advCallback, &advParams1, &advHandle);

   HCI_EXT_SetQOSParameters(LL_QOS_ADV_TASK_TYPE, LL_QOS_TYPE_PRIORITY, LL_QOS_HIGH_PRIORITY, advHandle);

For scanning and initiating phase, since each device can only be in one
scanner or initiating role, there is no handle assigned to those tasks.
Therefore, when using :ble_api:`HCI_EXT_SetQOSParameters` for scan and
initiator, we need to use a dummy handle for this.

.. code-block:: c
  :caption: Change priority to high for scanning 

   // Scanning dummy handle
   static uint8 scanDummyHandle;

   scanDummyHandle = 0 ;

   HCI_EXT_SetQOSParameters(LL_QOS_SCN_TASK_TYPE, LL_QOS_TYPE_PRIORITY, LL_QOS_HIGH_PRIORITY, scanDummyHandle);

Configuration for All Secondary Tasks
"""""""""""""""""""""""""""""""""""""
If you want to set all the same secondary task with a default priority, you
can us :ble_api:`HCI_EXT_SetQOSDefaultParameters`. 

.. code-block:: c
  :caption: Change priority to low for all the advertising set

   HCI_EXT_SetQOSDefaultParameters(LL_QOS_LOW_PRIORITY, LL_QOS_TYPE_PRIORITY, LL_QOS_ADV_TASK_TYPE);

.. warning:: 
   :ble_api:`HCI_EXT_SetQOSDefaultParameters` can only be used before
   the secondary tasks start. It can not be used to change priority
   for already started secondary tasks and can not be used to specify priority
   for a certain secondary task handle.

.. _sec-ll-control-packet-buffer:

Link Layer Control Packet Buffer
--------------------------------

In the |STACK|, there is a separate buffer for control packets.
When a connection is established, a few link layer control packets
are automatically placed in the link layer control packet queue by the |STACK| 
such as Version Exchange, Feature Exchange, etc. The |STACK| can only store 4 
link layer control packets at any given time, therefore, if users use any
APIs that trigger control procedures under ``BLEAPPUTIL_LINK_ESTABLISHED_EVENT`` or
``GAP_LINK_ESTABLISHED_EVENT``, the |STACK| will most likely encounter an 
overflow of the TX queue which leads to unexpected behavior. 

.. attention::
    The best practice is to wait for 3-4 connection events
    to trigger a control procedure such as PHY Update, ChannelMap Update, etc.

.. note::    
    APIs that trigger control procedures include but are not limited to Version Exchange,
    Feature Exchanges, ChannelMap Update, PHY Update, Connection parameters Update, etc.

Following illustrates how this can be achieved:

.. uml::
   :caption: Trigger Control Procedure With Delay

    @startuml

    participant CenApp as "Central Application"
    participant CenUtil as "Central BLE App Util"
    participant CenStack as "Central BLE STACK"
    participant PerStack as "Peripheral BLE STACK"
    participant PerUtil as "Peripheral BLE App Util"
    participant PerApp as "Peripheral Application"

    CenStack --> PerStack: Connection Indication Packet
    ...
    ... Establish Connection Successfully ...
    ...

    CenStack -> CenUtil: GAP_LINK_ESTABLISHED_EVENT
    CenUtil -> CenApp: BLEAPPUTIL_LINK_ESTABLISHED_EVENT
    CenApp -> CenStack: Register Connection Event Callback\nand start a static counter

    PerStack -> PerUtil: GAP_LINK_ESTABLISHED_EVENT
    PerUtil -> PerApp: BLEAPPUTIL_LINK_ESTABLISHED_EVENT
    PerApp -> PerStack: Register Connection Event Callback\nand start a static counter

    group Central Static Counter Reaches 3 or More
        CenApp -> CenStack: Issue HCI_LE_SetHostChanClassificationCmd\nto update current channelmap
        CenStack -> CenStack: Add ChannelMap Update\nto the control packet queue
        CenStack --> PerStack: Start ChannelMap update procedure
    end    

    group Peripheral Static Counter Reaches 3 or More
        PerApp -> PerStack: Issue HCI_LE_SetPhyCmd\nto update current PHY
        PerStack -> PerStack: Add Phy Update\nto the control packet queue
        PerStack --> CenStack: Start Phy update procedure
    end   

    @enduml

.. _sec-ll-buffers:

Link Layer Buffers
------------------

The link layer is responsible for low level sending and receiving data.
Inside the link layer there are two queues: one for transmit, and one for
receive.
Dynamic memory is used to allocate the buffers that are part of the queues.
The relative sizes of these queues are dependent on settings in the stack.
This section will describe these queues, how they affect heap utilization, and how
to configure them.

TX Queues
^^^^^^^^^

To send data, the higher level host protocol (e.g. GATT, SM) dynamically
allocates and populates the memory for the transmit buffer, and passes this to
the Controller through L2CAP (see :ref:`sec-l2cap`). The maximum number of
buffers that can be allocated is controlled by ``MAX_NUM_PDU`` and the size of
each buffer is controlled by ``MAX_PDU_SIZE``. See the graphic below for an
illustration of the TX queue.

The data queue structure itself is allocated in the initialization of the
Link Layer, but the data is allocated on the fly by the host depending
on the needs the application

    .. _fig-ll-tx-queue:
    .. ditaa::
        :--no-separation:

           TxQueue
        /-------------\      /-----------------\      /-----------------\      /-----------------\
        | pCurrEntry  +----->|                 +----->|                 +----->|                 +-------\
        |-------------|      |                 |      |                 |      |                 |       |
        | pLastEntry  +-\    |    Data[0]      |      |     Data[1]     |      |     Data[N]     |       V
        \-------------/ |    |                 |      |                 |      |                 |
                        |    |                 |      |                 |      |                 |
                        |    |                 |      |                 |      |                 |
                        |    \-----------------/      \-----------------/      \-----------------/
                        |                                                                ^
                        |                                                                |
                        \----------------------------------------------------------------/


It is important to remember that the maximum number of data packets that the host
is allowed to queue up in the controller is ``MAX_NUM_PDU``, but due to
fragmentation, these packets may be split up across multiple queue entries.

If fragmentation is needed, the original host packet will be split across
subsequent link layer PDUs. These link layer fragments are allocated from the
heap as needed depending on the TX PDU size and the amount of data to send.

At the extreme, with a very large host MTU (e.g. 255) and a small link layer
PDU (e.g. 27), the single host packet may be split across 10 link layer packets.
For a short time both the fragments and the original packet will exist in
memory. After the fragments are created and queued, the original packet will be
freed. The fragments are freed as they are sent.

See :ref:`le_data_length_extension` for more information.

RX Queues
^^^^^^^^^

Unlike the TX chain, in RX the data is coming from the peer device and thus is
an unknown quantity in terms of size until it is received. In order to be
prepared for this, the controller will pre-allocate the RX queue starting on
initialization based on the default settings for RX pdu size. (See
:ref:`le_data_length_extension` for more info). This allocation is done on init,
and the buffers are re-sized if the data length accepted by the controller
changed.

    .. _fig-ll-rx-queue:
    .. ditaa::
        :--no-separation:

                                       /-----------------------------------------------------------------\
                                       |                                                                 |
           RxQueue                     V                                                                 |
        /-------------\      /-----------------\      /-----------------\      /-----------------\       |
        | pCurrEntry  +----->|    pNextEntry   +----->|    pNextEntry   +----->|    pNextEntry   +-------/
        |-------------|      |-----------------|      |-----------------|      |-----------------|
        | pLastEntry  |      |    Status       |      |     Status      |      |     Status      |
        \------+------/      |-----------------|      |-----------------|      |-----------------|
               |             |    Config       |      |     Config      |      |     Config      |
               V             |-----------------|      |-----------------|      |-----------------|
                             |    Length       |      |    Length       |      |    Length       |
                             |-----------------|      |-----------------|      |-----------------|
                             |    pData        |      |    pData        |      |    pData        |
                             \-------+---------/      \-------+---------/      \-------+---------/
                                     |                        |                        |
                                     |                        |                        |
                                     |                        |                        |
                                     V                        V                        V
                             /-----------------\      /-----------------\      /-----------------\
                             |      Header     |      |      Header     |      |      Header     |
                             |-----------------|      |-----------------|      |-----------------|
                             |                 |      |                 |      |                 |
                             |                 |      |                 |      |                 |
                             |                 |      |                 |      |                 |
                             |      Payload    |      |      Payload    |      |      Payload    |
                             |                 |      |                 |      |                 |
                             |                 |      |                 |      |                 |
                             |                 |      |                 |      |                 |
                             |                 |      |                 |      |                 |
                             |                 |      |                 |      |                 |
                             |-----------------|      |-----------------|      |-----------------|
                             |     Suffix      |      |     Suffix      |      |     Suffix      |
                             \-----------------/      \-----------------/      \-----------------/


The number of RX buffers in the chained queue is set by
``NUM_RX_DATA_ENTRIES`` (4) and cannot be modified. The size of each buffer is
allocated based on the max PDU size, and reallocated if changed by DLE
procedures (see :ref:`le_data_length_extension`).

.. _le_data_length_extension:

LE Data Length Extension (DLE)
------------------------------

The data length extension feature allows the LE controller to send
data channel packet data units (PDUs) with payloads of up to 251
bytes of application data, while in the connected state.
Furthermore, a new PDU size can be negotiated by either side at any
time during a connection.

Previously, the controller's largest data
channel payload was 27 bytes. This Feature increases the data rate by around
250% when compared to Bluetooth Core Specification Versions 4.0 and 4.1
devices (if both devices support extended packet length and are
configured properly).

The |DEVICE| has Data Length Extension enabled by default - allowing
peer devices to utilize this feature with no application overhead.

   *  :ref:`sec-data-length-update-procedure`
   *  :ref:`pdu_size_negotiations`
   *  :ref:`initial_values`
   *  :ref:`sec-using-DLE-at-runtime`
   *  :ref:`sec-disabling-data-length-ext-at-run-time`
   *  :ref:`sec-interoperability-with-peers`
   *  :ref:`sec-ram-considerations-dle`

.. _sec-data-length-update-procedure:

DLE Update Procedure and Definitions
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

This section describes what is done from a controller perspective during
a connection as well as terminology.

Once a connection is formed, the controller will behave in one of
two possible ways:

      *  If prior to the connection, the suggested PDU size and time are set
         to the defaults for both TX and RX (27B, 328 us) then the |DEVICE|
         will not initiate a data length exchange (i.e. a ``LL_LENGTH_REQ``
         will not be sent).

         If the peer device sends a ``LL_LENGTH_REQ`` then the controller
         of the device will send a  ``LL_LENGTH_RSP`` corresponding to the
         default sizes of 4.0 devices autonomously.

         .. note::
               See :ref:`sec-disabling-data-length-ext-at-run-time` for
               information on how to modify this behavior.

      *  If prior to the connection, the PDU size or the maximum time for RX or
         TX are not default, then the LE controller of the device will
         use the ``LL_LENGTH_REQ`` and ``LL_LENGTH_RSP`` control PDUs to
         negotiate a larger payload size for data channel PDUs.

         A data length update may be initiated by the host or performed
         autonomously by the controller. Either the central or the peripheral
         can initiate the procedure.

After the data length update procedure is complete, both controllers
select a new data length based on two parameters: PDU size and time.
The largest size supported by both local and remote controller is
selected; time is taken into account to support different data
rates. These parameters are defined below:

*  PDU size
      The largest application data payload size supported by the
      controller. This size does not include packet overhead, such as
      access address or preamble.

*  Time
      The maximum number of microseconds that the device takes to
      transmit or receive a PDU at the PHY rate. This parameter uses
      units of microseconds (us).

Each direction has a PDU size and time; in other words there is a
Receive PDU size/time and a separate Transmit PDU size/time. A device
can only influence a peer's Receive PDU size/time by adjusting it's
own Transmit PDU size/time via the DLE Update Procedure.

Reference ([Vol 6], Part B, Section 5.1.9) of the |CORESPEC|
for more information about the data length update procedure.

Reference ([Vol 6], Part B, Section 4.5.10) of the |CORESPEC|
for information on the valid ranges for data PDU length and
timing parameters.

.. _pdu_size_negotiations:

How PDU size negotiation works
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

BLE devices often need to negotiate the maximum size of PDUs they can exchange. 
The PDU size is negotiated on connection setup betweeen the connection devices.

1. Initiation:
The central initiates the negotiation by sending the ``LL_LENGTH_REQ`` to 
the peripheral device. This message will indicate the maximum PDU size that 
the central device supports.

2. Response:
The peripheral device responds with an ``LL_LENGTH_RSP`` message, that supports 
the maximum PDU size. This value is less than or equal to the value requested 
by the central device. 

3. Agreement:
The final PDU size is determined by the smaller of the two values that was 
proposed by the central and the peripheral devices. Both devices agree to use 
this maximum PDU size for their communication. 

Example: 
The central device sends an ``LL_LENGTH_REQ`` message to a peripheral device 
indicating that it's preffered maximum PDU size is 251 bytes. The response of 
the peripheral will specify that its maximum supported PDU size is 190 bytes. 
Both devices will agree to use a maximum PDU size of 190 bytes for their 
communication as it's the smaller of the two proposed values. 

.. _initial_values:

Default Application DLE Behavior
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

This section describes the default behavior of the |DEVICE|
due to the feature being enabled by default.

The controller defaults to using TX PDU sizes compatible with 4.0 and
4.1 devices. It uses 27 bytes as its initial maximum PDU size, and 328
us as the maximum PDU transmit time.

On the RX PDU size and time, the controller
defaults to the maximum PDU size and the maximum PDU receive time for
a LE Data Packet Length Extension enabled device. In other words,
the RX PDU size will be 251, and the RX PDU receive time will be 2120 us.

.. note::
      As mentioned in :ref:`sec-data-length-update-procedure`, by default
      a ``LL_LENGTH_REQ`` control packet will be sent due
      to the RX max PDU size and max PDU receive time not being default 4.0
      PDU sizes and timings.

.. _sec-using-DLE-at-runtime:

Utilizing DLE in the Application
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

This section describes how the application can influence
the controller to use DLE for transmission of data at runtime.

The application can update the data length in two ways.

      #. the application can set the initial connection TX PDU size
         or time to cause the controller to request the peer's RX PDU size
         and time to change for every connection.

      #. the controller can initialize the connection with the default
         values of 27 octets and 328 us, then dynamically negotiate
         the data length at a later time in the connection using HCI commands.

For maximum throughput, high layer protocols such as the BLE host
should also use a larger PDU size (see :ref:`maximum-transmission-unit-mtu`).
See :ref:`sec-ll-buffers` for more information how the link layer manages
buffers and PDUs.

The following HCI commands can be used to interact with the
controller related to the data length extension feature:

-  LE Read Suggested Default Data Length Command (:ble_api:`HCI_LE_ReadSuggestedDefaultDataLenCmd`)

-  LE Write Suggested Default Data Length Command (:ble_api:`HCI_LE_WriteSuggestedDefaultDataLenCmd`)

-  LE Read Maximum Data Length Command (:ble_api:`HCI_LE_ReadMaxDataLenCmd`)

-  LE Set Data Length Command (:ble_api:`HCI_LE_SetDataLenCmd`)

The above commands may generate:

-  LE Data Length Change Event

For example, to dynamically change the TX PDU size and timing, the
command :ble_api:`HCI_LE_SetDataLenCmd` during a connection. This
will cause the LE controller to negotiate with the peer's LE controller
to adjust its RX PDU size and timing as described in :ref:`sec-data-length-update-procedure`.

.. note::
    The code below assumes that application already obtained the 
    connection handle under ``BLEAPPUTIL_LINK_ESTABLISHED_EVENT``.

.. code-block:: c

   // Can declare as static on the application
   // file and save it for later use. 
   uint16_t connHandle; 

   //Request max supported size
   uint16_t requestedPDUSize = 251;
   uint16_t requestedTxTime = 2120;

   HCI_LE_SetDataLenCmd(connHandle, requestedPDUSize, requestedTxTime);

.. note::
      For more information about these HCI commands and their fields, see the
      LE Controller Commands and Events sections ([Vol 2], Part E, Section
      7.7-7.8) of the |CORESPEC|. Additionally, the APIs for these commands
      are documented under :ref:`ble_api_reference`.

Assuming the central device sends the LL_LENGTH_REQ first, then the following 
shows the sequence of how the |STACK| handles the packets and sends notification
to the application layer.

.. uml::

    @startuml
    participant CenApp as "Central Application"
    participant CenUtil as "Central BLE App Util"
    participant CenStack as "Central BLE STACK"
    participant PerStack as "Peripheral BLE STACK"
    participant PerUtil as "Peripheral BLE App Util"
    participant PerApp as "Peripheral Application"

    CenApp -> CenStack : Change default data length
    CenStack --> PerStack : LL_LENGTH_REQ

    note over PerStack
      Update its supported payload
      length based on the LL_LENGTH_REQ
      and its ability.
    end note

    CenStack <-- PerStack : LL_LENGTH_RSP
    PerStack -> PerUtil : HCI_BLE_DATA_LENGTH_CHANGE_EVENT
    PerUtil -> PerApp:BLEAPPUTIL_HCI_GAP_TYPE 

    note right
      Peripheral application 
      layer might get the
      notification from BLE STACK 
      before the LL_LENGTH_RSP
      is received by Central 
      device.
    end note

    note over CenStack
      Update its supported payload
      length based on the LL_LENGTH_RSP.
    end note

    CenStack -> CenUtil : HCI_BLE_DATA_LENGTH_CHANGE_EVENT
    CenUtil -> CenApp:BLEAPPUTIL_HCI_GAP_TYPE 
    
    @enduml


.. _sec-disabling-data-length-ext-at-run-time:

Disabling DLE at Runtime
^^^^^^^^^^^^^^^^^^^^^^^^

This section describes how to disable the DLE feature at runtime.

There are two main steps to disable this feature, the first is
modifying the controller PDU sizes directly, and the second is
modifying the features the controller supports. Both steps must
be taken to completely remove DLE.

As discussed in :ref:`initial_values`, the LE controller initially uses packet length
values compatible with 4.0 and 4.1 devices in new connections for TX.
The controller will automatically attempt to
negotiate the data length at the beginning of every new
connection. To disable this feature, add :ble_api:`HCI_EXT_SetMaxDataLenCmd`
to the application:

.. code-block:: c
   :linenos:

   #define APP_TX_PDU_SIZE 27
   #define APP_RX_PDU_SIZE 27
   #define APP_TX_TIME 328
   #define APP_RX_TIME 328

   //This API is documented in hci.h
   HCI_EXT_SetMaxDataLenCmd(APP_TX_PDU_SIZE ,  APP_TX_TIME,
      APP_RX_PDU_SIZE, APP_RX_TIME);

Once a connection is formed, the peer device may request
features supported by |DEVICE| and attempt to negotiate a new
PDU size/time. This can be prevented by also utilizing the following
vendor specific command :ble_api:`HCI_EXT_SetLocalSupportedFeaturesCmd`.

.. code-block:: c
   :linenos:

   // featSet is an array of bytes representing features supported
   // of the Device. Clear DLE Feature bit
   CLR_FEATURE_FLAG( featSet[0], LL_FEATURE_DATA_PACKET_LENGTH_EXTENSION );
   HCI_EXT_SetLocalSupportedFeaturesCmd( featSet );

Both :ble_api:`HCI_EXT_SetMaxDataLenCmd` and :ble_api:`HCI_EXT_SetLocalSupportedFeaturesCmd`
should be called prior to forming a connection.

In addition to the TI Vendor Specific command, Bluetooth SIG HCI commands can also be used, such as the following:

.. code-block:: c 
   :linenos:

   #define APP_SUGGESTED_PDU_SIZE 251
   #define APP_SUGGESTED_TX_TIME 2120

   //This API is documented in hci.h
   HCI_LE_WriteSuggestedDefaultDataLenCmd(APP_SUGGESTED_PDU_SIZE ,
   APP_SUGGESTED_TX_TIME);

HCI_LE_WriteSuggestedDefaultDataLenCmd() only alters the PDU size and time for the Transmit side. 

Note that, the max PDU size in SysConfig doesn't affect the suggested data length.

.. _sec-interoperability-with-peers:

Interoperability with Legacy Peers
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Legacy Bluetooth Core Specification Versions 4.0 and 4.1 peer Hosts
or Controllers may run into interoperability issues. These may manifest
in the Link Layer or Controller Command Collisions, among other issues.

An example of these collisions can be seen in the following:

.. _dle-older-peer-diagram:
.. uml::
    :caption: Example collision from an older peer due to DLE.
    :align: center

    @startuml
    hide footbox


    participant Central
    participant Peripheral

      == Connection Established ==

      group Connection Event 1
         Central -> Peripheral: LL_FEATURE_REQ
            note right: Central requests Peripheral features

         Peripheral -> Central: Empty Packet
      end

      group Connection Event 2
         Central -> Peripheral: Empty Packet

         Peripheral -> Central: LL_FEATURE_RSP
            note right: Peripheral informs central of supported features
      end

      group Connection Event 3
         Central -> Peripheral: Empty Packet

         Peripheral -> Central: LL_LENGTH_REQ
            note right: Peripheral wishes to negotiate DLE
      end

      group Connection Event 4
         Central -> Peripheral: LL_ENC_REQ
            note right: Central wishes to start encryption

         Peripheral -> Central: Empty Packet
      end

      ...

      group Connection Events Until Termination
         Central -> Peripheral: Empty Packet

         Peripheral -> Central: Empty Packet
      end

      ...

      == Connection Terminated ==

    @enduml

:numref:`dle-older-peer-diagram` shows one way an older
central device may behave when communicating with a
DLE supporting peripheral. The connection terminates due to
the central failing to respond to the peripheral's DLE request.
Central expected a response to the encryption request,
thus never responding to the DLE request.

To support these older peers, it is recommended to
completely disable the feature as outlined in
:ref:`sec-disabling-data-length-ext-at-run-time`.

.. _sec-ram-considerations-dle:

RAM Considerations when using DLE
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

This section describes the how DLE impacts the |STACK|'s HEAP
memory usage.

The |STACK| utilizes the heap for all dynamic memory
allocations. This includes both the Transmit and Receive Buffers used in the
controller. (Covered in :ref:`sec-ll-buffers`).

It is important to understand that the transmit buffers
are allocated based on the respective PDU sizes negotiated for
each connection; while the receive buffers are only negotiated by max 
PDU size among all the connections and the 4 receive buffers are shared 
among all the connections. TX buffers are allocated at runtime and the total 
is limited by ``MAX_NUM_PDU``. The size of TX data is enforced by the MTU size of higher
level protocols such as GATT or L2CAP, however if applicable, the link
layer will fragment this based on the negotiated PDU.

For the TX case, large host MTU packets and small controller PDU results in
the most heap memory being used. For example when using the smallest LL PDU (27)
and the largest ATT_MTU (255) a single host packet will be fragmented into 10
controller packets. The equation below uses 14 for
``sizeof(dataEntry_t) + LL_PKT_HDR_LEN + LL_PKT_MIC_LEN``.
An estimation of the memory consumed can be shown below:

.. code-block:: none

   number of packets = ceil(Host Packet Size/ LL PDU Size)
   total mem of fragments = (number of packets) * (sizeof(dataEntry_t) + LL_PKT_HDR_LEN + LL_PKT_MIC_LEN + packet size)
   max memory = (total mem of fragments) * MAX_NUM_PDU

In the worst case scenario, this could mean about 3280 bytes of heap
used per connection when the host packets are 255B, the controller PDU is 27,
and MAX_NUM_PDU is set to 8. This also assumes that the application is filling
every TX PDU continually.

In the receive case, there are only ``NUM_RX_DATA_ENTRIES`` (4) queue entries
allocated at initialization time. The queue depth is fixed and not modifiable.
However, the PDU buffers will be reallocated if the TX PDU size changes due to
a data length update.

An estimation for the memory consumed can be shown below:

.. code-block:: none

   max memory = (connEffectiveMaxRxOctets + LL_PKT_MIC_LEN + LINK_SUFFIX_SIZE) * NUM_RX_DATA_ENTRIES

In the worst case scenario where a large RX PDU is used this could result in
1040 bytes of heap used for all the connections.

See :ref:`sec-ll-buffers` for more information about the LL TX and RX data
queues.

To prevent HEAP exhaustion or other issues in the rest of the application
the developer should choose the PDU size for both RX and TX, as well
as limit the max number of connections to meet the demands of the
application.

To modify the size of the both the RX and TX buffers - the vendor
specific command :ble_api:`HCI_EXT_SetMaxDataLenCmd` can be used.
This must be used prior to establishing the connection.

To modify the number of connections, see :ref:`stack_features_configuration`
for details.

.. _HCI:                                    ..\/..\/doxygen\/ble\/html\/group___h_c_i.html

RSSI Monitoring
^^^^^^^^^^^^^^^

To utilize RSSI readings as part of the decision-making process of the device behavior, a statistical RSSI
reading is required.

The RSSI Monitoring feature allows users to gather statistical Received Signal Strength Indicator (RSSI)
from RX readings during a connection event. This improves upon the single time reading from the
Radio Control Layer (RCL) for each connection event, which can be unstable and unreliable if
solely relied upon.

For detail information about the Statistical RSSI Monitoring APIs, please go to the `HCI`_ API documentation.

The TI Specific HCI Commands for this feature are the following:

- ``HCI_EXT_RssiMon_RegCmd``: Enables the App/Host to register an RSSI monitoring command for a specific connection.
- ``HCI_EXT_RssiMon_UnregCmd``: Enables the App/Host to unregister from an RSSI monitoring command for a specific register handle.
- ``HCI_EXT_RssiMon_SetConfigCmd``: Enables the App/Host to set the RSSI monitoring configuration.
- ``HCI_EXT_RssiMon_GetConfigCmd``: Enables the App/Host to get the RSSI monitoring configuration.
- ``HCI_EXT_RssiMon_GetRssiStatCmd``: Enables the App/Host to get the RSSI monitoring statistics.
- ``HCI_EXT_RssiMon_ReportCB``: This callback function is called when the RSSI monitoring reports a threshold passed.

This section will explain how to enable the feature using the ``basic_ble`` example from the SDK. 

1. Enable RSSI Monitoring in the project using SysConfig.

.. _RSSI_monitoring_enable:
.. figure:: resources/RSSI_monitoring_enable.png
   :align: center

   SysConfig - Enable RSSI Monitoring

2. Register the connection handler to receive a HCI callback event when RSSI value is out of the threshold (min, max) range defined with the same
   HCI API command.

     .. code-block:: c
       :caption: **app\_connection.c** Register Connection Event with RSSI Monitoring.
       :linenos:
       :emphasize-lines: 26
       
       #define RSSI_T_MIN -70
       #define RSSI_T_MAX 0

       void Connection_ConnEventHandler(uint32 event, BLEAppUtil_msgHdr_t *pMsgData)
       {
         switch(event)
         {
            case BLEAPPUTIL_LINK_ESTABLISHED_EVENT:
            {
                  gapEstLinkReqEvent_t *gapEstMsg = (gapEstLinkReqEvent_t *)pMsgData;

                  // Add the connection to the connected device list
                  Connection_addConnInfo(gapEstMsg->connectionHandle, gapEstMsg->devAddr);

                  /*! Print the peer address and connection handle number */
                  MenuModule_printf(APP_MENU_CONN_EVENT, 0, "Conn status: Established - "
                                    "Connected to " MENU_MODULE_COLOR_YELLOW "%s " MENU_MODULE_COLOR_RESET
                                    "connectionHandle = " MENU_MODULE_COLOR_YELLOW "%d" MENU_MODULE_COLOR_RESET,
                                    BLEAppUtil_convertBdAddr2Str(gapEstMsg->devAddr), gapEstMsg->connectionHandle);

                  /*! Print the number of current connections */
                  MenuModule_printf(APP_MENU_NUM_CONNS, 0, "Connections number: "
                                    MENU_MODULE_COLOR_YELLOW "%d " MENU_MODULE_COLOR_RESET,
                                    linkDB_NumActive());
                  
                  HCI_EXT_RssiMon_RegCmd(gapEstMsg->connectionHandle, RSSI_T_MIN, RSSI_T_MAX)

                  break;
            }
            //...
         }

3. Subscribe to the ``BLEAPPUTIL_HCI_VE_EVENT_CODE`` event inside the ``connectionHciGAPHandler`` handler to trigger callbacks 
   based on the monitored RSSI value.

     .. code-block:: c
       :caption: **app\_connection.c** Register Connection Event with RSSI Monitoring.
       :linenos:
       :emphasize-lines: 7
       
       BLEAppUtil_EventHandler_t connectionHciGAPHandler =
       {
         .handlerType    = BLEAPPUTIL_HCI_GAP_TYPE,
         .pEventHandler  = Connection_HciGAPEventHandler,
         .eventMask      = BLEAPPUTIL_HCI_COMMAND_STATUS_EVENT_CODE |
                           BLEAPPUTIL_HCI_LE_EVENT_CODE |
                           BLEAPPUTIL_HCI_VE_EVENT_CODE
       };

4. Subscribe to the ``BLEAPPUTIL_HCI_VE_EVENT_CODE`` event inside the ``connectionHciGAPHandler`` handler, and
   trigger actions based on HCI RSSI monitoring API callbacks.

     .. code-block:: c
       :caption: **app\_connection.c** Register Connection Event with RSSI Monitoring.
       :linenos:
       :emphasize-lines: 6, 12 

       void Connection_HciGAPEventHandler(uint32 event, BLEAppUtil_msgHdr_t *pMsgData)
       {
         switch (event)
         {
            //...
            case BLEAPPUTIL_HCI_VE_EVENT_CODE:
            {
                  hciEvt_VSCmdComplete_t *pHciMsg = (hciEvt_VSCmdComplete_t *)pMsgData;
                  
                  switch (pHciMsg->cmdOpcode)
                  {
                     case HCI_EXT_RSSI_MON_CB_EVENT:
                     {
                        MenuModule_printf(APP_MENU_CONN_EVENT, 0, "Conn status: RSSI monitor threshold event - RSSI handle = %d, Reason = %d", pHciMsg->pEventParam[2], pHciMsg->pEventParam[3]);
                     }
                        
                     //...
                  }
            }
            //...
         }
       }

5. In case the application requires to get statistical RSSI value for a specific connection independently of the RSSI value being within the 
   defined range threshold (min, max) or not, use the HCI API: ``HCI_EXT_RssiMon_GetRssiStatCmd()``. However, first make sure to
   always register a RSSI monitoring command for that specific connection using ``HCI_EXT_RssiMon_RegCmd()``.

6. In case the application requires to modify the parameters used to calculate the RSSI statistical values, use ``HCI_EXT_RssiMon_SetConfigCmd()``
   to set the weights used to compute the RSSI values as well as to set the minimum number of RSSI samples used in the calculation.

.. note:: 
   - The RSSI Monitor generates a statistical RSSI value only after a defined number of connection events.
   - The RSSI Monitor can be used only on active connections. If a connection is terminated, the application must call the register function again to reactivate the callback.
   - The RSSI Monitor does not differentiate between RSSI values from different channels. It aggregates RSSI readings from all channels to create a single statistical value.